mirror of
https://github.com/UniXNU/UniXNU-sheng.git
synced 2026-11-07 18:36:04 +03:00
feat(bluetooth): install native services and publish UART properties
This commit is contained in:
+3
-1
@@ -57,7 +57,7 @@
|
||||
"dram_size" = "0x80000000"
|
||||
"skip_setup_tool" = "scripts/seed-data-skip-setup.py"
|
||||
"panic_screen" = true
|
||||
"kernel_args" = ["-v", "serial=3", "debug=0x14e", "kt_fixed_zones=120", "-no_slto_panic", "use_contiguous_hint=0", "native-source-storage=1", "native-ufs-root=1", "offline-mobile-graphics-load=1", "offline-mobile-graphics-client=1", "offline-legacy-register=1", "offline-legacy-gop=1", "offline-legacy-unit-scale=2", "offline-legacy-pm=1", "offline-legacy-validate=1", "offline-legacy-transfer=1", "offline-legacy-cpu-present=1", "offline-legacy-phase=4", "offline-key-events=1", "sheng-aks=1", "offline-hid-input=1", "offline-hid-home=1", "sheng-touch=4", "sheng-touch-hid=1", "sheng-buttons=1", "sheng-log=1", "sheng-smp=1", "armcpu-spi-ipi=1", "armcpu-self-ipi=1", "sheng-data-persist=2", "sheng-adsp=2", "sheng-audio=12", "sheng-wifi=5", "sheng-backlight=1", "sheng-cpufreq=4", "sheng-gpu-power=9", "sheng-gpu-metal=1", "sheng-fb-gpu=1", "sheng-fb-bgra=1", "sheng-dpu-scanout=2", "sheng-no-lc=1", "sheng-vsync=120", "sheng-vsync-fixed=1", "sheng-gpu-dcvs=1", "sheng-disable-watchdogd=1", "sheng-lite=1", "sheng-gpu-addon=1"]
|
||||
"kernel_args" = ["-v", "serial=3", "debug=0x14e", "kt_fixed_zones=120", "-no_slto_panic", "use_contiguous_hint=0", "native-source-storage=1", "native-ufs-root=1", "offline-mobile-graphics-load=1", "offline-mobile-graphics-client=1", "offline-legacy-register=1", "offline-legacy-gop=1", "offline-legacy-unit-scale=2", "offline-legacy-pm=1", "offline-legacy-validate=1", "offline-legacy-transfer=1", "offline-legacy-cpu-present=1", "offline-legacy-phase=4", "offline-key-events=1", "sheng-aks=1", "offline-hid-input=1", "offline-hid-home=1", "sheng-touch=4", "sheng-touch-hid=1", "sheng-buttons=1", "sheng-log=1", "sheng-smp=1", "armcpu-spi-ipi=1", "armcpu-self-ipi=1", "sheng-data-persist=2", "sheng-adsp=2", "sheng-audio=12", "sheng-wifi=5", "sheng-bluetooth=1", "sheng-backlight=1", "sheng-cpufreq=4", "sheng-gpu-power=9", "sheng-gpu-metal=1", "sheng-fb-gpu=1", "sheng-fb-bgra=1", "sheng-dpu-scanout=2", "sheng-no-lc=1", "sheng-vsync=120", "sheng-vsync-fixed=1", "sheng-gpu-dcvs=1", "sheng-disable-watchdogd=1", "sheng-lite=1", "sheng-gpu-addon=1"]
|
||||
|
||||
[payload.runtime]
|
||||
tool = "scripts/build-boot-runtime.py"
|
||||
@@ -73,6 +73,8 @@ wifi_tool = "scripts/build-wifi-userspace.py"
|
||||
wifi_target = "ios27"
|
||||
wifi_launchd_cache = true
|
||||
wifi_bin_prefix = "wifi-bin"
|
||||
bluetooth_tool = "scripts/build-bluetooth-userspace.py"
|
||||
bluetooth_target = "ios27"
|
||||
|
||||
[payload.runtime.launchd_job_environment."com.apple.iconservices.iconservicesagent"]
|
||||
FORCE_SOFTWARE_RENDERER = "0"
|
||||
|
||||
@@ -14,6 +14,15 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
bluetooth {
|
||||
device_type = "bluetooth";
|
||||
compatible = "qcom,wcn7850-bt";
|
||||
unixnu,adt-name = "bluetooth";
|
||||
transport-encoding = <1>;
|
||||
transport-speed = <3200000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0 0x80000000 0 0x80000000>;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause-Patent */
|
||||
#include <IOKit/IOLib.h>
|
||||
#include <IOKit/IOService.h>
|
||||
#include <IOKit/IOPlatformExpert.h>
|
||||
#include <IOKit/IODeviceMemory.h>
|
||||
#include <IOKit/IOBufferMemoryDescriptor.h>
|
||||
#include <IOKit/IODeviceTreeSupport.h>
|
||||
@@ -26,6 +28,7 @@ namespace {
|
||||
struct Region {IOMemoryMap *map;volatile uint32_t *va;};
|
||||
struct Bluetooth {
|
||||
Region gcc,uart,wrapper,tlmm,smmu;
|
||||
IOService *radio;
|
||||
IOBufferMemoryDescriptor *dma,*tables;
|
||||
struct sm8550_qup_dma domain;
|
||||
struct qbt_geni geni;
|
||||
@@ -163,9 +166,38 @@ bool address() {
|
||||
const uint8_t *seed=static_cast<const uint8_t *>(id->getBytesNoCopy());
|
||||
bool nonzero=false;
|
||||
for(unsigned i=0;i<id->getLength();i++){nonzero|=seed[i]!=0;hash=(hash^seed[i])*0x100000001b3ULL;}
|
||||
if(nonzero){for(unsigned i=0;i<6;i++)bt.address[i]=(uint8_t)(hash>>(i*8));bt.address[0]=(bt.address[0]&0xfe)|2;
|
||||
chosen->setProperty("mac-address-bluetooth0",bt.address,6);}
|
||||
chosen->release();return nonzero;
|
||||
bool published=false;
|
||||
if(nonzero) {
|
||||
for(unsigned i=0;i<6;i++)bt.address[i]=(uint8_t)(hash>>(i*8));
|
||||
bt.address[0]=(bt.address[0]&0xfe)|2;
|
||||
IORegistryEntry *node=IORegistryEntry::fromPath("/arm-io/bluetooth",gIODTPlane);
|
||||
OSData *encoding=node?OSDynamicCast(OSData,node->getProperty("transport-encoding")):nullptr;
|
||||
OSData *speed=node?OSDynamicCast(OSData,node->getProperty("transport-speed")):nullptr;
|
||||
uint32_t wire=0,baud=0;
|
||||
if(encoding && encoding->getLength()==4)memcpy(&wire,encoding->getBytesNoCopy(),4);
|
||||
if(speed && speed->getLength()==4)memcpy(&baud,speed->getBytesNoCopy(),4);
|
||||
if(node && wire==1 && baud==3200000) {
|
||||
published=chosen->setProperty("mac-address-bluetooth0",bt.address,6) &&
|
||||
node->setProperty("local-mac-address",bt.address,6);
|
||||
if(published && !bt.radio) {
|
||||
IOService *radio=new IOService;
|
||||
if(radio && radio->init()) {
|
||||
radio->setName("bluetooth");
|
||||
published=radio->setProperty("device_type","bluetooth") &&
|
||||
radio->setProperty("transport-encoding",encoding) &&
|
||||
radio->setProperty("transport-speed",speed) &&
|
||||
radio->setProperty("local-mac-address",bt.address,6);
|
||||
IOService *provider=IOService::getPlatform();
|
||||
if(published && provider && radio->attach(provider)) {
|
||||
bt.radio=radio;radio->registerService();
|
||||
} else {published=false;radio->release();}
|
||||
} else {published=false;if(radio)radio->release();}
|
||||
}
|
||||
}
|
||||
if(node)node->release();
|
||||
}
|
||||
chosen->release();return published;
|
||||
|
||||
}
|
||||
int resources() {
|
||||
if(bt.resources)return 0;
|
||||
@@ -327,6 +359,7 @@ void sheng_bluetooth_probe(void) {
|
||||
if(!PE_parse_boot_argn("sheng-bluetooth",&enabled,sizeof(enabled)) || !enabled)return;
|
||||
uint32_t expected=0;if(!__atomic_compare_exchange_n(&bt.started,&expected,1u,false,__ATOMIC_ACQ_REL,__ATOMIC_ACQUIRE))return;
|
||||
native_bluetooth_stats[0]=1;
|
||||
if(!address()){native_bluetooth_stats[0]=3;native_bluetooth_stats[1]=(uint64_t)(int64_t)-ENOENT;return;}
|
||||
PE_parse_boot_argn("log-bluetooth",&bt.log,sizeof(bt.log));
|
||||
thread_t thread=nullptr;
|
||||
if(kernel_thread_start(worker,nullptr,&thread)==KERN_SUCCESS)thread_deallocate(thread);
|
||||
|
||||
@@ -8,5 +8,6 @@ zzzzzz-sheng-latency-trace.patch
|
||||
zzzzzzzz-sheng-exit-latency.patch
|
||||
zzzzzzzzz-sheng-unnest-trace.patch
|
||||
sheng-wifi-launchd-cache.patch
|
||||
sheng-bluetooth-runtime.patch
|
||||
sheng-wifi-association-event.patch
|
||||
sheng-main-thread-profile.patch
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
diff --git a/bsd/kern/kern_exec.c b/bsd/kern/kern_exec.c
|
||||
index 119275e..6321d34 100644
|
||||
--- a/bsd/kern/kern_exec.c
|
||||
+++ b/bsd/kern/kern_exec.c
|
||||
@@ -8711,6 +8711,20 @@ native_gpu_addon_prepare(proc_t p, user_addr_t scratch)
|
||||
wifi_bin_point, sizeof(wifi_bin_point), "/usr/libexec/launchd_cache_loader",
|
||||
"/usr/libexec/unixnu-wpa_supplicant", &wifi_bin_stage, &wifi_bin_status);
|
||||
printf("wifi: service executable mount stage %d status %d\n", wifi_bin_stage, wifi_bin_status);
|
||||
+ /* Standard system paths retain launchd policy and dyld library lookup. */
|
||||
+ uint32_t bluetooth_enabled = 0;
|
||||
+ if (PE_parse_boot_argn("sheng-bluetooth", &bluetooth_enabled, sizeof(bluetooth_enabled)) && bluetooth_enabled == 1) {
|
||||
+ static const char bt_lib_source[] = "/private/var/ngpu/bluetooth-lib", bt_lib_point[] = "/usr/lib";
|
||||
+ static const char bt_bin_source[] = "/private/var/ngpu/bluetooth-bin", bt_bin_point[] = "/usr/sbin";
|
||||
+ static volatile int bt_lib_stage, bt_lib_status, bt_bin_stage, bt_bin_status;
|
||||
+ native_gpu_addon_mount(p, scratch, 0x600, bt_lib_source, sizeof(bt_lib_source),
|
||||
+ bt_lib_point, sizeof(bt_lib_point), "/usr/lib/dyld", "/usr/lib/QcaBTType0.dylib", &bt_lib_stage, &bt_lib_status);
|
||||
+ if (bt_lib_stage == 5 && !bt_lib_status) {
|
||||
+ native_gpu_addon_mount(p, scratch, 0x600, bt_bin_source, sizeof(bt_bin_source),
|
||||
+ bt_bin_point, sizeof(bt_bin_point), "/usr/sbin/notifyd", "/usr/sbin/QcaBluetooth.runtime", &bt_bin_stage, &bt_bin_status);
|
||||
+ }
|
||||
+ printf("[bluetooth-runtime] library=%d/%d executables=%d/%d\n", bt_lib_stage, bt_lib_status, bt_bin_stage, bt_bin_status);
|
||||
+ }
|
||||
native_cryptex_os_view(p, scratch);
|
||||
native_gestalt_cache_drop(p, scratch);
|
||||
native_ls_store_drop(p, scratch);
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Stage signed Bluetooth services and pinned firmware for the existing Data addon."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
root=Path(__file__).resolve().parents[1]
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('output',type=Path)
|
||||
parser.add_argument('target',choices=('ios27',))
|
||||
parser.add_argument('--os-root',type=Path,required=True)
|
||||
parser.add_argument('--firmware-source',type=Path,default=root/'.cache/firmware/qca')
|
||||
args=parser.parse_args()
|
||||
out=args.output.resolve();out.mkdir(parents=True,exist_ok=True)
|
||||
(out/'report.json').unlink(missing_ok=True)
|
||||
component=Path(os.environ.get('QCA_BLUETOOTH_DIR',root/'drivers/QcaBluetooth')).resolve()
|
||||
userland=out/'userland'
|
||||
subprocess.run([sys.executable,component/'tools/build-userland.py',userland,
|
||||
'--bluetoothd',args.os_root/'usr/sbin/bluetoothd'],check=True)
|
||||
subprocess.run([sys.executable,root/'scripts/stage-bluetooth-firmware.py',out,
|
||||
'--source',args.firmware_source,'--fetch'],check=True)
|
||||
firmware=json.loads((out/'bluetooth-firmware.json').read_text())
|
||||
report=json.loads((userland/'report.json').read_text())
|
||||
report['directories']={'bluetooth-bin':'userland/bin','bluetooth-lib':'userland/lib',
|
||||
firmware['firmware_prefix']:firmware['firmware_prefix']}
|
||||
report['firmware']=firmware
|
||||
# A unique upper entry lets the kernel verify the executable union mount.
|
||||
marker=dict(native_input_sha256=report['native_input_sha256'],
|
||||
files={name:item['sha256'] for name,item in report['files'].items()})
|
||||
(userland/'bin/QcaBluetooth.runtime').write_text(json.dumps(marker,sort_keys=True)+'\n')
|
||||
report['runtime_marker_sha256']=hashlib.sha256((userland/'bin/QcaBluetooth.runtime').read_bytes()).hexdigest()
|
||||
(out/'report.json').write_text(json.dumps(report,indent=2)+'\n')
|
||||
print('Staged Bluetooth runtime: '+str(out))
|
||||
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify the packed native Bluetooth runtime and its shared launchd/trust inputs."""
|
||||
import argparse
|
||||
import copy
|
||||
import ctypes
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import plistlib
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import zlib
|
||||
|
||||
root=Path(__file__).resolve().parents[1]
|
||||
unixnu=root.parent/'UniXNU'
|
||||
sys.path.insert(0,str(unixnu/'scripts'))
|
||||
sys.path.insert(0,str(root/'drivers/QcaBluetooth/tools'))
|
||||
from native_ios27 import _inspect, ORIGINAL_UUID, NATIVE_DYLIB
|
||||
from unixnu.devicetree import generate
|
||||
from unixnu.profiles import merge
|
||||
import tomllib
|
||||
spec=importlib.util.spec_from_file_location('bluetooth_boot_runtime',unixnu/'scripts/build-boot-runtime.py')
|
||||
builder=importlib.util.module_from_spec(spec);spec.loader.exec_module(builder)
|
||||
|
||||
|
||||
def digest(path):return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
def addon(path):
|
||||
data=path.read_bytes()
|
||||
assert data[:8]==b'NGPUADD2' and struct.unpack_from('<Q',data,16)[0]==len(data)
|
||||
at=24;result={}
|
||||
for _ in range(struct.unpack_from('<I',data,8)[0]):
|
||||
length,mode,size,packed=struct.unpack_from('<IIQQ',data,at);at+=24
|
||||
assert 1<length<=160 and data[at+length-1]==0
|
||||
name=data[at:at+length-1].decode();at+=(length+7)&~7
|
||||
assert name not in result and not Path(name).is_absolute() and '..' not in Path(name).parts
|
||||
body=zlib.decompress(data[at:at+packed]);at+=(packed+7)&~7
|
||||
assert len(body)==size
|
||||
result[name]=(mode,body)
|
||||
assert at==len(data)
|
||||
return result
|
||||
|
||||
def modules(path):
|
||||
data=path.read_bytes();count=struct.unpack_from('<I',data)[0]
|
||||
offsets=list(struct.unpack_from('<'+count*'I',data,4))+[len(data)]
|
||||
assert 1<=count<=128 and offsets[0]==4+4*count and offsets==sorted(set(offsets))
|
||||
result=[];hashes=set()
|
||||
for a,b in zip(offsets,offsets[1:]):
|
||||
body=data[a:b];version,_,count=struct.unpack_from('<I16sI',body)
|
||||
stride={0:20,1:22,2:24}[version];assert len(body)==24+count*stride
|
||||
result.append(body)
|
||||
hashes.update(body[24+i*stride:44+i*stride].hex() for i in range(count))
|
||||
return result,hashes
|
||||
|
||||
def decode_adt(data,at=0):
|
||||
properties,children=struct.unpack_from('<II',data,at);at+=8;values={}
|
||||
for _ in range(properties):
|
||||
name=data[at:at+32].split(b'\0')[0].decode();length=struct.unpack_from('<I',data,at+32)[0]&0x7fffffff;at+=36
|
||||
values[name]=data[at:at+length];at+=(length+3)&~3
|
||||
nodes={}
|
||||
for _ in range(children):
|
||||
value,at=decode_adt(data,at);nodes[value[0]['name'].rstrip(b'\0').decode()]=value
|
||||
return (values,nodes),at
|
||||
|
||||
def host_xpc(data):
|
||||
xpc=ctypes.CDLL('/usr/lib/system/libxpc.dylib')
|
||||
xpc.xpc_create_from_plist.argtypes=[ctypes.c_void_p,ctypes.c_size_t];xpc.xpc_create_from_plist.restype=ctypes.c_void_p
|
||||
xpc.xpc_dictionary_get_value.argtypes=[ctypes.c_void_p,ctypes.c_char_p];xpc.xpc_dictionary_get_value.restype=ctypes.c_void_p
|
||||
xpc.xpc_dictionary_get_string.argtypes=[ctypes.c_void_p,ctypes.c_char_p];xpc.xpc_dictionary_get_string.restype=ctypes.c_char_p
|
||||
xpc.xpc_release.argtypes=[ctypes.c_void_p]
|
||||
buf=ctypes.create_string_buffer(data);parsed=xpc.xpc_create_from_plist(buf,len(data));assert parsed
|
||||
jobs=xpc.xpc_dictionary_get_value(parsed,b'LaunchDaemons')
|
||||
blue=xpc.xpc_dictionary_get_value(jobs,b'/System/Library/LaunchDaemons/com.apple.BlueTool.plist');assert blue
|
||||
assert xpc.xpc_dictionary_get_string(blue,b'UserName')==b'root'
|
||||
xpc.xpc_release(parsed)
|
||||
|
||||
def main():
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--runtime',type=Path,required=True)
|
||||
parser.add_argument('--os-root',type=Path,required=True)
|
||||
parser.add_argument('--seed-record',type=Path,help='existing runtime inputs.json that records the preserved Data seed')
|
||||
args=parser.parse_args();out=args.runtime.resolve()
|
||||
request=json.loads((out/'request.json').read_text());generated=json.loads((out/'generated.json').read_text())
|
||||
service=json.loads((out/'bluetooth-service.json').read_text())
|
||||
before=addon(Path(request['gpu_addon']));packed=addon(Path(generated['gpu_addon']))
|
||||
changed=[name for name,value in before.items() if packed.get(name)!=value]
|
||||
allowed=('bluetooth-bin/','bluetooth-lib/','firmware/qca/','wifi-bin/','etc/wifi/','xpc/','daemons/org.unixnu.wifi.')
|
||||
assert all(name.startswith(allowed) for name in changed)
|
||||
old_modules,_=modules(Path(request['trust_cache']));current_modules,trusted=modules(Path(generated['trust_cache']))
|
||||
assert current_modules[:len(old_modules)]==old_modules
|
||||
old_inputs=args.seed_record or root.parent/'UniXNU/out/sheng/ipados-27.0.1-24A446/sheng_ipados27/runtime/inputs.json'
|
||||
prior=json.loads(old_inputs.read_text())['inputs']['data_ramdisk']
|
||||
seed=Path(request['data_ramdisk']);assert str(seed)==prior['path'] and digest(seed)==prior['sha256']
|
||||
assert generated['data_ramdisk']==str(seed)
|
||||
with tempfile.TemporaryDirectory(prefix='bluetooth-verify-',dir=out) as td:
|
||||
work=Path(td)
|
||||
for relative,identity in service['files'].items():
|
||||
prefix,rest=relative.split('/',1);name={'bin':'bluetooth-bin','lib':'bluetooth-lib'}[prefix]+'/'+rest
|
||||
mode,body=packed[name];assert mode==0o755 and len(body)==identity['bytes']
|
||||
assert hashlib.sha256(body).hexdigest()==identity['sha256']
|
||||
path=work/name;path.parent.mkdir(parents=True,exist_ok=True);path.write_bytes(body)
|
||||
assert builder.verified_cdhash(path)==identity['cdhash'] and identity['cdhash'] in trusted
|
||||
image=_inspect.Image(path);assert image.subtype==0x80000002
|
||||
native=work/'bluetooth-bin/bluetoothd'
|
||||
original=args.os_root/'usr/sbin/bluetoothd'
|
||||
def entitlements(path):
|
||||
return plistlib.loads(subprocess.run(['codesign','--display','--entitlements',':-',str(path)],
|
||||
check=True,capture_output=True).stdout)
|
||||
assert entitlements(native)==entitlements(original)
|
||||
image=_inspect.Image(native);assert image.uuid==ORIGINAL_UUID
|
||||
assert image.data.count(NATIVE_DYLIB+b'\0')==1
|
||||
marker=json.loads(packed['bluetooth-bin/QcaBluetooth.runtime'][1])
|
||||
assert marker['files']=={name:item['sha256'] for name,item in service['files'].items()}
|
||||
manifest=service['firmware']
|
||||
for name,identity in manifest['files'].items():
|
||||
mode,body=packed[manifest['firmware_prefix']+'/'+name]
|
||||
assert mode==0o644 and len(body)==identity['bytes'] and hashlib.sha256(body).hexdigest()==identity['sha256']
|
||||
cache=work/'xpc/launchd.plist';cache.parent.mkdir(exist_ok=True)
|
||||
cache.write_bytes(packed['xpc/launchd.plist'][1]);signature=cache.with_suffix('.plist.sig')
|
||||
signature.write_bytes(packed['xpc/launchd.plist.sig'][1]);assert builder.verified_cdhash(cache,signature) in trusted
|
||||
original_cache=plistlib.loads((args.os_root/'System/Library/xpc/launchd.plist').read_bytes())
|
||||
merged=plistlib.loads(cache.read_bytes());jobs=merged['LaunchDaemons'];expected=copy.deepcopy(original_cache)
|
||||
for key,job in expected['LaunchDaemons'].items():
|
||||
if job['Label'] in service['launchd_job_overrides']:job.update(service['launchd_job_overrides'][job['Label']])
|
||||
if job['Label'] in request.get('launchd_job_environment',{}):
|
||||
job.setdefault('EnvironmentVariables',{}).update(request['launchd_job_environment'][job['Label']])
|
||||
for name,(_,body) in packed.items():
|
||||
if name.startswith('daemons/org.unixnu.') and name.endswith('.plist'):
|
||||
key='/System/Library/LaunchDaemons/'+Path(name).name
|
||||
expected['LaunchDaemons'][key]=plistlib.loads(body)
|
||||
assert merged==expected
|
||||
assert jobs['/System/Library/LaunchDaemons/com.apple.bluetoothd.plist']==original_cache['LaunchDaemons']['/System/Library/LaunchDaemons/com.apple.bluetoothd.plist']
|
||||
host_xpc(cache.read_bytes())
|
||||
empty=work/'empty';empty.mkdir()
|
||||
blue_only=work/'blue-only.plist'
|
||||
builder.merge_launchd_cache(args.os_root/'System/Library/xpc/launchd.plist',empty,blue_only,
|
||||
job_overrides=service['launchd_job_overrides'])
|
||||
assert len(plistlib.loads(blue_only.read_bytes())['LaunchDaemons'])==len(original_cache['LaunchDaemons'])
|
||||
for bad in ({'ProgramArguments':['/bad']},{'UserName':'../root'},{'ThrottleInterval':True},{'EnablePressuredExit':1}):
|
||||
try:builder.merge_launchd_cache(args.os_root/'System/Library/xpc/launchd.plist',empty,work/'bad.plist',job_overrides={'com.apple.BlueTool':bad})
|
||||
except ValueError:pass
|
||||
else:raise AssertionError('invalid launchd override accepted')
|
||||
dtb=work/'hardware.dtb'
|
||||
subprocess.run(['dtc','-I','dts','-O','dtb','-i',str(root.parent/'UniXNU-sm8550-common/dts'),
|
||||
'-o',str(dtb),str(root/'dts/sheng.dts')],check=True,capture_output=True)
|
||||
config=merge(tomllib.loads((unixnu/'profiles/os/ipados-27.0.1-24A446/profile.toml').read_text()),tomllib.loads((root/'board.toml').read_text()))
|
||||
encoded=generate(dtb,config,unique_chip_id='11223344')
|
||||
(tree,end)=decode_adt(encoded);assert end==len(encoded)
|
||||
radio=tree[1]['arm-io'][1]['bluetooth'][0]
|
||||
assert radio['device_type']==b'bluetooth\0' and radio['transport-encoding']==struct.pack('<I',1)
|
||||
assert radio['transport-speed']==struct.pack('<I',3200000)
|
||||
report=dict(passed=True,hardware_verified=False,files=len(packed),stock_jobs=len(original_cache['LaunchDaemons']),
|
||||
runtime_jobs=len(jobs),signed_bluetooth_files=3,original_entitlements_preserved=True,
|
||||
stock_bluetoothd_job_preserved=True,blue_tool_user='root',host_libxpc_parsed=True,
|
||||
original_trust_modules_preserved=len(old_modules),trust_modules=len(current_modules),
|
||||
data_seed_preserved=True,bluetooth_adt_encoding='H4 UART.SK',bluetooth_uart_rate=3200000,
|
||||
changed_base_files=changed,addon_sha256=digest(Path(generated['gpu_addon'])),trust_sha256=digest(Path(generated['trust_cache'])))
|
||||
(out/'verification.json').write_text(json.dumps(report,indent=2)+'\n')
|
||||
print(f"Bluetooth runtime: {len(packed)} packed files, three signed arm64e binaries, {len(jobs)} launchd jobs; firmware, entitlements, trust modules, preserved Data seed and little-endian ADT verified")
|
||||
|
||||
if __name__=='__main__':main()
|
||||
@@ -5,6 +5,8 @@ import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import os
|
||||
import tempfile
|
||||
import urllib.request
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
@@ -21,14 +23,25 @@ for name, expected in manifest['files'].items():
|
||||
if not re.fullmatch(r'hmtbtfw[0-9a-f]{2}\.tlv|hmtnv[0-9a-f]{2}\.(bin|b[0-9a-f]{2,4})', name):
|
||||
raise SystemExit('Unsupported Bluetooth firmware name: '+name)
|
||||
source = a.source/name
|
||||
fetched = False
|
||||
if not source.exists() and a.fetch:
|
||||
url = manifest['repository'].replace('github.com', 'raw.githubusercontent.com')+'/'+manifest['commit']+'/qca/'+name
|
||||
with urllib.request.urlopen(url, timeout=30) as response:
|
||||
data = response.read()
|
||||
fetched = True
|
||||
else:
|
||||
data = source.read_bytes()
|
||||
if len(data) != expected['bytes'] or hashlib.sha256(data).hexdigest() != expected['sha256']:
|
||||
raise SystemExit('Bluetooth firmware identity mismatch: '+name)
|
||||
if fetched:
|
||||
source.parent.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.NamedTemporaryFile(dir=source.parent, prefix=name+'.', delete=False) as cache:
|
||||
temporary = Path(cache.name)
|
||||
cache.write(data)
|
||||
try:
|
||||
os.replace(temporary, source)
|
||||
finally:
|
||||
temporary.unlink(missing_ok=True)
|
||||
staged[name] = data
|
||||
destination = a.output.resolve()/prefix
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user