docs(porting): the real packaging script, the PAC requirement and the release command

The packaging page describes the implemented unixnu release command, its
board.toml keys, the outputs and the checks verify makes. The arm64e page states
that arm64e needs native PAC hardware, that iPadOS 18 is the last version that
supports arm64, recommends PAC devices and the iOS or iPadOS 27 profile, and
states that every driver and optimization must work for 17 and 27 with the
build target as the only difference.
This commit is contained in:
UniXNU Docs committed 2026-11-01 06:06:26 +08:00
1 parent 90ca56a289
commit 29576874dd
8 files changed
+157 -109

No files matched your search

+12 -9
View File
@@ -5,16 +5,19 @@ meets every [requirement](#requirements) and appears in
[supported devices](#supported-devices). Other devices use the arm64 profile
`ipados-17.7.11-21H461` and the regular [porting steps](/porting/steps).
iPadOS 18 and later ship arm64e user space only, so arm64 is the last resort
whose endpoints are iOS 17 and iPadOS 18. An arm64e profile builds XNU with
pointer authentication (PAC) and links the original arm64e kexts of the target
kernelcache.
arm64e needs native PAC hardware: a CPU that implements pointer
authentication and a hypervisor that leaves it usable, as the
[requirements](#requirements) check. A device without it stays on arm64, and
iPadOS 18 is the last version that supports arm64. iPadOS 26 and later are
arm64e only. An arm64e profile builds XNU with pointer authentication (PAC)
and links the original arm64e kexts of the target kernelcache.
For a new port, choose a device whose CPUs meet the requirements below. Prefer
the iOS or iPadOS 27 profile: its drivers, patches and build recipes are the
ones under active development, and every driver and optimization in this
repository is maintained against both 17 and 27, selected by build parameter
alone.
For a new port, choose a device whose CPUs have PAC and prefer the iOS or
iPadOS 27 profile. Its drivers, patches and build recipes are the ones under
active maintenance. Every driver and optimization in this repository must work
for 17 and 27, arm64 and arm64e, with the build target as the only difference:
the `--os` parameter of [the packaging script](/porting/packaging). A change that
works for one target only is not merged.
## Requirements {#requirements}
+1
View File
@@ -19,6 +19,7 @@ UniXNU-<device>/
configs/<device>_defconfig
dts/<device>.dts
patches/xnu/series
scripts/package.sh
proprietary-files.txt
package/
local.toml.example
+69 -58
View File
@@ -1,91 +1,102 @@
# Device packaging script
**Mandatory for every device repository.** A device repository carries one
packaging script that produces its boot image and its payload from a clean
checkout, with no argument and no edit. Other device repositories copy this
page's structure. They fill in configuration values, never the script.
**Mandatory for every device repository.** A device repository carries
`scripts/package.sh`, which produces the boot image and the payload of the
device from a clean checkout in one command. Every device repository holds the
same script text. A board changes `board.toml`, never the script.
## Rules
1. **One command, one result.** `scripts/package.sh` in the device repository
builds both artifacts. A second run on the same sources produces byte
identical outputs.
2. **Configuration comes from TOML.** The script reads `board.toml` and the
referenced `feeds.toml`, profile and local file. It contains no device name,
path, size, kernel argument or version as a literal. A value the script
needs but the TOML does not carry is added to `board.toml` first.
3. **The script is shared, not per device.** Device repositories use the same
script text. Boards differ only in their TOML values. A change to the flow
is made once and adopted by every device repository.
1. **One command.** `scripts/package.sh` runs the fixed steps below and writes
the outputs and a manifest. It stops at the first failing step and names it.
2. **Configuration comes from TOML.** The script and `unixnu release` contain no
device name, path, size, kernel argument or version. The values are read from
`board.toml` (and the profiles and feeds it selects). A value that is missing
is added to `board.toml` first.
3. **The script is fixed.** `templates/package.sh` in the UniXNU repository is the
only source. A device repository copies it unchanged. The one board value it
reads itself is `[package] unixnu`, the path of the UniXNU checkout.
4. **The build target is a parameter.** One branch serves every OS profile.
`--os` selects iOS or iPadOS 17, 26 or 27 for that run. There is no per
target branch, and no second copy of a driver, patch or optimization for a
second target.
5. **Every step is named and checked.** A step that fails stops the run with
its name and the command's output. A step that is skipped says so.
`--os 17|26|27|PROFILE` selects the profile for the run. The values that differ
per profile sit in `board.toml` under `[os_overrides."<profile>"]`; there is no
branch and no second copy of a driver, patch or optimization per target.
5. **Sources are pinned.** `deps` fetches only the revisions that `feeds.toml`,
`.gitmodules` and `unixnu.lock` name.
## Structure
## Steps
The script runs these steps in this order. Each one is a function with the
step's name, and each prints a header line before it runs.
`unixnu release` runs these steps in order and prints a `step <name>` line before each.
| Step | Does | Reads |
| --- | --- | --- |
| `deps` | Clones or updates UniXNU, the device repository, its modules and the UEFI repository; checks each pinned revision | `feeds.toml`, `.gitmodules`, `unixnu.lock` |
| `preflight` | Runs the board's checks and resolves the profiles | `board.toml`, `--os` |
| `patches` | Lists the resolved patch series in application order, then applies it | `patch_series`, profile series |
| `build` | Builds each stage in dependency order, stopping at the first failure | `components`, `kernel`, `firmware` |
| `pack` | Writes the two artifacts and their manifest | `bootimg`, `payload` |
| `verify` | Checks the artifacts against the manifest and reports sizes | the manifest |
| `deps` | Fetches the module submodules and git sources, writes `unixnu.lock`, extracts the IPSW members the board lists | `feeds.toml`, `.gitmodules`, `[ipsw]` |
| `preflight` | Selects the defconfig of the OS profile and writes the configuration | `[package.defconfig]`, `[kernel]` |
| `patches` | Resolves and lists the patch series in application order | `[kernel] patch_series` |
| `build` | Builds kernel, package, payload and firmware in dependency order | `[components]`, `[kernel]`, `[firmware]`, `[payload]` |
| `pack` | Packs the boot image from the firmware volume, the device tree and the payload | `[bootimg]`, `[device_tree]` |
| `verify` | Writes the manifest and checks the outputs against it | the outputs |
## Interface
```sh
scripts/package.sh [--os 17|26|27|PROFILE] [--device DIR] [--out DIR] [--jobs N] [--no-deps] [--check]
scripts/package.sh [--os 17|26|27|PROFILE] [--no-deps] [--check] [unixnu options]
```
| Option | Meaning |
| --- | --- |
| `--os` | OS profile for this run. Defaults to `board.os_profile` |
| `--device` | Device repository. Defaults to the directory holding the script |
| `--out` | Output root. Defaults to `out/` in the UniXNU checkout |
| `--jobs` | Parallel jobs for the compile steps |
| `--no-deps` | Skips `deps`, for a machine whose sources are already fetched and pinned |
| `--check` | Runs `deps`, `preflight`, `patches` and `verify` only, and reports what would change |
| `--os` | OS profile for this run. Defaults to `[board] os_profile` |
| `--no-deps` | Skips the `deps` step, for a machine whose sources are fetched and pinned |
| `--check` | Runs `deps`, `preflight` and `patches`, prints the patch list and stops before any build |
Every option maps onto a `unixnu` argument. The script adds no logic of its own
to a step that `unixnu` already performs.
Any other `unixnu` option (`--uefi`, `--kernelcache`, `--dtb`, `--out`, `-j`) is passed on.
Local inputs that are not in a repository come from `unixnu.local.toml`.
## Required outputs
## board.toml keys
The run writes these files, and the manifest names each one with its size and
SHA-256.
```toml
[package]
unixnu = "../UniXNU"
[package.defconfig]
"ipados-27.0.1-24A446" = "<device>_ipados27_defconfig"
[os_overrides."ipados-17.7.11-21H461".kernel]
archives = [ ... ]
remove = [ ... ]
```
| Key | Meaning |
| --- | --- |
| `[package] unixnu` | Path of the UniXNU checkout, relative to the device repository |
| `[package.defconfig]` | Defconfig for each OS profile; `release` uses it |
| `[package] boot_partition_bytes` | Optional. `verify` refuses a larger `boot.img` |
| `[os_overrides."<profile>"]` | Tables merged over the board for that profile only |
| `remove` in an override | Dotted keys the board sets for other profiles and this one does not |
## Outputs
All paths are under `out/<device>/<os_profile>/<config>/`. The manifest records the size and
SHA-256 of each file, the resolved revision of every module, the patch order and the length
of the kernel command line.
| Output | Contents |
| --- | --- |
| `out/<device>/<os_profile>/<config>/boot.img` | Android boot image: shim, firmware volume, device tree, payload ramdisk |
| `out/<device>/<os_profile>/<config>/payload.img` | The payload volume the boot image carries |
| `out/<device>/<os_profile>/<config>/kernel.macho` | The prelinked kernel the payload boots |
| `out/<device>/<os_profile>/<config>/package.manifest.json` | Build id, OS profile, resolved revisions, patch series, output sizes and hashes |
The boot image must fit the bootloader's partition and the kernel command line
must stay under 1000 bytes. The script refuses both cases before it writes an
image.
| `boot/boot.img` | Android boot image: shim, firmware volume, device tree, payload ramdisk |
| `payload/payload.img` | The FAT payload volume the boot image carries |
| `kernel/kernel.macho` | The prelinked kernel the payload boots |
| `package.manifest.json` | The manifest |
## Verification
A packaging run counts as complete when `verify` passes: both artifacts exist,
their hashes match the manifest, the kernel command line is within its limit,
and the boot image is not larger than the partition it is booted from. Booting
the artifact is a separate step with its own record.
`verify` fails when an output is missing or differs from the manifest, when the kernel
command line reaches 1000 bytes, or when `boot.img` exceeds `boot_partition_bytes`.
Booting the artifacts is a separate step with its own record.
## Adoption
For a device repository without the script:
1. Copy `scripts/package.sh` from the reference device repository.
2. Fill `board.toml` until `--check` reports no missing value.
3. Record the outputs in the device's `porting.toml` packaging area.
4. Add the run to the build documentation.
1. Copy `templates/package.sh` to `scripts/package.sh` in the device repository.
2. Add `[package]` and `[package.defconfig]` to `board.toml`, and `[os_overrides]` for each other profile.
3. Run `scripts/package.sh --check --os <profile>` for every profile and fix what it reports.
4. Record the run in the `packaging` area of `porting.toml`.
[Build and boot](/building), [Device repository](/porting/device-repository)
+8
View File
@@ -81,6 +81,14 @@ unixnu clean
Removes `tree`, `logs`, `kernel`, `package`, `boot` and `edk2-conf` under the board output. Keeps fetched sources.
### release
```
unixnu release [--os VERSION] [--no-deps] [--check]
```
Runs the fixed steps `deps`, `preflight`, `patches`, `build`, `pack` and `verify` for the device, then writes `package.manifest.json`. The device repository's `scripts/package.sh` calls it. See [Device packaging script](/porting/packaging).
## Options
| Option | Meaning |
+5 -3
View File
@@ -3,11 +3,13 @@
**仅适用于受支持的设备。** 只有满足全部[要求](#requirements)并列入[受支持设备](#supported-devices)的设备才能使用本方法。
其他设备使用 arm64 配置 `ipados-17.7.11-21H461` 和常规[移植步骤](/zh/porting/steps)。
iPadOS 18 及以后版本只提供 arm64e 用户空间,因此 arm64 是最后的退路,其终点是 iOS 17 和 iPadOS 18。
arm64e 需要原生 PAC 硬件:CPU 实现指针认证,且虚拟机监控程序不阻止使用,见下面的[要求](#requirements)。
没有 PAC 的设备继续使用 arm64,iPadOS 18 是最后支持 arm64 的版本;iPadOS 26 及以后只提供 arm64e。
arm64e 配置以指针认证(PAC)编译 XNU,并链接目标 kernelcache 中的原版 arm64e kext。
新移植应选择满足下列要求的设备。优先使用 iOS 或 iPadOS 27 配置:其驱动、补丁和构建配方
处于持续维护中,本仓库的每个驱动和优化都同时面向 17 和 27 维护,只靠构建参数选择。
新移植应选择 CPU 带 PAC 的设备,并优先使用 iOS 或 iPadOS 27 配置:其驱动、补丁和构建配方处于持续维护中。
本仓库的每个驱动和优化都必须同时适用于 17 和 27、arm64 和 arm64e,唯一的差别是构建目标,
即[打包脚本](/zh/porting/packaging)的 `--os` 参数。只对一个目标有效的改动不予合并。
## 要求 {#requirements}
+1
View File
@@ -18,6 +18,7 @@ UniXNU-<device>/
configs/<device>_defconfig
dts/<device>.dts
patches/xnu/series
scripts/package.sh
proprietary-files.txt
package/
local.toml.example
+53 -39
View File
@@ -1,71 +1,85 @@
# 设备打包脚本
**每个设备仓库必须遵守。** 设备仓库只带一个打包脚本,从干净检出、不带参数、不需要修改即可产出启动镜像和 payload。
其他设备仓库照搬本页的结构,只填写配置值,不修改脚本本身。
**每个设备仓库必须遵守。** 设备仓库带有 `scripts/package.sh`,用一条命令从干净检出产出该设备的启动镜像和 payload。
所有设备仓库中的脚本文本相同。板级只修改 `board.toml`,不修改脚本。
## 规则
1. **一条命令,两项产物。** 设备仓库的 `scripts/package.sh` 同时构建两项产物。同一份源码第二次运行产出的字节完全相同。
2. **配置来自 TOML。** 脚本读取 `board.toml` 及其引用的 `feeds.toml`、配置文件和本地文件。脚本里不出现设备名、路径、尺寸、内核参数或版本的字面值。脚本需要而 TOML 没有的值,先加进 `board.toml`。
3. **脚本是共享的,不按设备各写一份。** 各设备仓库使用同一份脚本文本,差异只在 TOML 取值。流程改动只改一次,由所有设备仓库采用。
4. **构建目标是参数。** 单一分支服务所有 OS 配置。`--os` 为本次运行选择 iOS 或 iPadOS 17、26、27。不存在按目标拆分的分支,也不存在为第二个目标另存一份的驱动、补丁或优化。
5. **每一步都有名字和检查。** 失败的一步以其名称和命令输出终止本次运行;被跳过的一步要说明原因。
1. **一条命令。** `scripts/package.sh` 按下列固定步骤运行,写出产物和清单。第一个失败的步骤会终止运行并指出步骤名。
2. **配置来自 TOML。** 脚本和 `unixnu release` 中不出现设备名、路径、尺寸、内核参数或版本。取值读自 `board.toml`(以及它选择的配置文件和 feeds)。缺少的值先加进 `board.toml`。
3. **脚本是固定的。** UniXNU 仓库的 `templates/package.sh` 是唯一来源,设备仓库原样复制。脚本自己读取的板级值只有 `[package] unixnu`,即 UniXNU 检出的路径。
4. **构建目标是参数。** 单一分支服务所有 OS 配置。`--os 17|26|27|PROFILE` 为本次运行选择配置。随配置不同的取值写在 `board.toml` 的 `[os_overrides."<profile>"]` 下;不按目标建分支,也不为第二个目标另存驱动、补丁或优化。
5. **源码已固定。** `deps` 只获取 `feeds.toml`、`.gitmodules` 和 `unixnu.lock` 指定的版本。
## 结构
## 步骤
脚本按下列顺序执行。每一步是一个同名函数,运行前打印一行标题。
`unixnu release` 按顺序运行下列步骤,每步之前打印一行 `step <名称>`。
| 步骤 | 作用 | 读取 |
| --- | --- | --- |
| `deps` | 克隆或更新 UniXNU、设备仓库、其模块和 UEFI 仓库,并校验每个固定版本 | `feeds.toml`、`.gitmodules`、`unixnu.lock` |
| `preflight` | 运行板级检查并解析配置 | `board.toml`、`--os` |
| `patches` | 按应用顺序列出解析后的补丁系列,然后应用 | `patch_series`、各配置的系列 |
| `build` | 按依赖顺序构建各阶段,遇到第一个失败即停止 | `components`、`kernel`、`firmware` |
| `pack` | 写出两项产物及其清单 | `bootimg`、`payload` |
| `verify` | 按清单校验产物并报告尺寸 | 清单 |
| `deps` | 获取模块子模块和 git 源,写 `unixnu.lock`,解出板级列出的 IPSW 成员 | `feeds.toml`、`.gitmodules`、`[ipsw]` |
| `preflight` | 选择该 OS 配置的 defconfig 并写出配置 | `[package.defconfig]`、`[kernel]` |
| `patches` | 解析并按应用顺序列出补丁系列 | `[kernel] patch_series` |
| `build` | 按依赖顺序构建内核、package、payload 和固件 | `[components]`、`[kernel]`、`[firmware]`、`[payload]` |
| `pack` | 由固件卷、设备树和 payload 打包启动镜像 | `[bootimg]`、`[device_tree]` |
| `verify` | 写清单并按清单检查产物 | 产物 |
## 接口
```sh
scripts/package.sh [--os 17|26|27|PROFILE] [--device DIR] [--out DIR] [--jobs N] [--no-deps] [--check]
scripts/package.sh [--os 17|26|27|PROFILE] [--no-deps] [--check] [unixnu 选项]
```
| 选项 | 含义 |
| --- | --- |
| `--os` | 本次运行的 OS 配置,默认取 `board.os_profile` |
| `--device` | 设备仓库,默认为脚本所在目录 |
| `--out` | 输出根目录,默认为 UniXNU 检出中的 `out/` |
| `--jobs` | 编译阶段的并行任务数 |
| `--no-deps` | 跳过 `deps`,用于源码已获取并固定版本的本机 |
| `--check` | 只运行 `deps`、`preflight`、`patches` 和 `verify`,报告将会发生的变化 |
| `--os` | 本次运行的 OS 配置,默认取 `[board] os_profile` |
| `--no-deps` | 跳过 `deps`,用于源码已获取并固定的本机 |
| `--check` | 运行 `deps`、`preflight` 和 `patches`,打印补丁列表后在任何构建之前停止 |
每个选项都对应一个 `unixnu` 参数。`unixnu` 已经完成的步骤,脚本不再添加自己的逻辑。
其他 `unixnu` 选项(`--uefi`、`--kernelcache`、`--dtb`、`--out`、`-j`)原样传递。不在仓库中的本地输入来自 `unixnu.local.toml`。
## 必需产物
## board.toml 键
本次运行写出下列文件,清单为每个文件记录尺寸和 SHA-256。
```toml
[package]
unixnu = "../UniXNU"
[package.defconfig]
"ipados-27.0.1-24A446" = "<device>_ipados27_defconfig"
[os_overrides."ipados-17.7.11-21H461".kernel]
archives = [ ... ]
remove = [ ... ]
```
| 键 | 含义 |
| --- | --- |
| `[package] unixnu` | UniXNU 检出相对设备仓库的路径 |
| `[package.defconfig]` | 各 OS 配置的 defconfig,`release` 使用 |
| `[package] boot_partition_bytes` | 可选。`verify` 拒绝更大的 `boot.img` |
| `[os_overrides."<profile>"]` | 仅对该配置合并到板级之上的表 |
| 覆盖中的 `remove` | 板级为其他配置设置、而本配置没有的点分键 |
## 产物
路径都在 `out/<device>/<os_profile>/<config>/` 下。清单记录每个文件的尺寸和 SHA-256、每个模块解析后的版本、补丁顺序和内核命令行长度。
| 产物 | 内容 |
| --- | --- |
| `out/<device>/<os_profile>/<config>/boot.img` | Android 启动镜像:shim、固件卷、设备树、payload ramdisk |
| `out/<device>/<os_profile>/<config>/payload.img` | 启动镜像携带的 payload 卷 |
| `out/<device>/<os_profile>/<config>/kernel.macho` | payload 启动的预链接内核 |
| `out/<device>/<os_profile>/<config>/package.manifest.json` | 构建标识、OS 配置、解析后的版本、补丁系列、产物尺寸与哈希 |
启动镜像必须放得进引导加载程序的分区,内核命令行必须保持在 1000 字节以内。两种情况脚本在写镜像之前就拒绝。
| `boot/boot.img` | Android 启动镜像:shim、固件卷、设备树、payload ramdisk |
| `payload/payload.img` | 启动镜像携带的 FAT payload 卷 |
| `kernel/kernel.macho` | payload 启动的预链接内核 |
| `package.manifest.json` | 清单 |
## 验证
一次打包运行以 `verify` 通过为完成:两项产物存在,哈希与清单一致,内核命令行在限制之内,启动镜像不大于它所来自的分区。
启动该产物是另一步,另行记录。
产物缺失或与清单不符、内核命令行达到 1000 字节、`boot.img` 超过 `boot_partition_bytes`,`verify` 都会失败。启动这些产物是另一步,另行记录。
## 采用
给尚无该脚本的设备仓库:
1. 从参考设备仓库复制 `scripts/package.sh`。
2. 填写 `board.toml`,直到 `--check` 不再报告缺失值。
3. 把产物记录到设备 `porting.toml` 的 packaging 区域。
4. 把运行方式加入构建文档。
1. 把 `templates/package.sh` 复制为设备仓库的 `scripts/package.sh`。
2. 在 `board.toml` 加 `[package]` 和 `[package.defconfig]`,为其他配置加 `[os_overrides]`。
3. 对每个配置运行 `scripts/package.sh --check --os <profile>`,修正报告的问题。
4. 把运行记录到 `porting.toml` 的 `packaging` 区域。
[构建与启动](/zh/building)、[设备仓库](/zh/porting/device-repository)
+8
View File
@@ -83,6 +83,14 @@ unixnu clean
删除板级输出下的 `tree`、`logs`、`kernel`、`package`、`boot` 和 `edk2-conf`,保留已拉取源码。
### release
```
unixnu release [--os VERSION] [--no-deps] [--check]
```
为设备依次运行固定步骤 `deps`、`preflight`、`patches`、`build`、`pack` 和 `verify`,然后写出 `package.manifest.json`。设备仓库的 `scripts/package.sh` 调用它。见[设备打包脚本](/zh/porting/packaging)。
## 选项
| 选项 | 含义 |