diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index 733aa0a4..b8a46f22 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + diff --git a/kernel/src/kernel_main.c b/kernel/src/kernel_main.c index c8d713d1..5e3b9698 100644 --- a/kernel/src/kernel_main.c +++ b/kernel/src/kernel_main.c @@ -490,11 +490,12 @@ static void sk_v4_block_chain(void) } console_println("PCI: init..."); pci_init(sk_v4_boot_info->acpi_table); - if (virtio_blk_find_artemis(&artemis_dev) == 0) { - console_println("Artemis: virtio-blk attached"); - blk_subsys_attach_device(&artemis_dev); - } else { + if (virtio_blk_find_artemis(&artemis_dev) != 0) { console_println("Artemis: no virtio-blk disk"); + } else if (blk_subsys_attach_device(&artemis_dev) == BLK_OK) { + console_println("Artemis: virtio-blk attached"); + } else { + console_println("Artemis: virtio-blk found, and could not be attached"); } } #endif diff --git a/logs/20261007-135741/amd64/qemu-amd64-20261007-135741.log b/logs/20261007-135741/amd64/qemu-amd64-20261007-135741.log new file mode 100644 index 00000000..f1a49dcc --- /dev/null +++ b/logs/20261007-135741/amd64/qemu-amd64-20261007-135741.log @@ -0,0 +1,160 @@ +[=3hBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +RAW SERIAL UP +[CKPT 002] Serial (COM1) initialized +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +EBS... +EBS OK +Calling kernel_main (monolithic)... + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: amd64 +Build: Oct 7 2026 13:57:12 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 131 +Total memory: 1023 MB +Usable memory: 966 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 248743 + Free pages : 247220 + Used pages : 1523 + Total MB : 971 + Free MB : 965 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +APIC: IA32_APIC_BASE MSR=0x00000000fee00900 +APIC: stale-ISR drain: 0 EOI(s) issued +APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear) +APIC: init done + +I/O APIC: init... +I/O APIC: base=0xfec00000, gsi_base=0, overrides=5 + override: source=00 gsi=2 flags=0x0000 + override: source=05 gsi=5 flags=0x000d + override: source=09 gsi=9 flags=0x000d + override: source=0a gsi=10 flags=0x000d + override: source=0b gsi=11 flags=0x000d +i8042: keyboard ACKed enable-scanning +i8042: IRQ1 enabled in controller config byte +I/O APIC: keyboard IRQ1 routed (masked) + +Timer: init... +Timer: init start +Timer: PM_TMR_BLK discovered from FADT at port 1544 +Timer: VM mode detected (hypervisor present). +Timer: HPET calibration disabled (VM-exit MMIO would poison timing). +Timer: WARNING: invariant TSC not present under hypervisor. +Timer: continuing in RELATIVE mode (no determinism guarantees). +Timer: RDTSCP not present; using RDTSC (less serialized). +Timer: CPUID frequency unavailable; trying PM Timer... +Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2148522542 Hz +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 24641536 + Heap end addr: 561512448 + +Heartbeat: init... +APIC Timer: calibrating... +APIC Timer: apic_hz=1032714420, tick_hz=100, initial_count=10327144 +APIC Timer: configured (masked, ready to start) +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0xbb8f7aba92a2f5dc capsule_hash=0xbb8f7aba92a2f5dc words=308 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x145ecc5563d10b54 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=314 dict_hash=0x5f0a949a6fc8ef2b +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +PCI: ECAM mapped (amd64) +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 80492958] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b +Artemis: virtio-blk attached +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> T{ +UNKNOWN WORD: 'T{' + ERROR +ok> RS1 +UNKNOWN WORD: 'RS1' + ERROR +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> 1 BLOCK C@ . 2047 BLOCK C@ . +0 0 ok +ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . +65 ok +ok> 3072 BLOCK C@ . +0 ok +ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS +Storage refused + ERROR +ok> 9999999 BLOCK +Block out of range + ERROR +ok> 5 7 PORT! +No one on that port + ERROR +ok> 1 2 + . +3 ok +ok> HERE . +8300 ok +ok> BYE +BYE: cold restart diff --git a/logs/20261007-140004/aarch64/qemu-aarch64-20261007-140004.log b/logs/20261007-140004/aarch64/qemu-aarch64-20261007-140004.log new file mode 100644 index 00000000..b387a9e0 --- /dev/null +++ b/logs/20261007-140004/aarch64/qemu-aarch64-20261007-140004.log @@ -0,0 +1,133 @@ +UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026) +[=3hBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found +BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found +BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0) +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Collecting boot information... +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: aarch64 +Build: Oct 7 2026 13:59:36 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 108 +Total memory: 4093 MB +Usable memory: 4054 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 1039356 + Free pages : 1037945 + Used pages : 1411 + Total MB : 4059 + Free MB : 4054 + Used MB : 5 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +AArch64: running at EL1 +IDT installed. + +APIC: init... +PSCI: no DTB -- using HVC (QEMU virt-machine default) +GICv2: no DTB GIC node -- using QEMU virt-machine defaults +GICv2: distributor+CPU interface enabled, PPI 30 +APIC: init done + +Timer: init... +Timer: AArch64 generic timer initialised. +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 2147483608 + Free bytes: 2147483608 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 1207959552 + Heap end addr: 3355443200 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0xbb8f7aba92a2f5dc capsule_hash=0xbb8f7aba92a2f5dc words=308 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x145ecc5563d10b54 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=314 dict_hash=0x5f0a949a6fc8ef2b +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 1398175] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b +Artemis: virtio-blk attached +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> T{ +UNKNOWN WORD: 'T{' + ERROR +ok> RS1 +UNKNOWN WORD: 'RS1' + ERROR +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> 1 BLOCK C@ . 2047 BLOCK C@ . +0 0 ok +ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . +65 ok +ok> 3072 BLOCK C@ . +0 ok +ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS +Storage refused + ERROR +ok> 9999999 BLOCK +Block out of range + ERROR +ok> 5 7 PORT! +No one on that port + ERROR +ok> 1 2 + . +3 ok +ok> HERE . +8300 ok +ok> BYE +BYE: cold restart diff --git a/logs/20261007-140329/riscv64/qemu-riscv64-20261007-140329.log b/logs/20261007-140329/riscv64/qemu-riscv64-20261007-140329.log new file mode 100644 index 00000000..01ca33c8 --- /dev/null +++ b/logs/20261007-140329/riscv64/qemu-riscv64-20261007-140329.log @@ -0,0 +1,203 @@ + +OpenSBI v1.8 + ____ _____ ____ _____ + / __ \ / ____| _ \_ _| + | | | |_ __ ___ _ __ | (___ | |_) || | + | | | | '_ \ / _ \ '_ \ \___ \| _ < | | + | |__| | |_) | __/ | | |____) | |_) || |_ + \____/| .__/ \___|_| |_|_____/|____/_____| + | | + |_| + +Platform Name : riscv-virtio,qemu +Platform Features : medeleg +Platform HART Count : 1 +Platform HART Protection : pmp +Platform IPI Device : aclint-mswi +Platform Timer Device : aclint-mtimer @ 10000000Hz +Platform Console Device : uart8250 +Platform HSM Device : --- +Platform PMU Device : --- +Platform Reboot Device : syscon-reboot +Platform Shutdown Device : syscon-poweroff +Platform Suspend Device : --- +Platform CPPC Device : --- +Firmware Base : 0x80000000 +Firmware Size : 321 KB +Firmware RW Offset : 0x40000 +Firmware RW Size : 65 KB +Firmware Heap Offset : 0x47000 +Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free) +Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free) +Runtime SBI Version : 3.0 +Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr +Experimental SBI Extensions : none + +Domain0 Name : root +Domain0 Boot HART : 0 +Domain0 HARTs : 0* +Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: () +Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: () +Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W) +Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W) +Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: () +Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W) +Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W) +Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X) +Domain0 Next Address : 0x0000000020000000 +Domain0 Next Arg1 : 0x00000000bfe00000 +Domain0 Next Mode : S-mode +Domain0 SysReset : yes +Domain0 SysSuspend : yes + +Boot HART ID : 0 +Boot HART Domain : root +Boot HART Priv Version : v1.12 +Boot HART Base ISA : rv64imafdch +Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu +Boot HART PMP Count : 16 +Boot HART PMP Granularity : 2 bits +Boot HART PMP Address Bits : 54 +Boot HART MHPM Info : 16 (0x0007fff8) +Boot HART Debug Triggers : 2 triggers +Boot HART MIDELEG : 0x0000000000001666 +Boot HART MEDELEG : 0x0000000000f4b509 +[=3hRISC-V EDK2 firmware version 2025.11-3ubuntu7.3 +Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850 +BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr +om PciRoot(0x0)/Pci(0x1,0x0): Not Found +[=3hStarKernel UEFI Loader +Loading kernel from ESP... +[CKPT 001] Entered efi_main - ConOut live +Monolithic build - kernel linked directly +Collecting boot information... +CmdLine: parsed OK +[CKPT 004] Command line parsed +[CKPT 005] Kernel stack allocation decided +[CKPT 006] Boot info collected (ACPI table located) +GOP: linear framebuffer found +[CKPT 007] GOP: linear framebuffer found +[CKPT 008] About to enter ExitBootServices retry loop +Calling kernel_main (monolithic)... +riscv64 item 4.3.5a: satp state at kernel entry (before switch) + satp.MODE = 0x000000000000000a + satp.PPN = 0x00000000000bf868 + __kernel_start = 0x00000000bdca0a04 +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: riscv64 +Build: Oct 7 2026 14:02:48 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 100 +Total memory: 1020 MB +Usable memory: 975 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250271 + Free pages : 249619 + Used pages : 652 + Total MB : 977 + Free MB : 975 + Used MB : 2 + +VMM initialized (mapped RAM, CR3 switched) +VMM initialized (mapped RAM, CR3 switched) +VMM self-test: mapped OK at 0xffff800000000000 +VMM self-test complete. + +IDT installed. + +APIC: init... +PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000) +PLIC: init (S-mode context 1, threshold=0) +APIC: init done + +Timer: init... +Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree) +Timer: init done + +Kernel heap initialized. +Heap statistics: + Total bytes: 536870872 + Free bytes: 536870872 + Used bytes: 0 + Peak bytes: 0 + Heap base addr: 2214588416 + Heap end addr: 2751459328 + +Heartbeat: init... +Heartbeat: init done +Kernel initialization complete. +Boot successful! + +StarForth v4: one host node, the F18-derived engine +V4: capsule v4:nucleus-64.f18 signature: missing (unsigned) +PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0xbb8f7aba92a2f5dc capsule_hash=0xbb8f7aba92a2f5dc words=308 +V4: capsule v4:forth79.4th signature: missing (unsigned) +PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x145ecc5563d10b54 +PARITY:V4_POST tests=538 pass=538 fail=0 +PARITY:V4_SYSTEM word_count=314 dict_hash=0x5f0a949a6fc8ef2b +PARITY:OK +POST: PASSED +[HADES][INFO ] [KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks) +PCI: init... +virtio-blk: found device +[HADES][INFO ] [KRELTSC: 26484591] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b +Artemis: virtio-blk attached +ok> : SQ DUP * ; + ok +ok> 7 SQ . 3 4 U* . . +49 0 12 ok +ok> T{ +UNKNOWN WORD: 'T{' + ERROR +ok> RS1 +UNKNOWN WORD: 'RS1' + ERROR +ok> COLD +FORTH-79 Cold Start +System initialized. + ok +ok> 3 4 U* . . +0 12 ok +ok> FORGET U* +Protected word + ERROR +ok> 9 KERNEL-WORD ASK9 ASK9 +Argument out of range + ERROR +ok> 1 BLOCK C@ . 2047 BLOCK C@ . +0 0 ok +ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . +65 ok +ok> 3072 BLOCK C@ . +0 ok +ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS +Storage refused + ERROR +ok> 9999999 BLOCK +Block out of range + ERROR +ok> 5 7 PORT! +No one on that port + ERROR +ok> 1 2 + . +3 ok +ok> HERE . +8300 ok +ok> BYE +BYE: cold restart diff --git a/v4/include/v4/blocks.h b/v4/include/v4/blocks.h index 499fa6c9..5a6feec8 100644 --- a/v4/include/v4/blocks.h +++ b/v4/include/v4/blocks.h @@ -34,7 +34,8 @@ * by SAVE-BUFFERS or when its slot is wanted for another block. (v3's * UPDATE copies the slot to the kernel at once; the standard is followed.) * A slot whose block is not marked is taken before one whose block is. A - * block that storage would not take is let go of: its slot is empty. + * block that storage would not take is let go of: its slot is empty, and + * the kernel keeps the block as it was before, not what was refused. * * When the kernel's chain of devices changes, everything in the slots is * let go and nothing of it is written, as v3 does (blk_vm_check_epoch). diff --git a/v4/include/v4/post.h b/v4/include/v4/post.h index fe91ff5b..f619d80a 100644 --- a/v4/include/v4/post.h +++ b/v4/include/v4/post.h @@ -36,7 +36,10 @@ extern const unsigned v4_post_case_count; * case's lines one at a time, keeping what the node prints and showing none * of it; and judges. A case passes when it ended in an error exactly if * one was expected and, if none was, its stack and its printing are what - * the table has. It has ended in an error if any of its lines did. What + * the table has. It has ended in an error if any of its lines did. A + * case one of whose lines ends with QUIT fails: it went back to the + * terminal and did not complete. So does one whose starting state could + * not be set, and what the node said of that is shown. What * the cases define is still in the node's dictionary when the runner * returns: whoever runs POST puts the dictionary back afterwards, as v3 * does after each of its suites (v3/src/test_runner/test_common.c, diff --git a/v4/system/blocks.c b/v4/system/blocks.c index dcb74661..e79045c0 100644 --- a/v4/system/blocks.c +++ b/v4/system/blocks.c @@ -30,12 +30,14 @@ static v4_cell slot_addr(const v4_blocks *w, unsigned s) * no longer marked. */ static int write_slot(v4_blocks *w, v4_node *n, unsigned s) { + static uint8_t was[V4_BLOCK_CELLS * 4u]; /* the block as the kernel had it, in case it is refused */ uint8_t *b = blk_get_buffer(w->block[s], 1); v4_cell at = slot_addr(w, s); unsigned i; w->changed[s] = 0; if (!b) return V4_BLOCK_REFUSED; + for (i = 0; i < V4_BLOCK_CELLS * 4u; i++) was[i] = b[i]; for (i = 0; i < V4_BLOCK_CELLS; i++) { v4_ucell c = (v4_ucell)n->mem[at + (v4_cell)i]; b[4u * i] = (uint8_t)(c & 0xFFu); @@ -43,7 +45,19 @@ static int write_slot(v4_blocks *w, v4_node *n, unsigned s) b[4u * i + 2u] = (uint8_t)((c >> 16) & 0xFFu); b[4u * i + 3u] = (uint8_t)((c >> 24) & 0xFFu); } - return (blk_update(w->block[s]) == BLK_OK && blk_flush(w->block[s]) == BLK_OK) ? V4_BLOCK_OK : V4_BLOCK_REFUSED; + if (blk_update(w->block[s]) == BLK_OK && blk_flush(w->block[s]) == BLK_OK) return V4_BLOCK_OK; + + /* Storage would not have it. The node is told so, and the kernel does + * not keep what was refused: its own copy is put back as it was, so + * that the block reads as before and what was refused is not written + * later. The buffer is asked for again, since the failed write may + * have moved it. */ + b = blk_get_buffer(w->block[s], 1); + if (b) { + for (i = 0; i < V4_BLOCK_CELLS * 4u; i++) b[i] = was[i]; + (void)blk_update(w->block[s]); + } + return V4_BLOCK_REFUSED; } /* A slot to put a block in: an empty one, or one whose block is not marked, diff --git a/v4/system/post.c b/v4/system/post.c index 719128a2..f1c2c72d 100644 --- a/v4/system/post.c +++ b/v4/system/post.c @@ -44,13 +44,16 @@ int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count for (i = 0; i < count; i++) { const v4_post_case *c = &cases[i]; unsigned kept = 0, total = 0, len = 0, depth; - int errored = 0, came_back = 1, lost = 0, ok, how; + int errored = 0, came_back = 1, lost = 0, no_state = 0, quit = 0, ok, how; /* every case starts from the same state */ v4_dstack_reset(&h->n->ds); - how = h->line(h->self, state_line, (unsigned)sizeof state_line - 1u, out, 0u, &len); + how = h->line(h->self, state_line, (unsigned)sizeof state_line - 1u, out, V4_POST_OUT, &len); if (how < 0) lost = 1; - if (how != V4_TEXT_COMPLETED) came_back = 0; + if (how != V4_TEXT_COMPLETED) { /* what the node said of it is what is shown */ + came_back = 0; no_state = 1; + total = len; kept = len < V4_POST_OUT ? len : V4_POST_OUT; + } v4_dstack_reset(&h->n->ds); for (k = 0; came_back && k < c->line_count; k++) { @@ -58,6 +61,7 @@ int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count how = h->line(h->self, c->lines[k], length(c->lines[k]), out + kept, V4_POST_OUT - kept, &len); if (how < 0) { came_back = 0; lost = 1; break; } if (how == V4_TEXT_ERROR) errored = 1; + if (how == V4_TEXT_QUIT) quit = 1; /* it went back to the terminal: it did not complete */ total += len; kept = total < V4_POST_OUT ? total : V4_POST_OUT; } @@ -70,7 +74,7 @@ int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count } v4_dstack_reset(&h->n->ds); - if (!came_back) { + if (!came_back || quit) { ok = 0; } else if (c->expect == V4_POST_ERROR) { ok = errored; @@ -92,6 +96,8 @@ int v4_post_run(const v4_post_host *h, const v4_post_case *cases, unsigned count if (ok) { tally->pass++; continue; } tally->fail++; say(h, "POST FAIL: "); say(h, c->name); + if (no_state) say(h, " could not be put in its starting state:"); + if (quit) say(h, " ended with QUIT:"); say(h, " out<"); h->say(h->self, out, kept < SHOWN_OUT ? kept : SHOWN_OUT); say(h, "> stack<"); for (k = depth < SHOWN_STACK ? depth : SHOWN_STACK; k-- > 0; ) { say_number(h, (long long)left[k]); say(h, " "); } diff --git a/v4/tests/test_host_blocks.c b/v4/tests/test_host_blocks.c index df17dcf1..2f6f8932 100644 --- a/v4/tests/test_host_blocks.c +++ b/v4/tests/test_host_blocks.c @@ -52,6 +52,25 @@ static v4_cell tell(v4_cell request) static int in_window(v4_cell a) { return a >= WINDOW && a < WINDOW + (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS) && (a - WINDOW) % (v4_cell)V4_BLOCK_CELLS == 0; } static unsigned char *chain_block(unsigned num) { return num < 2048u ? ram + ((size_t)num + BLK_FORTH_SYS_RESERVED) * 1024u : dev + (size_t)(num - 2048u) * 1024u; } +/* A device whose writes can be made to fail: 2048 blocks of RAM behind v3's + * device interface (v3/include/blkio.h). */ +#define FAILING_BLOCKS 2048u +static unsigned char failing_bytes[FAILING_BLOCKS * 1024u]; +static int failing; +static int f_open(struct blkio_dev *d, const blkio_params_t *p) { (void)d; (void)p; return BLKIO_OK; } +static int f_close(struct blkio_dev *d) { (void)d; return BLKIO_OK; } +static int f_read(struct blkio_dev *d, uint32_t b, void *dst) { (void)d; memcpy(dst, failing_bytes + (size_t)b * 1024u, 1024); return BLKIO_OK; } +static int f_write(struct blkio_dev *d, uint32_t b, const void *src) +{ + (void)d; + if (failing) return BLKIO_EIO; + memcpy(failing_bytes + (size_t)b * 1024u, src, 1024); + return BLKIO_OK; +} +static int f_flush(struct blkio_dev *d) { (void)d; return failing ? BLKIO_EIO : BLKIO_OK; } +static int f_info(struct blkio_dev *d, blkio_info_t *out) { (void)d; memset(out, 0, sizeof *out); return BLKIO_OK; } +static const blkio_vtable_t failing_vt = { f_open, f_close, f_read, f_write, f_flush, f_info }; + int main(void) { unsigned i; @@ -165,6 +184,30 @@ int main(void) CHECK(ask(V4_REQ_BLOCK, 2070) == V4_BLOCK_OK && (n.mem[got_addr] & 0xFF) == 'N', "and the block is read again"); } + /* ---- a write that fails on the device leaves the block as it was ---- */ + { + static blkio_dev_t fdev; + blkio_params_t params; + uint32_t first = 0, n_blocks = 0; + params.forth_block_size = 0; params.total_blocks = FAILING_BLOCKS; params.opaque = 0; + CHECK(blkio_open(&fdev, &failing_vt, ¶ms) == BLKIO_OK && blk_subsys_attach_device(&fdev) == BLK_OK + && blk_get_device_range(&fdev, &first, &n_blocks) == BLK_OK && n_blocks > 8 && blk_subsys_confirm_format(first) == BLK_OK, + "a disk joins the chain and is formatted: %u blocks from %u", n_blocks, first); + CHECK(ask(V4_REQ_BLOCK, (v4_cell)first + 3) == V4_BLOCK_OK, "one of its blocks is asked for"); + for (i = 0; i < V4_BLOCK_CELLS; i++) n.mem[got_addr + (v4_cell)i] = (v4_cell)0x4F4F4F4F; + CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK && tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_OK, "and written: all O"); + CHECK(ask(V4_REQ_BLOCK, (v4_cell)first + 3) == V4_BLOCK_OK, "it is asked for again"); + for (i = 0; i < V4_BLOCK_CELLS; i++) n.mem[got_addr + (v4_cell)i] = (v4_cell)0x4E4E4E4E; + failing = 1; + CHECK(tell(V4_REQ_UPDATE) == V4_BLOCK_OK && tell(V4_REQ_SAVE_BUFFERS) == V4_BLOCK_REFUSED, "with the device failing, a write of all N is refused"); + failing = 0; + (void)tell(V4_REQ_EMPTY_BUFFERS); + CHECK(ask(V4_REQ_BLOCK, (v4_cell)first + 3) == V4_BLOCK_OK && n.mem[got_addr] == (v4_cell)0x4F4F4F4F && n.mem[got_addr + 255] == (v4_cell)0x4F4F4F4F, + "and the block is what it was before: the kernel does not keep what the device refused: %lx", (unsigned long)n.mem[got_addr]); + CHECK(blk_flush(0) == BLK_OK && ask(V4_REQ_BLOCK, (v4_cell)first + 3) == V4_BLOCK_OK && n.mem[got_addr] == (v4_cell)0x4F4F4F4F, + "nor does it write it later, when the device works again"); + } + /* ---- what is not a block request ---- */ v4_dstack_reset(&n.ds); v4_dstack_push(&n.ds, 11); v4_dstack_push(&n.ds, 22); diff --git a/v4/tests/test_host_quit.c b/v4/tests/test_host_quit.c index ffe511ad..55d480e9 100644 --- a/v4/tests/test_host_quit.c +++ b/v4/tests/test_host_quit.c @@ -1250,9 +1250,17 @@ int main(void) CHECK(is(say("1 2 3 HEX\n"), " ok\nok> "), "the node is left in HEX with three values on its stack"); CHECK(post_one("state", "10 .", 0, V4_POST_STACK, 0, 0, "10 ") == 1, "a case still starts in decimal with nothing on the stack"); post_state_fails = 1; - CHECK(post_one("state.bad", "1 2 +", 0, V4_POST_STACK, three, 1, "") == 0 && strstr(post_said, "POST FAIL: state.bad ") != NULL, "if the state cannot be set the case fails, by name"); + CHECK(post_one("state.bad", "1 2 +", 0, V4_POST_STACK, three, 1, "") == 0 && strstr(post_said, "POST FAIL: state.bad ") != NULL + && strstr(post_said, "could not be put in its starting state") != NULL && strstr(post_said, "NOSUCHWORD-FOR-STATE") != NULL, + "if the state cannot be set the case fails, by name, and says that and what the node said: \"%s\"", post_said); post_state_fails = 0; + /* a case that ends with QUIT is not a case that completed */ + CHECK(post_one("quit.plain", "QUIT", 0, V4_POST_STACK, 0, 0, "\n") == 0 && strstr(post_said, "POST FAIL: quit.plain ") != NULL, + "a case that ends with QUIT fails, though it left and printed what the table has: \"%s\"", post_said); + CHECK(post_one("quit.err", "QUIT", 0, V4_POST_ERROR, 0, 0, "") == 0, "and it has not ended in an error either"); + CHECK(post_one("after.quit", "1 2 +", 0, V4_POST_STACK, three, 1, "") == 1, "the case after it is judged as usual"); + /* a case that prints more than is kept */ CHECK(is(say(": MANY 2000 0 DO 65 EMIT LOOP ;\n"), " ok\nok> "), "a word that prints 2,000 characters"); memset(big, 'A', 2000); big[2000] = 0;