// Process-lifecycle core regression for GNO: fork a leaf child that _exit(42)s, // have the parent wait() and assert the real exit status propagates. Covers two // fixed bugs at once: // 1. Kernel dispatch vector: gnoKernel.s called $E10000 (the standard Tool // Locator, toolset $03 = Misc Tools) instead of GNO's udispatch $E10008, so // EVERY K* primitive hung. Latent until this probe -- fork is the first K* // call ever exercised under GNO. // 2. Exit status: _exit routed QUIT through __gnoGsosCall, which loaded // A = callNum (0x2029) right before the trap, so GNO's StackGSOS recorded // 0x2029 as the exit code and wait() decoded WEXITSTATUS = 0x29 (41). // __gnoQuit now leaves A = status, so wait() sees 42 (0x2A). // // GNO fork is a thread-spawn: the child begins at child() on a fresh stack/DP, so // child() is a LEAF using only absolute-long stores + _exit (no DP scratch). // Bank-2 absolute markers (DBR-independent), per the gnoHeapProbe convention. // 0x025000 C0DE reached end (no hang in fork/wait) // 0x025010 C41D child was scheduled + ran // 0x025014 002A WEXITSTATUS == 42 (the status propagated) // 0x025016 0001 wait() reaped the same pid fork() returned // 0x025018 600D exit status is NOT the old 41/0x29 miscompile #include #include extern int fork(void *subr); // GNO thread-spawn: subr = (void *)&childFn extern int wait(int *status); extern __attribute__((noreturn)) void _exit(int status); #define M(a) (*(volatile uint16_t *)(a)) static void child(void) { M(0x025010UL) = 0xC41D; // child was scheduled + entered child() _exit(42); // exit code 42 -> status word 0x2A00 } int main(void) { M(0x025000UL) = 0x0000; int pid = fork((void *)child); if (pid <= 0) { M(0x025016UL) = 0xDEAD; // fork failed / returned no child M(0x025000UL) = 0xC0DE; for (volatile unsigned long j = 0; j < 300000UL; j++) { } return 0; } int st = 0; int w = wait(&st); // blocks until the child dies (race-free) M(0x025014UL) = WIFEXITED(st) ? (uint16_t)WEXITSTATUS(st) : 0xEEEE; // == 0x002A M(0x025016UL) = (w == pid) ? 0x0001 : 0xDEAD; // pid round-trip M(0x025018UL) = (WEXITSTATUS(st) == 41) ? 0xDEAD : 0x600D; // guard old bug M(0x025000UL) = 0xC0DE; // reached end for (volatile unsigned long j = 0; j < 300000UL; j++) { } return 0; }