Introduce a generic Tools submenu plus a menu-plugin protocol so device tools can be discovered at runtime instead of being hardcoded in UniXNU. Structure: - UniXNUPkg/Include/Protocol/UniXNUMenuPlugin.h: plugin protocol with a Run callback, a content rect and a DrawStatus footer callback. - UniXNUPkg/Library/UniXNULib: discover installed plugins, render a Back + plugin list, and run the selected plugin between the header and footer while keeping the upper UI visible. - UniXNUPkg/Driver/AdvancedLogDxe: first plugin; exports the Advanced Logger log as OneSend QR frames with 5 volume-key speed gears and a 5-segment level bar, drawn with a single Blt. - UniXNUPkg.dec: adds the menu plugin GUID and PcdUniXNUDeviceModel so exported log files are named with the device model. - scripts/unixnu/payload.py, built-in config and docs: `tools = true` appends a Tools entry and documents the `tools` action. The exported QR frames are read with OneSend (扫传): https://onesend.01mvp.com Scope: loader and boot logic are unchanged. This commit only adds the menu/UI plugin path and the Advanced Logger tool; device wiring lives in the platform checkout and is not part of this change.
7.9 KiB
Boot configuration
The UniXNU boot manager reads \EFI\UniXNU\unixnu.toml from the volume it was started from, then from every other volume. A kit directory contains Kit.toml with the same match and injection sections.
unixnu.toml
version = 1
[boot]
timeout = 5
rotate = 0
fallback_timeout = 10
connect_all = true
default = "xnu"
[ui]
title = "UniXNU"
scale = 0
logo = true
layout = "auto"
portrait_below = 800
console = "auto"
[boot]
| Key | Default | Meaning |
|---|---|---|
timeout |
5 | Seconds. Negative waits for input |
rotate |
0 | Idle highlight rotation in seconds. 0 disables it |
fallback_timeout |
10 | Timeout when no input device exists |
connect_all |
true | Calls ConnectController on every handle |
default |
first entry | Entry id or index |
[ui]
| Key | Default | Meaning |
|---|---|---|
title |
UniXNU |
Menu title |
scale |
0 | Glyph scale. 0 selects automatically |
logo |
true | Draws the logo |
layout |
auto |
auto, landscape or portrait |
portrait_below |
800 | With auto, portrait when width / height times 1000 is below this value |
console |
auto |
auto, graphics, text or none |
The portrait layout is a column for a tall panel such as a phone. The logo floats at the top, the entries are numbered cards at the bottom, and the status lines wrap under a rule. The logo carries the UniXNU wordmark, so the title text appears only when logo is false or title is not UniXNU. With auto, a 1080x2400 panel (ratio 450) is portrait, a 3:4 tablet (750) is portrait, and a 4:5 panel (800) or any wider one keeps the landscape layout. Without a scale value, the portrait layout picks a glyph scale of width / 270, so a 1080 pixel wide panel shows about 33 characters per line.
driver
[[driver]]
path = "Drivers/MyDriver.efi"
args = "board=1"
connect = true
enabled = true
| Key | Default | Meaning |
|---|---|---|
path |
required | File path or fv:<GUID> |
args |
Load options | |
connect |
true | Connects controllers after the driver starts |
enabled |
true | false skips the entry |
A kit driver uses file instead of path.
dt_patch
[[dt_patch]]
op = "set"
node = "/chosen"
prop = "bootargs"
value = "console=ttyAMA0"
type = "string"
| Key | Meaning |
|---|---|
op |
set, delete-prop, add-node, delete-node or overlay |
node |
Absolute node path |
prop |
Property name for set and delete-prop |
value |
Value for set |
type |
string, stringlist, u32, u64, bytes or empty |
file |
Overlay file for overlay |
Patches apply to EFI and Linux entries. The Darwin path uses the .adt sidecar.
block_slice
[[block_slice]]
partition = "<GPT name>"
name = "<slice name>"
offset = 0
length = 0
writable = false
enabled = true
| Key | Meaning |
|---|---|
partition |
GPT partition name |
name |
Label in the device path |
offset |
Byte offset from the partition start |
length |
Byte length. 0 means to the end |
writable |
Publishes a writable block device |
enabled |
false skips the slice |
The slice appears as a whole disk with its own device path. A child partition scheme or file system driver can bind to it.
ACPI
[acpi]
add = ["Tables/DSDT.aml", "Tables/SSDT.aml"]
Each table is installed through EFI_ACPI_TABLE_PROTOCOL. The header length must match the file size.
Kits
[[kit]]
path = "Kits/MyKit.kit"
enabled = true
[kits]
autoload = true
directory = "Kits"
Explicit kits load first. With autoload, every *.kit directory under directory loads in name order.
entry
[[entry]]
id = "xnu"
title = "UniXNU"
type = "xnu"
path = "Payloads/kernel.macho"
args = "-v serial=3"
initrd = "Payloads/scratch-data.img"
confirm = "Boot the kernel?"
confirm_titles = ["Normal", "Verbose"]
confirm_args = ["", "debug=0x14e"]
enabled = true
| Key | Meaning |
|---|---|
id |
Entry identifier |
title |
Menu title |
type |
efi, linux, action or xnu |
path |
EFI image, Linux image or kernel path |
args |
Load options or kernel command line |
dtb |
firmware, a file path, or absent |
initrd |
Initrd path |
confirm |
Question shown before the entry boots. The entry never boots by countdown |
confirm_titles |
Optional choice titles. Requires confirm and confirm_args |
confirm_args |
One argument string per choice. The chosen string is appended to args |
action |
reset, shutdown, exit or tools for action entries |
enabled |
false skips the entry |
An entry with confirm boots only when Enter is pressed. Without choices, any other key cancels, and a machine without an input device cancels. With confirm_titles, Up and Down step through the choices and Cancel is selected first. The chosen confirm_args entry is appended to a copy of the entry's args.
When the default entry requires confirmation, the countdown falls back to the first entry that does not.
The built-in configuration has exit, reset, shutdown and tools entries. tools opens a second-level menu listing the installed menu plugins. When no file is found, removable loaders are added in front of them.
[entry.chosen]
[entry.chosen]
bootargs = "console=ttyAMA0"
Every key becomes a /chosen property. These patches apply after the entry patches.
entry.kext
[[entry.kext]]
bundle = "Kexts/MyDriver.kext"
plist = "Contents/Info.plist"
executable = "Contents/MacOS/MyDriver"
enabled = true
Entry kexts apply only to the entry that declares them.
entry.variable
[[entry.variable]]
guid = "00000000-0000-0000-0000-000000000000"
name = "MyVariable"
value = "hello"
type = "ascii"
volatile = true
| Key | Meaning |
|---|---|
guid |
Variable GUID |
name |
Variable name |
value |
Value |
type |
ascii, ucs2, u8, u16, u32, u64 or bytes |
volatile |
false adds EFI_VARIABLE_NON_VOLATILE |
The variables are set before the entry starts.
entry.dt_patch
The entry accepts its own [[dt_patch]] array. Entry patches apply after global patches.
Kit.toml
schema = 1
[kit]
name = "MyKit"
version = "1.0.0"
description = "Board support"
[match]
arch = "AARCH64"
fdt_compatible = ["vendor,board"]
firmware_vendor = ["Vendor"]
requires_protocol = ["00000000-0000-0000-0000-000000000000"]
[[driver]]
file = "MyDriver.efi"
args = "from-kit"
[[overlay]]
file = "board.dtbo"
[[dt_patch]]
op = "set"
node = "/chosen"
prop = "from-kit"
value = "1"
type = "u32"
[[acpi]]
file = "DSDT.aml"
[[kext]]
bundle = "MyDriver.kext"
entry = "xnu"
| Section | Meaning |
|---|---|
[kit] |
Name, version and description |
[match] |
All present keys must match |
[[driver]] |
Driver file relative to the kit |
[[overlay]] |
Device tree overlay relative to the kit |
[[dt_patch]] |
Device tree patch |
[[acpi]] |
ACPI table relative to the kit |
[[kext]] |
Kext bundle scoped to an entry id |
Match keys:
| Key | Meaning |
|---|---|
arch |
AARCH64 |
fdt_compatible |
Strings in the firmware root compatible list |
firmware_vendor |
Substring of gST->FirmwareVendor |
requires_protocol |
GUIDs that must be installed |
Within a key, any listed value matches. Across keys, every key must match.
Menu behavior
| Condition | Result |
|---|---|
| Input device present | Countdown runs to the timeout |
| No input device | fallback_timeout applies |
| Negative timeout with input | Waits for a key |
| Negative timeout without input | fallback_timeout applies |
| Failed boot | Returns to the menu without a countdown |
The menu shows the configuration source, the entry list, the injection summary and the first error.