Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions apps/starry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,23 @@ PATH="$PWD/target/qemu-k230-docker-build:$PATH" \
See `k230-kpu-nncase/README.md` and `docs/k230-kpu-nncase-runtime.md` for the
asset preparation flow.

## macOS HVF Self-Build

The `macos-selfbuild` case is an Apple Silicon macOS workflow that boots an
AArch64 StarryOS SMP kernel with QEMU/HVF, enters the StarryOS guest userland,
and runs guest `cargo build` to build StarryOS again.

```bash
KERNEL=target/aarch64-unknown-none-softfloat/release/starryos.bin \
ROOTFS=tmp/axbuild/rootfs/rootfs-aarch64-hvf-selfbuild.img \
SMP=8 JOBS=8 RAYON_NUM_THREADS=1 RUSTC_THREADS=2 SOURCE_TMPFS=1 \
apps/starry/macos-selfbuild/run_selfbuild.sh
```

See `macos-selfbuild/README.md` for the no-Docker reviewer path, native rootfs
build/check flow, QEMU/HVF details, PASS markers, and representative self-build
timings.

## Redis

The `redis` case is a QEMU app workflow that installs Redis into a temporary
Expand Down
270 changes: 270 additions & 0 deletions apps/starry/macos-selfbuild/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# StarryOS macOS HVF Self-Build

This case is an Apple Silicon macOS reproduction workflow. The host runs QEMU
with HVF, boots an AArch64 StarryOS SMP guest, and runs guest `cargo build` to
build StarryOS again inside StarryOS.

The normal reproduction path builds the rootfs locally on macOS and does not use
Docker. `build_rootfs.sh` creates the AArch64 Alpine guest rootfs, installs the
pinned guest Rust/Cargo toolchain, prefetches the offline Cargo cache, and
injects the current TGOSKits source tree.

## What This Demonstrates

- host: Apple Silicon macOS;
- accelerator: QEMU HVF;
- guest kernel: StarryOS AArch64 SMP kernel;
- guest workload: StarryOS guest runs Cargo and builds the `starryos` binary;
- stable build shape: 8-vCPU guest with eight Cargo jobs (`SMP=8 JOBS=8`);
- pass marker: `===STARRY-MACOS-SELFBUILD-PASS jobs=<N> elapsed=<seconds>===`.

The default reproduction proves that the StarryOS SMP guest can complete a
self-build while booted with 8 vCPUs and running Cargo with eight jobs.

Using AArch64/HVF keeps the guest ISA aligned with the Mac host CPU. This avoids
the cross-ISA TCG cost of RISC-V-on-macOS experiments and makes the self-build
result practical to reproduce on a laptop.

## Prerequisites

```bash
brew install qemu e2fsprogs zig llvm
```

The scripts use:

- `qemu-system-aarch64`;
- `debugfs` from Homebrew `e2fsprogs`;
- `zig` or an `aarch64-linux-musl-gcc` cross compiler for the seed kernel;
- `llvm-nm` and `llvm-objdump`, with Homebrew `llvm` used as fallback.

The generated self-build rootfs contains the guest Rust/Cargo toolchain,
offline Cargo dependencies, and a TGOSKits source tarball. `check_rootfs.sh`
verifies the minimum paths.

## Reproduce From a Fresh Clone

Clone and enter the branch under test:

```bash
git clone https://github.com/yks23/tgoskits.git
cd tgoskits
git checkout app/starry-macos-selfbuild-only
```

Run the complete reproduction on macOS:

```bash
RUST_DIST_SERVER=https://rsproxy.cn \
STARRY_CARGO_REGISTRY_INDEX=sparse+https://rsproxy.cn/index/ \
apps/starry/macos-selfbuild/reproduce.sh
```

The mirror variables are optional. Omit them to use the official Rust and
crates.io endpoints, or set them to closer mirrors when `static.rust-lang.org`
or `index.crates.io` is slow.

`reproduce.sh` runs the three required steps: build or refresh the rootfs, build
the seed kernel, and launch the QEMU HVF self-build. On a base M1 with 8 GB
memory, close other heavy applications before running the 8-vCPU case; if it is
memory pressured, first verify the setup with:

```bash
SMP=4 JOBS=4 MEM=3072M \
RUST_DIST_SERVER=https://rsproxy.cn \
STARRY_CARGO_REGISTRY_INDEX=sparse+https://rsproxy.cn/index/ \
apps/starry/macos-selfbuild/reproduce.sh
```

The rootfs build downloads Alpine AArch64 APKs and Rust nightly components, then
runs `cargo fetch` on the host to populate the guest offline cache. The
`cargo fetch` phase may print only `Updating crates.io index` for several
minutes while the sparse registry cache is being populated.

For reproducibility, the default native rootfs payload is pinned to Alpine
`v3.23` and Rust `nightly-2026-05-28`. Do not switch `ALPINE_BRANCH=edge` for
the graded reproduction: Alpine edge currently provides a newer Cargo/Rust
package set and can change the build-std schedule substantially.

The expected output ends with:

```text
STARRY_MACOS_SELFBUILD_ROOTFS_OK
```

After every `git pull`, branch switch, or source edit, refresh the source
payload embedded in the rootfs before running QEMU:

```bash
apps/starry/macos-selfbuild/prepare_rootfs.sh
```

`run_selfbuild.sh` checks `/opt/tgoskits-src.meta` by default and exits early if
the rootfs was built from a different commit. This avoids accidentally running
an old rootfs for an hour. Set `REQUIRE_FRESH_ROOTFS=0` only for deliberate
stale-rootfs experiments.

If a prebuilt rootfs artifact is supplied, it can still be placed at the
standard path instead of rebuilding locally. Use either a local downloaded file:

```bash
apps/starry/macos-selfbuild/fetch_rootfs.sh \
--input /path/to/rootfs-aarch64-hvf-selfbuild.img
```

or a direct artifact URL:

```bash
ROOTFS_URL='https://.../rootfs-aarch64-hvf-selfbuild.img' \
apps/starry/macos-selfbuild/fetch_rootfs.sh
```

Build the seed StarryOS kernel on macOS:

```bash
apps/starry/macos-selfbuild/build_kernel.sh
```

Run the complete 8-vCPU, eight-Cargo-job self-build:

```bash
KERNEL=target/aarch64-unknown-none-softfloat/release/starryos.bin \
ROOTFS=tmp/axbuild/rootfs/rootfs-aarch64-hvf-selfbuild.img \
SMP=8 \
JOBS=8 \
RAYON_NUM_THREADS=1 \
RUSTC_THREADS=2 \
SOURCE_TMPFS=1 \
QEMU_TIMEOUT_SEC=10800 \
apps/starry/macos-selfbuild/run_selfbuild.sh
```

A successful run prints:

```text
===STARRY-MACOS-SELFBUILD-QEMU-AARCH64-PROFILE expected_crates~420===
===STARRY-MACOS-SELFBUILD-PASS jobs=8 elapsed=<seconds>===
===STARRY-MACOS-SELFBUILD-RUN-END rc=0===
```

The qemu-aarch64 reproducible profile should show:

```text
rustc_threads=2
features=plat-dyn,ax-driver/virtio-blk,ax-driver/virtio-net,ax-driver/virtio-gpu,ax-driver/virtio-input,ax-driver/virtio-socket,starry-kernel/input,starry-kernel/vsock
```

The guest refuses a run whose `RUSTC_THREADS` differs from `2` unless
`ALLOW_SLOW_SELFBUILD=1` is explicitly set. This keeps the graded run on the
same qemu-aarch64 profile that was debugged for reproducibility.

The host runner also refuses unexpectedly large Cargo totals by default. The
current qemu-aarch64 profile is expected to report about `420` Cargo units. A much larger
total usually means a stale rootfs or slow feature set is being used; refresh the
rootfs from the current checkout and rerun the command above.

Logs are written under:

```text
target/starry-macos-selfbuild/logs/
```

The runner copies the input rootfs into
`target/starry-macos-selfbuild/rootfs/`, injects the guest runner scripts, and
runs QEMU against that working copy, so the input artifact is not modified. Set
`QEMU_SNAPSHOT=1` only when an explicit throw-away QEMU disk overlay is desired.

## Quick Boot Check

To verify the rootfs and kernel reach the StarryOS guest shell without starting
the Cargo build:

```bash
KERNEL=target/aarch64-unknown-none-softfloat/release/starryos.bin \
ROOTFS=tmp/axbuild/rootfs/rootfs-aarch64-hvf-selfbuild.img \
SMP=8 \
BOOT_ONLY=1 \
QEMU_TIMEOUT_SEC=180 \
apps/starry/macos-selfbuild/run_selfbuild.sh
```

`BOOT_ONLY=1` is only a smoke test. Leave it unset for the full self-build.

## Rootfs Contract

The generated rootfs is intentionally kept outside git because it is large. It
must contain:

```text
/usr/bin/cargo
/opt/rust-nightly/bin/rustc
/opt/rust-nightly/lib/rustlib/src/rust/library/Cargo.lock
/usr/bin/aarch64-linux-musl-gcc
/opt/rustc-nightly-sysroot
/opt/rustdoc-nightly-sysroot
/opt/tgoskits/Cargo.toml or /opt/tgoskits-src.tar
/root/.cargo/registry/index
/root/.cargo/registry/cache
```

Check an already placed rootfs with:

```bash
apps/starry/macos-selfbuild/check_rootfs.sh \
tmp/axbuild/rootfs/rootfs-aarch64-hvf-selfbuild.img
```

If a prebuilt toolchain rootfs is available and only the source tree needs to be
refreshed, inject the current checkout without rebuilding the toolchain:

```bash
apps/starry/macos-selfbuild/prepare_rootfs.sh \
--base-rootfs tmp/axbuild/rootfs/rootfs-aarch64-hvf-toolchain.img \
--output-rootfs tmp/axbuild/rootfs/rootfs-aarch64-hvf-selfbuild.img
```

`prepare_rootfs.sh` writes `/opt/tgoskits-src.tar` and
`/opt/tgoskits-src.meta`. The host runner checks this metadata before booting
QEMU, and the guest checks it again when `TGOSKITS_COMMIT` is supplied.

## Important Knobs

| Variable | Default | Meaning |
| --- | --- | --- |
| `SMP` | `8` | QEMU vCPU count, passed to `-smp`. |
| `JOBS` | `SMP` | Guest Cargo job count. |
| `RAYON_NUM_THREADS` | `1` | Rayon worker limit for guest build scripts. |
| `RUSTC_THREADS` | `2` | Guest `-Zthreads=<N>` value for the reproducible qemu-aarch64 profile. |
| `SOURCE_TMPFS` | `1` | Copy source into `/tmp` before building. |
| `QEMU_TIMEOUT_SEC` | `7200` | Host timeout; use `0` to disable. |
| `QEMU_ACCEL` | `hvf` | QEMU accelerator string. |
| `QEMU_MACHINE` | `virt,gic-version=3` | QEMU machine string. |
| `QEMU_CPU` | `host` | QEMU CPU model for HVF. |
| `BOOT_ONLY` | `0` | Stop after the shell prompt instead of starting Cargo. |
| `BUILD_TARGET` | `aarch64-unknown-none-softfloat` | Guest Cargo target. |
| `BUILD_PACKAGE` | `starryos` | Cargo package to build. |
| `BUILD_BIN` | `starryos` | Cargo binary to build; set `none` for library package diagnostics. |
| `FEATURES` | `plat-dyn,ax-driver/virtio-blk,ax-driver/virtio-net,ax-driver/virtio-gpu,ax-driver/virtio-input,ax-driver/virtio-socket,starry-kernel/input,starry-kernel/vsock` | QEMU AArch64 feature profile used by the reproducible self-build; set it to an empty string for single-crate diagnostics. |
| `REQUIRE_FRESH_ROOTFS` | `1` | Refuse a rootfs whose embedded source commit does not match the checkout. |
| `ALLOW_SLOW_SELFBUILD` | `0` | Permit the slow full-device feature profile only for explicit experiments. |
| `GUEST_MONITOR_INTERVAL_SEC` | `60` | Print guest `ps` snapshots while Cargo runs; set `0` to disable. |
| `EXTRA_RUSTFLAGS` | empty | Extra guest Rust flags for local experiments. |

## Rootfs Rebuild Details

```bash
apps/starry/macos-selfbuild/build_rootfs.sh
```

That helper creates an AArch64 Alpine payload natively on macOS, installs the
pinned guest Rust toolchain and offline Cargo cache, and injects it with
`debugfs`. It writes:

```text
tmp/axbuild/rootfs/rootfs-aarch64-hvf-toolchain.img
tmp/axbuild/rootfs/rootfs-aarch64-hvf-selfbuild.img
```

The script still accepts `--payload` or `ROOTFS_PAYLOAD_URL` for an externally
prepared payload tarball. `--build-payload-with-docker` is kept only as an
explicit maintainer fallback and is not used by the macOS reproduction path.
92 changes: 92 additions & 0 deletions apps/starry/macos-selfbuild/RESULTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# macOS HVF Self-Build Result Notes

This file records the expected result shape for the macOS/HVF self-build
workflow. The authoritative reproduction command is in `README.md`.

## Control Variables

```text
host OS: macOS on Apple Silicon
guest ISA: AArch64
accelerator: QEMU HVF
kernel: StarryOS AArch64 SMP
rootfs: macOS-native generated self-build ext4 image
QEMU disk mode: writable working-copy image; optional QEMU_SNAPSHOT=1 overlay
validated reproduction: SMP=8, JOBS=8
success marker: STARRY-MACOS-SELFBUILD-PASS
```

The validated path boots an 8-vCPU guest and runs Cargo with eight jobs.

The git repository contains the runner, checks, source-level fixes, and the
macOS-native rootfs construction script. The generated rootfs is still kept out
of git because it is large, but reviewers should not need Docker or a prebuilt
artifact to reproduce the macOS/HVF run. A prebuilt rootfs can be supplied only
as a faster optional path.

## Guest Build Shape

Inside the StarryOS guest, the runner executes:

```bash
cargo build \
-p starryos \
--bin starryos \
--target aarch64-unknown-none-softfloat \
-Z build-std=core,alloc \
--target-dir /tmp/starryos-selfbuild-target \
--features plat-dyn,ax-driver/virtio-blk,ax-driver/virtio-net,ax-driver/virtio-gpu,ax-driver/virtio-input,ax-driver/virtio-socket,starry-kernel/input,starry-kernel/vsock \
--release
```

with:

```text
CARGO_BUILD_JOBS=8
RAYON_NUM_THREADS=1
RUSTC_THREADS=2
CARGO_INCREMENTAL=0
CARGO_NET_OFFLINE=true
RUSTC_BOOTSTRAP=1
RUSTC=/opt/rustc-nightly-sysroot
RUSTDOC=/opt/rustdoc-nightly-sysroot
ALLOW_SLOW_SELFBUILD=0
```

The qemu-aarch64 reproducible profile is guarded by the guest script. Unless
`ALLOW_SLOW_SELFBUILD=1` is set for experiments, it refuses runs that do not use
`RUSTC_THREADS=2`.

## Reference Numbers

These are local Apple Silicon reference measurements from the macOS/HVF
self-build experiments. Re-run locally for authoritative numbers on another
machine.

| Case | Time | Notes |
| --- | --- | --- |
| `SMP=8`, `JOBS=8`, qemu-aarch64 profile, tmp source/target, `RUSTC_THREADS=2` | `331s` | latest validated default reproduction |
| `SMP=8`, `JOBS=1`, `SOURCE_TMPFS=0`, tuned feature set | `657s` | historical single-job fallback |
| `SMP=1`, `JOBS=1`, `SOURCE_TMPFS=0`, tuned feature set | `642s` | latest single-vCPU validation |
| `SMP=8`, `JOBS=1`, ext4 source/target | `951s` | slow guest baseline |
| `SMP=8`, `JOBS=8`, ext4 source/target | `917s` | first complete SMP self-build |
| `SMP=8`, `JOBS=8`, tmp target only | `660s` | moves Cargo target output to `/tmp` |
| `SMP=8`, `JOBS=8`, tmp source and target | `642s` | copies source and target output to `/tmp` |
| `SMP=8`, `JOBS=8`, tmp source/target, no LTO | `515s` | `CARGO_PROFILE_RELEASE_LTO=false` |
| `SMP=8`, `JOBS=8`, tmp source/target, no LTO, opt0, CGU256 | `427s` | reduces serial optimized codegen cost |
| host macOS reference | `134s` | host-side lower bound, not inside StarryOS |

Useful ratios:

```text
951s / 331s = 2.87x slow guest baseline to latest stable reproduction
642s / 331s = 1.94x tmp source/target baseline to latest stable reproduction
657s / 331s = 1.99x single-job fallback to eight-job default reproduction
```

## Interpretation

The macOS/HVF app demonstrates a real StarryOS guest self-build, not a host-side
cross build. The remaining gap to the macOS host reference is from filesystem
writeback, process/wait/pipe overhead, SMP scheduling and wakeups, lock
contention, and Cargo's serial critical path.
Loading