Files
UniXNU/scripts/add-gpu-plugin-data.py
T
2026-10-19 18:49:31 +08:00

88 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""Stage the owner-built Adreno Metal plugin into a copy of a packed Data seed.
add-gpu-plugin-data.py BASE.dbr OUTPUT.dbr
Adds /private/var/ngpu/addons/NativeAdrenoMetal.bundle, /private/var/ngpu/bin/adrenoprobed and /private/var/ngpu/daemons/*.plist (from build/adreno-metal-plugin, see build-adreno-metal-plugin.py). The
kernel's boot-time addon mount (sheng-gpu-addon=1) presents that directory as a read-only union view over
/System/Library/Extensions, which is where the original Metal discovery looks for MetalPluginName. BASE is not modified and the
volume UUID is unchanged. Nothing is written to Git or to the OS inputs."""
import json
import os
import plistlib
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'drivers/DarwinBoot/Test'))
import packed_ramdisk
BUNDLE = ROOT / 'build/adreno-metal-plugin/NativeAdrenoMetal.bundle'
def main():
if len(sys.argv) != 3:
sys.exit(__doc__)
base, output = Path(sys.argv[1]).resolve(), Path(sys.argv[2]).resolve()
if output.exists():
sys.exit('Refuse to overwrite ' + str(output))
if not (BUNDLE / 'NativeAdrenoMetal').is_file():
sys.exit('Build the plugin first: python3 scripts/build-adreno-metal-plugin.py')
blob = base.read_bytes()
logical, extents = packed_ramdisk.regions(blob)
with tempfile.TemporaryDirectory(prefix='data-seed-', dir=str(ROOT / 'build')) as td:
raw = Path(td) / 'seed.raw'
with raw.open('wb') as f:
f.truncate(logical)
for offset, data in extents:
f.seek(offset)
f.write(data)
mount = Path(td) / 'mount'
mount.mkdir()
attached = plistlib.loads(subprocess.check_output(
['hdiutil', 'attach', '-imagekey', 'diskimage-class=CRawDiskImage', '-nobrowse', '-owners', 'off',
'-mountpoint', str(mount), '-plist', str(raw)]))
device = attached['system-entities'][0]['dev-entry']
try:
if not (mount / 'mobile').is_dir():
sys.exit('The Data seed has no /mobile; wrong base image?')
target = mount / 'ngpu/addons/NativeAdrenoMetal.bundle'
if target.exists():
shutil.rmtree(target)
target.parent.mkdir(parents=True)
for directory in (mount / 'ngpu', mount / 'ngpu/addons'):
os.chmod(directory, 0o755)
shutil.copytree(BUNDLE, target, symlinks=False)
daemon_dir, bin_dir = mount / 'ngpu/daemons', mount / 'ngpu/bin'
for directory in (daemon_dir, bin_dir):
if directory.exists():
shutil.rmtree(directory)
directory.mkdir(parents=True)
os.chmod(directory, 0o755)
shutil.copyfile(BUNDLE.parent / 'adrenoprobed', bin_dir / 'adrenoprobed')
os.chmod(bin_dir / 'adrenoprobed', 0o755)
for plist in sorted(BUNDLE.parent.glob('*.plist')):
if plist.name.endswith('-entitlements.plist'):
continue # build input, not a launchd job
shutil.copyfile(plist, daemon_dir / plist.name)
os.chmod(daemon_dir / plist.name, 0o644)
for path in [target, *target.rglob('*')]:
os.chmod(path, 0o755 if path.is_dir() or path.name in ('NativeAdrenoMetal', 'libvulkan_freedreno.dylib') else 0o644)
print('staged', target.relative_to(mount), sorted(p.name for p in target.iterdir()))
finally:
subprocess.run(['hdiutil', 'detach', device], check=True)
if raw.read_bytes()[32:36] != b'NXSB':
sys.exit('The edited image is no APFS container any more')
metadata = packed_ramdisk.pack(raw, output)
report = dict(base_sha256=packed_ramdisk.inspect(base)[0]['sha256'], output=metadata,
plugin=json.loads((ROOT / 'build/adreno-metal-plugin/trust.json').read_text()))
output.with_suffix('.json').write_text(json.dumps(report, indent=2) + '\n')
print(json.dumps(report, indent=2))
if __name__ == '__main__':
main()