// 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 <stdint.h>
#include <sys/wait.h>

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;
}
