From dff0f533f7be1bf7e96c03f0ea8f12313162512a Mon Sep 17 00:00:00 2001 From: UniXNU Docs Date: Sun, 25 Oct 2026 03:59:12 +0800 Subject: [PATCH] docs: add staged log capture and automated boot testing --- AGENTS.md | 2 +- docs/.vitepress/config.mts | 7 +- docs/devices/sheng-unattended-test.md | 160 +++++++++++++++----- docs/devices/sheng.md | 4 +- docs/guide/debugging.md | 10 +- docs/index.md | 2 +- docs/porting/bring-up.md | 8 + docs/porting/index.md | 7 + docs/porting/log-capture.md | 181 +++++++++++++++++++++++ docs/porting/uefi-firmware.md | 7 + docs/reference/configuration.md | 1 + docs/zh/devices/sheng-unattended-test.md | 148 +++++++++++++----- docs/zh/devices/sheng.md | 3 +- docs/zh/guide/debugging.md | 9 +- docs/zh/index.md | 2 +- docs/zh/porting/bring-up.md | 6 + docs/zh/porting/index.md | 6 + docs/zh/porting/log-capture.md | 150 +++++++++++++++++++ docs/zh/porting/uefi-firmware.md | 6 + docs/zh/reference/configuration.md | 1 + 20 files changed, 642 insertions(+), 78 deletions(-) create mode 100644 docs/porting/log-capture.md create mode 100644 docs/zh/porting/log-capture.md diff --git a/AGENTS.md b/AGENTS.md index ef702ba..1e5c335 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,7 +20,7 @@ files in UniXNU before selecting components or changing a port: | Component work | Component page under `docs/drivers/`, component `README.md`, catalog build command, dependencies, and relevant source | | Kernel work | `docs/xnu/source-and-patches.md`, `docs/xnu/patch-reference.md`, selected OS `profile.toml`, XNU source and ordered patch series | | Image assembly | `docs/concepts/prelink.md`, `docs/concepts/payload.md`, `docs/porting/uefi-firmware.md`, device firmware configuration | -| Verification | `docs/building.md`, `docs/porting/bring-up.md`, selected device page | +| Verification | `docs/building.md`, `docs/porting/bring-up.md`, `docs/porting/log-capture.md`, selected device page | | Migration | `docs/porting/migration.md` | | Documentation | `docs/contributing/documentation.md` | diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index a54e57c..ca21ce4 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -23,6 +23,7 @@ function taskSidebars(prefix: string, zh: boolean) { item('Boot the image', '启动镜像', 'guide/boot'), item('Boot arguments', '启动参数', 'xnu/boot-arguments'), item('Logs and checkpoints', '日志与检查点', 'guide/debugging'), + item('Capture logs', '抓取日志', 'porting/log-capture'), item('Troubleshooting', '故障排查', 'reference/troubleshooting'), item('QEMU verification', 'QEMU 验证', 'reference/qemu'), ]), @@ -55,6 +56,7 @@ function taskSidebars(prefix: string, zh: boolean) { group('4. Verify and publish', '4. 验证与发布', [ item('Build and boot', '构建与启动', 'building'), item('Bring-up sequence', '启动验证顺序', 'porting/bring-up'), + item('Log capture and boot tests', '日志抓取与启动测试', 'porting/log-capture'), item('Porting record', '适配记录', 'porting/records'), item('Publish documentation', '发布文档', 'contributing/documentation'), ]), @@ -138,7 +140,7 @@ export default withMermaid(defineConfig({ items: [ { text: '设备列表', link: '/zh/devices/' }, { text: '小米平板 6S Pro(sheng)', link: '/zh/devices/sheng' }, - { text: '无人值守测试', link: '/zh/devices/sheng-unattended-test' }, + { text: 'sheng 日志抓取示例', link: '/zh/devices/sheng-unattended-test' }, { text: '社区移植', collapsed: true, @@ -253,7 +255,6 @@ export default withMermaid(defineConfig({ alt: 'UniXNU', }, siteTitle: 'UniXNU', - socialLinks: [{ icon: 'github', link: 'https://github.com/UniXNU/UniXNU' }], nav: [ { text: 'Port a device', link: '/porting/', activeMatch: '^/porting/' }, { text: 'Build and boot', link: '/building', activeMatch: '^/(guide/|building)' }, @@ -273,7 +274,7 @@ export default withMermaid(defineConfig({ items: [ { text: 'Devices', link: '/devices/' }, { text: 'Xiaomi Pad 6S Pro (sheng)', link: '/devices/sheng' }, - { text: 'Unattended test cycle', link: '/devices/sheng-unattended-test' }, + { text: 'sheng log capture example', link: '/devices/sheng-unattended-test' }, { text: 'Community ports', collapsed: true, diff --git a/docs/devices/sheng-unattended-test.md b/docs/devices/sheng-unattended-test.md index 0bf752b..45f69ae 100644 --- a/docs/devices/sheng-unattended-test.md +++ b/docs/devices/sheng-unattended-test.md @@ -1,60 +1,152 @@ -# Unattended test cycle +# sheng log capture example -Two boot arguments make a sheng hardware run unattended. Neither is enabled by default. +Follow [Capture logs and automate boot tests](/porting/log-capture) for the porting +sequence, including QR export during firmware bring-up. This page supplies sheng's +storage, reset and reader inputs for the later capture stages. -| Argument | Effect | +## 1. Prepare the inputs + +Use the selected [sheng repository](/devices/sheng), a built kernel/package, +configured [local build inputs](/reference/configuration#local-build-inputs), +fastboot and Python 3. Run the following commands from the main UniXNU checkout: + +```sh +DEVICE_REPO=$(cd ../UniXNU-sheng && pwd) +TARGET="$PWD/out/sheng/ipados-17.7.11-21H461/sheng" +mkdir -p "$TARGET/boot" +fastboot devices +``` + +Record the device serial for the commands below. The reader needs these inputs: + +- `boot_sheng_singleboot.img` from the + [sheng Linux release](https://github.com/ianchb/sm8550-mainline/releases), with + Android header version 0, appended DTB and an empty ramdisk. +- A static AArch64 Linux BusyBox with shell, mount, USB-reader utilities, + `dd`, `gzip`, `base64` and `md5sum` applets. +- `nvmem-reboot-mode.ko` from the same kernel release's `linux-xiaomi-sheng.deb`. +- `rebootbl`, compiled from `package/linux-log/rebootbl.cpp` with an AArch64 Linux + toolchain. It uses Linux syscalls and the board DT's reboot-mode cell. + +For example, with LLVM's `clang++` and `ld.lld` installed: + +```sh +clang++ --target=aarch64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -fno-stack-protector -fno-exceptions -fno-rtti -Wl,-e,start \ + "$DEVICE_REPO/package/linux-log/rebootbl.cpp" -o "$TARGET/boot/rebootbl" +python3 "$DEVICE_REPO/package/linux-log/build-linux-log-boot.py" \ + --boot /path/to/boot_sheng_singleboot.img --busybox /path/to/busybox \ + --rebootbl "$TARGET/boot/rebootbl" --module /path/to/nvmem-reboot-mode.ko \ + --out "$TARGET/boot/sheng-linux-log.img" +``` + +**Result:** a reader image that uses sheng's Linux kernel and DTB. It reads the +last 32 MiB of `userdata` into RAM and exposes a USB CDC ACM shell. Storage access +is read-only. Its build command prints `BUILT` and the output path. + +## 2. Build a logging image + +`BootLog.c` writes diagnostic snapshots and the kernel message buffer through +ShengUfs into the reserved last 32 MiB of `userdata`. The writer opens the region +after ShengUfs reads the root layout. Check that this reservation matches the +installed [storage layout](/concepts/userdata). + +| Argument | Behavior | | --- | --- | -| `sheng-log=1` | Starts `BootLog` from the board monitor. It writes the diagnostic page, banner, GPU rows and kernel message buffer to the last 32 MiB of `userdata`. | -| `sheng-autoreset=` | After that many seconds of log time, writes the PMIC reboot-reason cell and resets into fastboot. It runs only with `sheng-log=1`. | +| `sheng-log=1` | Start the persistent writer from the board monitor | +| `sheng-autoreset=120` | Attempt return to fastboot after 120 seconds of log time and a successful sync; the board monitor also marks the reboot reason and starts watchdog recovery when its hardware probe succeeds | -Build the test image with both arguments: +Build a logging payload first, using the saved local inputs: ```sh -./unixnu build payload --unique-chip-id --trust-cache --data-ramdisk \ - --kernel-arg=sheng-log=1 --kernel-arg=sheng-autoreset=120 +./unixnu payload --kernel-arg=sheng-log=1 +./unixnu bootimg ``` -The log writer opens the window only after ShengUfs has read the root layout. The reset happens once, after that round's log is on the medium. +**Result:** `payload/` and `boot/boot.img` under `$TARGET` contain the updated +arguments. Complete the manual cycle before adding timed reset. -## Log reader +## 3. Run one manual capture {#manual-cycle} -The reader is a fastboot-boot-only Linux image. It copies the log window into RAM, offers a USB CDC ACM shell and mounts nothing. Build it from the pinned Linux release inputs: +Set `SERIAL` to the identifier reported by `fastboot devices`: ```sh -python3 package/linux-log/build-linux-log-boot.py \ - --boot boot_sheng_singleboot.img --busybox busybox \ - --rebootbl rebootbl --module nvmem-reboot-mode.ko \ - --out out/sheng/ipados-17.7.11-21H461/sheng/boot/sheng-linux-log.img +SERIAL= +fastboot -s "$SERIAL" boot "$TARGET/boot/boot.img" ``` -`rebootbl` is the static aarch64 Linux program in `package/linux-log/rebootbl.cpp`. It calls `reboot(RESTART2, "bootloader")` through the device tree's `nvmem-reboot-mode` cell. - -## Run +Wait for the checkpoint under test, then use the device's bootloader key sequence +to return to fastboot. Boot the reader: ```sh -fastboot boot out/sheng/ipados-17.7.11-21H461/sheng/boot/boot.img -# Wait for the tablet to return to fastboot by itself. -fastboot boot out/sheng/ipados-17.7.11-21H461/sheng/boot/sheng-linux-log.img -python3 scripts/read-sheng-log.py --wait 240 +fastboot -s "$SERIAL" boot "$TARGET/boot/sheng-linux-log.img" ``` -`read-sheng-log.py` fetches the window over `/dev/cu.usbmodem*`, writes `build/sheng-logs/-/` and then runs `rebootbl`. The tablet returns to fastboot for the next image. - -The one-command form runs the same cycle: +Wait for its `ready: shell on USB serial` message. On macOS: ```sh -SERIAL= READER=out/sheng/ipados-17.7.11-21H461/sheng/boot/sheng-linux-log.img \ - scripts/run-sheng-unattended.sh out/sheng/ipados-17.7.11-21H461/sheng/boot/boot.img 420 +python3 "$DEVICE_REPO/scripts/read-sheng-log.py" --wait 240 --out "$TARGET/logs/captures" ``` -If the tablet does not return within the limit, the script says so and waits for a manual fastboot entry. +On Linux, find the reader's actual CDC port, ensure your account can open it, +then pass it explicitly: -## Default off +```sh +ls /dev/ttyACM* +python3 "$DEVICE_REPO/scripts/read-sheng-log.py" \ + --port /dev/ttyACM0 --out "$TARGET/logs/captures" +``` -- `board.toml` and the default kernel arguments do not set `sheng-log` or `sheng-autoreset`. -- `BootLog.c` and `BootReset.c` are compiled into the kernel, but they do nothing without those arguments. -- The build scripts do not add the arguments to any image. +**Result:** `logs/captures/-/` contains `log.bin`, `header.txt`, +`msgbuf.txt`, `slots.txt` and `latest.txt`. Check the boot ID, snapshots and write +errors. The reader sends `/bin/rebootbl` after transfer. Confirm the same serial +returns with `fastboot devices`. A `no log header` error calls for checking writer +startup and the reserved region before repeating the run. -## Offline check +## 4. Enable the automatic cycle {#automated-cycle} -`package/linux-log/check-linux-log-qemu.py` boots the reader in QEMU virt with a GPT disk that holds a synthetic log window. It checks partition lookup, the copy, the transfer and the decoder. It does not cover USB, UFS or the XNU writer. +Rebuild both outputs with timed reset: + +```sh +./unixnu payload --kernel-arg=sheng-log=1 --kernel-arg=sheng-autoreset=120 +./unixnu bootimg +``` + +The normal reset follows a successful log sync. The board monitor's watchdog +path can recover a stalled kernel: it requests a 60-second watchdog timeout and +pings until 60 seconds beyond the configured reset deadline. Record whether the +run returned normally or needed recovery. + +On a macOS host with one reader serial device, run: + +```sh +SERIAL="$SERIAL" READER="$TARGET/boot/sheng-linux-log.img" \ + bash "$DEVICE_REPO/scripts/run-sheng-unattended.sh" "$TARGET/boot/boot.img" 420 +``` + +The runner changes into the device repository, so these image paths are absolute. +It boots the test image, waits for return to fastboot, starts the Linux reader and +fetches the logs. Its automatic serial discovery uses `/dev/cu.usbmodem*`; on +Linux, use the explicit-port capture in step 3 after the timed return, or adapt +the runner to pass that port. The runner saves captures under +`UniXNU-sheng/build/sheng-logs/-/`. + +If the 420-second return timeout expires, the runner reports it and waits for +manual bootloader entry. Preserve this outcome in the [porting record](/porting/records). +Confirm the final return to fastboot before starting another run. + +## Reader verification + +The existing `package/linux-log/check-linux-log-qemu.py` exercises partition +lookup, RAM copying, transfer and decoding with a synthetic GPT log region: + +```sh +python3 "$DEVICE_REPO/package/linux-log/check-linux-log-qemu.py" \ + --image "$TARGET/boot/sheng-linux-log.img" --kernel /path/to/qemu-virt-linux-Image \ + --work "$TARGET/logs/reader-qemu" +``` + +Use an AArch64 QEMU `virt` Linux kernel with virtio block support and the matching +host QEMU tools. Record this host check separately from board storage writes, +USB transfer and reset observations. Continue with the +[shared test procedure](/porting/log-capture#automated-cycle). diff --git a/docs/devices/sheng.md b/docs/devices/sheng.md index 764d2e6..28714de 100644 --- a/docs/devices/sheng.md +++ b/docs/devices/sheng.md @@ -9,6 +9,8 @@ porting record. Use the [record guide](/porting/records), [repository specification](/porting/device-repository) and [UFS guide](/porting/ufs) with the relevant section below. -For repeated hardware runs, use the [unattended test cycle](/devices/sheng-unattended-test) to collect logs and return to fastboot. +Follow [log capture and boot tests](/porting/log-capture) in bring-up order. +The [sheng example](/devices/sheng-unattended-test) gives the reader inputs, +storage region and reset commands for this board. diff --git a/docs/guide/debugging.md b/docs/guide/debugging.md index bc14120..470a536 100644 --- a/docs/guide/debugging.md +++ b/docs/guide/debugging.md @@ -1,6 +1,6 @@ # Debugging and logs -A bring-up produces four kinds of evidence: serial output, the on-screen diagnostic page, the panic screen and build reports. Collect them together. +Collect firmware logs, kernel output, diagnostic screenshots and build reports for each bring-up checkpoint. ## Procedure {#procedure} @@ -10,6 +10,12 @@ A bring-up produces four kinds of evidence: serial output, the on-screen diagnos 4. Apply one diagnostic change. Rebuild the affected artifact; boot-argument changes require `./unixnu payload` and `./unixnu bootimg`. Repeat the failing operation and record the last confirmed checkpoint. 5. Save an [evidence bundle](#evidence-bundle) and update the affected [porting record](/porting/records). A useful result identifies the failing stage, input versions and exact error. +## Capture by boot stage + +Follow [log capture and automated tests](/porting/log-capture): QR export from +the firmware menu, UART or screen diagnostics at kernel entry, then persistent +logs and automated cycles after storage works. + ## USB debug terminal The host tools from the giulia port are available as `scripts/debug_terminal.py` and the Windows CMD launcher `scripts/debug-terminal.cmd`. They capture CDC logs, queue bounded diagnostic commands, export topic logs and decode GSC1 framebuffer packets. Python 3.10 or newer is required. Interactive editing and PTY keyboard input require Windows CMD; scripted capture works on Windows, Linux and macOS. @@ -62,6 +68,8 @@ The optional C-sender interoperability test needs `GIULIA_SCREEN_FIXTURE` pointi | Source | Transport | Use | | --- | --- | --- | +| [Firmware log export](/porting/log-capture#qr-logs) | OneSend QR frames | Current UEFI Advanced Logger buffer | +| [Persistent logs](/porting/log-capture#persistent-logs) | Reserved storage and Linux reader | Kernel messages and diagnostic snapshots | | UEFI serial | UART | Firmware, UniXNU and DarwinBoot | | Kernel serial | UART selected by `serial=` | XNU console and panic output | | Diagnostic page | Framebuffer | Live state after the console stops | diff --git a/docs/index.md b/docs/index.md index 3c9bb00..9dd342e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,7 +16,7 @@ hero: text: Port a device link: /porting/ - theme: brand - text: Devices + text: Supported devices link: /devices/ - theme: alt text: GitHub diff --git a/docs/porting/bring-up.md b/docs/porting/bring-up.md index db784ed..bd66195 100644 --- a/docs/porting/bring-up.md +++ b/docs/porting/bring-up.md @@ -43,6 +43,10 @@ Minimal test: an empty ramdisk. UniXNU falls back to its built-in configuration ./unixnu bootimg --uefi /path/to/Mu-Silicium --dtb board.dtb --ramdisk none ``` +Before continuing, [scan the firmware log](/porting/log-capture#qr-logs) from +**Tools → Advanced Logger**. Prepare the platform logger and plugin with the +[integration steps](/porting/log-capture#firmware-setup). + ## Stage 3: Payload Goal: UniXNU reads `unixnu.toml` and the payload files. @@ -98,6 +102,10 @@ Checks: A root match failure leaves the kernel without a root device. Check the UUID, the window offsets and the partition capacity. +Once storage works, [adapt persistent capture](/porting/log-capture#persistent-logs) +with a kernel writer and Linux reader. Complete one manual retrieval before +enabling timed reset and the automated cycle. + ## Stage 7: Userland Goal: `launchd` runs and the first user process reaches a visible state. diff --git a/docs/porting/index.md b/docs/porting/index.md index f55dd5e..1d005cc 100644 --- a/docs/porting/index.md +++ b/docs/porting/index.md @@ -104,6 +104,9 @@ Follow [UEFI integration](/porting/uefi-firmware#required-integration) to includ UniXNU, DarwinBoot and payload filesystem support. For a Mu-Silicium initrd, include `UniXNURamDiskDxe`, DiskIoDxe and FAT support in the DSC and FDF. +Include the [firmware log exporter](/porting/log-capture#firmware-setup) so +you can scan logs from the menu during initial bring-up. + **Result:** a buildable firmware configuration and two identified tree inputs: the board DTS for XNU's ADT, and the firmware DTB for boot-image assembly. @@ -133,6 +136,10 @@ in [apply arguments](/xnu/boot-arguments#apply-arguments). failure, record the last completed checkpoint and use [debugging](/guide/debugging) and [troubleshooting](/reference/troubleshooting). +Set up [QR log export](/porting/log-capture#firmware-setup) during firmware integration +and save the firmware log before kernel handoff. After storage verification, follow +the same guide through persistent capture, a manual cycle and automated tests. + ## 8. Publish the port Validate the record from the main checkout: diff --git a/docs/porting/log-capture.md b/docs/porting/log-capture.md new file mode 100644 index 0000000..e1b194f --- /dev/null +++ b/docs/porting/log-capture.md @@ -0,0 +1,181 @@ +# Capture logs and automate boot tests + +Set up log capture as you bring up the board. Start with firmware logs, collect +kernel evidence at handoff, then add persistent logs and automated reboot cycles. +Use the [bring-up checkpoints](/porting/bring-up) to identify the stage being tested. + +| Stage | Required support | Saved result | +| --- | --- | --- | +| UEFI menu | GOP display, menu input, Advanced Logger and QR plugin | Firmware `.log` file scanned from the screen | +| XNU entry | UART or framebuffer diagnostics | Serial log or photograph of the last checkpoint/panic | +| Storage | Reserved log region, kernel writer and Linux reader | Kernel message buffer and diagnostic snapshots | +| Repeated tests | Working log retrieval and return to bootloader | One evidence directory per boot | + +## 1. Include the firmware log exporter {#firmware-setup} + +Prepare the firmware checkout using [UEFI integration](/porting/uefi-firmware). +The shared exporter is +`package/UniXNUPkg/Driver/AdvancedLogDxe/AdvancedLogDxe.inf` in UniXNU. +It reads the Advanced Logger memory buffer while UEFI boot services are active. + +1. In the firmware DSC `[Components]`, add: + + ```ini + UniXNUPkg/Driver/AdvancedLogDxe/AdvancedLogDxe.inf + ``` + + In the FDF's DXE firmware volume, add: + + ```ini + INF UniXNUPkg/Driver/AdvancedLogDxe/AdvancedLogDxe.inf + ``` + +2. Enable the platform's Advanced Logger producer and route the desired firmware + debug output into it. The exporter dispatches after `gAdvancedLoggerProtocolGuid` + is installed. Its INF also requires `AdvLoggerPkg`, `MsGraphicsPkg`, + `AdvancedLoggerAccessLib` and `QrEncoderLib`. + From the firmware checkout, find the library instances supplied by its Mu revision: + + ```sh + find . -name '*AdvancedLogger*.inf' -o -name '*QrEncoder*.inf' + ``` + + Map the access and QR libraries in the DSC `[LibraryClasses]` and include their + package roots in `board.toml` `[firmware] packages`. Initialize the submodules + containing those packages if the search returns no files. Use the platform's + Advanced Logger configuration for its buffer and debug-library mappings. + +3. Set `gUniXNUPkgTokenSpaceGuid.PcdUniXNUDeviceModel` in the DSC `[PcdsFixedAtBuild]` + to the board's ASCII name. The export filename uses this value. +4. In the device's `board.toml`, add `tools = true` to its existing `[payload]` + table. This adds **Tools** to the generated boot menu. A hand-authored + `unixnu.toml` uses an [entry with `action = "tools"`](/reference/boot-configuration). +5. From the main UniXNU checkout, with the device selected and + [local inputs configured](/reference/configuration#local-build-inputs), run: + + ```sh + ./unixnu firmware + ./unixnu payload + ./unixnu bootimg + ``` + +**Result:** the rebuilt image contains the exporter, and **Tools → Advanced Logger** +appears when the platform's logging protocol is available. + +## 2. Scan the firmware log before kernel handoff {#qr-logs} + +Prepare a second phone or camera device with [OneSend (扫传)](https://onesend.01mvp.com). +The exporter sends a sequence of OneSend QR frames. + +1. Boot the image from the main checkout: + + ```sh + fastboot devices + fastboot -s boot out////boot/boot.img + ``` + +2. Stay in the UniXNU menu. Select **Tools**, then **Advanced Logger**. + The plugin takes a snapshot of the current firmware log when opened. + If a loader error returns you to the menu, open the plugin then to capture it + before resetting the device. +3. Open OneSend's receiving scanner, allow camera access and keep the complete QR + square in view. Keep scanning as frames cycle until the receiver finishes. +4. Use **Down / j** to slow rotation and **Up / k** to speed it up. The initial + interval is one second; five speeds range from 5 seconds to 250 milliseconds. + Boards that map volume buttons to Up/Down use those buttons. **Enter** or + **Escape** returns to the menu; a board's power button works when mapped to Enter. +5. Save the received `--