commit 8e53781e5a0dd5b1a6b264ffee145d7e8a0f925a
parent 66f47611dd938c3f3a445b94fe4e42df02f8d175
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 6 May 2026 13:12:46 -0700
B (kernel.c polish): name DTB/PVH/cpio magics; document sys_unlinkat ignored args
- PVH_HVM_START_{MAGIC,OFF_CMDLINE} constants with the EBX-handoff ABI
note from the (now-deleted) SEED-AMD64-TODO inlined where they're
defined; parse_dtb's amd64 branch uses the names instead of literals.
- CPIO_NEWC_{MAGIC,HDR_SIZE,FIELD,MODE_TYPE_*}; parse_cpio + the
blk_init probe drop the inline byte-by-byte magic check for
str_starts(p, CPIO_NEWC_MAGIC).
- DTB header constants now have a one-line spec reference.
- sys_unlinkat: comment explaining why dirfd and flags are both ignored
(flat path map; no dirs, so AT_REMOVEDIR is a no-op).
Diffstat:
1 file changed, 41 insertions(+), 18 deletions(-)
diff --git a/seed-kernel/kernel.c b/seed-kernel/kernel.c
@@ -118,6 +118,8 @@ static u64 be64(const u8 *p) { return ((u64)be32(p) << 32) | (u64)be32(p + 4); }
/* ─── Flattened Device Tree walker ──────────────────────────────────────── */
+/* DTB ("flattened device tree blob") header + token codes — devicetree
+ * spec §5.1 (header) + §5.4.1 (struct block tokens). */
#define FDT_MAGIC 0xd00dfeedu
#define FDT_BEGIN_NODE 1
#define FDT_END_NODE 2
@@ -125,6 +127,26 @@ static u64 be64(const u8 *p) { return ((u64)be32(p) << 32) | (u64)be32(p + 4); }
#define FDT_NOP 4
#define FDT_END 9
+/* Xen PVH ABI handoff (see Xen's docs/misc/pvh.pandoc). On PVH boot QEMU
+ * points EBX at a `struct hvm_start_info`; the amd64 long-mode init in
+ * arch/amd64/kernel.S preserves EBX through to kmain's `dtb_phys` arg.
+ * First word is the magic; cmdline_paddr sits at offset 0x18. microvm
+ * has no DTB, so this is the only path for `qemu -append "..."`. */
+#define PVH_HVM_START_MAGIC 0x336ec578u
+#define PVH_HVM_START_OFF_CMDLINE 0x18
+
+/* cpio "newc" (SVR4 portable) format — first 6 bytes of every header
+ * record are the magic; header is fixed-size (110 bytes) followed by
+ * the NUL-terminated name and the file data, both 4-byte padded. The
+ * 13 numeric fields are 8-char ASCII hex starting at offset 6. Spec:
+ * cpio(5) under "New ASCII Format". */
+#define CPIO_NEWC_MAGIC "070701"
+#define CPIO_NEWC_HDR_SIZE 110
+#define CPIO_NEWC_FIELD(p, n) ((p) + 6 + (n) * 8)
+#define CPIO_MODE_TYPE_MASK 0xf000 /* st_mode file-type bits */
+#define CPIO_MODE_TYPE_DIR 0x4000
+#define CPIO_MODE_TYPE_REG 0x8000
+
/* QEMU virt has 32 virtio-mmio slots (0x0a000000..0x0a004000, 0x200 each).
* Most are unpopulated and report MagicValue=0/DeviceID=0 — we capture all
* slots advertised by the DTB and the driver init filters at probe time. */
@@ -146,11 +168,9 @@ static int str_starts(const char *s, const char *prefix) {
static void parse_dtb(const void *dtb, struct dtb_info *out) {
#ifdef ARCH_STATIC_VIRTIO_MMIO_BASE
- /* amd64 (microvm) has no DTB. mem + virtio-mmio come from arch.h
- * defines, and the kernel cmdline (qemu -append "...") arrives via
- * the PVH `hvm_start_info` struct that QEMU points EBX at. The
- * Xen-defined magic is XEN_HVM_START_MAGIC_VALUE = 0x336ec578;
- * cmdline_paddr lives at offset 0x18. */
+ /* No DTB on this arch (amd64 microvm). mem + virtio-mmio come from
+ * arch.h compile-time constants; the kernel cmdline arrives via the
+ * PVH hvm_start_info struct (see PVH_HVM_START_* above). */
out->mem_start = ARCH_STATIC_MEM_START;
out->mem_size = ARCH_STATIC_MEM_SIZE;
out->virtio_mmio_n = ARCH_STATIC_VIRTIO_MMIO_COUNT;
@@ -160,8 +180,8 @@ static void parse_dtb(const void *dtb, struct dtb_info *out) {
if ((u64)dtb != 0) {
const u8 *p = dtb;
u32 magic = (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
- if (magic == 0x336ec578U) {
- const u8 *cp = p + 0x18;
+ if (magic == PVH_HVM_START_MAGIC) {
+ const u8 *cp = p + PVH_HVM_START_OFF_CMDLINE;
u64 cmdline_paddr = 0;
for (int i = 0; i < 8; i++) cmdline_paddr |= (u64)cp[i] << (i * 8);
if (cmdline_paddr) {
@@ -567,8 +587,7 @@ static void blk_init(struct dtb_info *dt) {
uart_putd((i64)i); uart_puts("\n");
hang();
}
- int is_cpio = (probe[0]=='0' && probe[1]=='7' && probe[2]=='0' &&
- probe[3]=='7' && probe[4]=='0' && probe[5]=='1');
+ int is_cpio = str_starts((const char *)probe, CPIO_NEWC_MAGIC);
if (is_cpio) {
if (g_blk_input >= 0) {
uart_puts("[seed] virtio-blk: multiple cpio disks\n");
@@ -707,20 +726,20 @@ static u64 hex_n(const char *s, int n) {
static void parse_cpio(const void *cpio, u64 total) {
const u8 *p = cpio;
const u8 *end = p + total;
- while (p + 110 <= end) {
- if (!(p[0]=='0'&&p[1]=='7'&&p[2]=='0'&&p[3]=='7'&&p[4]=='0'&&p[5]=='1')) break;
- u64 mode = hex_n((const char *)(p + 6 + 1*8), 8);
- u64 fsz = hex_n((const char *)(p + 6 + 6*8), 8);
- u64 nsz = hex_n((const char *)(p + 6 + 11*8), 8);
- const char *name = (const char *)(p + 110);
+ while (p + CPIO_NEWC_HDR_SIZE <= end) {
+ if (!str_starts((const char *)p, CPIO_NEWC_MAGIC)) break;
+ u64 mode = hex_n((const char *)CPIO_NEWC_FIELD(p, 1), 8);
+ u64 fsz = hex_n((const char *)CPIO_NEWC_FIELD(p, 6), 8);
+ u64 nsz = hex_n((const char *)CPIO_NEWC_FIELD(p, 11), 8);
+ const char *name = (const char *)(p + CPIO_NEWC_HDR_SIZE);
if (str_eq(name, "TRAILER!!!")) break;
- u64 hstride = (110 + nsz + 3) & ~3UL;
+ u64 hstride = (CPIO_NEWC_HDR_SIZE + nsz + 3) & ~3UL;
u64 fstride = (fsz + 3) & ~3UL;
const u8 *fdata = p + hstride;
- int is_dir = ((mode & 0xf000) == 0x4000);
- int is_reg = ((mode & 0xf000) == 0x8000);
+ int is_dir = ((mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_DIR);
+ int is_reg = ((mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_REG);
if (is_reg && !str_eq(name, ".")) {
int idx = new_file(name);
if (idx >= 0) {
@@ -940,6 +959,10 @@ static i64 sys_brk(u64 addr) {
}
static i64 sys_unlinkat(int dirfd, const char *path, int flags) {
+ /* dirfd is ignored: tmpfs is a flat path map, all callers pass
+ * AT_FDCWD. flags (AT_REMOVEDIR) is ignored too — there are no
+ * directories in our tmpfs, so the dir-vs-file distinction the
+ * flag selects has no observable effect. */
(void)dirfd; (void)flags;
int fidx = find_file(path);
if (fidx < 0) return -ENOENT;