M6: FAT read/write filesystem server, mounted into the VFS

Add a FAT12/16/32 filesystem the VFS mounts at /mnt/usb, reading and writing a
USB stick through the block device. Verified end to end under QEMU: the fat
server mounts the volume, the VFS routes /mnt/usb to it, and a client lists the
root and reads a file (the ELF magic of /mnt/usb/system/kernel).

- engine.zig: the FAT engine over a BlockDevice interface — mount (a bare FAT or,
  as QEMU's VVFAT and most real sticks present it, an MBR-partitioned disk), FAT
  chain walk (12/16/32), cluster allocation, directory traversal with long-name
  read, and file read / write / create. Host-tested against a RAM-backed FAT16
  image (create, cluster-spanning write, mid-file overwrite, read-back, list).
- on-disk.zig: the align(1) boot-sector / directory / long-name / FSInfo structs
  and the cluster-count FAT-type detection.
- fat.zig: the server — wraps the .block device (a DMA bounce buffer) in a
  BlockDevice, mounts the FAT, serves the vfs-protocol as a backend, and mounts
  itself into the VFS at /mnt/usb. Spawned by init as a boot service.
- runtime.block: the block-device client (geometry / read / write by physical
  address, so whole sectors never cross IPC).
- Raise the kernel service-name registry (maximum_services) 8 -> 16: it is
  indexed directly by ServiceId, and fat = 8 was being rejected, so the fat
  server exited before registering.
- VFS: an absolute path with no matching mount is now not-found rather than
  silently created in the flat ramfs — so /mnt/usb fails cleanly until mounted.

Tests: fat-mount (the full stack: block -> FAT -> VFS mount -> list + file read)
passes; host units cover the engine and on-disk structs; the vfs, shutdown, and
USB regression suite stays green (10/10).
This commit is contained in:
Daniel Samson
2026-07-13 15:05:53 +01:00
parent 35e8921de8
commit a64a01a6a9
13 changed files with 1318 additions and 2 deletions
+12
View File
@@ -310,6 +310,18 @@ CASES = [
"-device", "usb-storage,drive=stick,bus=xhci.0"],
"expect": r"usb-storage: ready[\s\S]*usb-storage: block 0 signature 0x55aa",
"fail": r"DANOS-TEST-RESULT: FAIL"},
# FAT mount end to end: attach a usb-storage device (a FAT volume via VVFAT),
# boot the full tree, and let the fat server mount it into the VFS at /mnt/usb.
# A fat-test client then lists and reads through the mount — proof of the whole
# stack: block device -> FAT parse -> VFS routing -> file read.
{"name": "fat-mount",
"smp": 4,
"timeout": 150,
"qemu_extra": ["-device", "qemu-xhci,id=xhci",
"-drive", "if=none,id=stick,format=raw,file=fat:rw:" + os.path.join(REPO, "zig-out"),
"-device", "usb-storage,drive=stick,bus=xhci.0"],
"expect": r"fat: mounted /mnt/usb[\s\S]*fat-test: ok",
"fail": r"DANOS-TEST-RESULT: FAIL"},
# M20.1: the ring-3 AML parse (the acpi service maps the blobs and parses
# them) finds exactly the Device count the kernel's own parse produced.
{"name": "acpi-parse",