// Map a forked child's REAL capabilities on a fresh DP (concurrency step 2).
// The leaf-only contract forbids "i32/i64 libcalls" -- but libcalls use the
// child's OWN $E0-$FF DP scratch (write-before-read), which a fresh page
// provides, so a child that CALLS A FUNCTION doing an i32 multiply (a real
// __mulsi3 libcall) may already work without any DP-scratch setup.  This probe
// tests exactly that: a non-leaf child that JSLs a helper which does a genuine
// 32-bit multiply.  It deliberately does NOT touch &global (needs $BE) or a
// function pointer (needs $B8 / the __jsl_indir operand) -- those are tested
// separately, since they can wild-jump.  Reading a global's VALUE (gA/gB) is
// plain absolute/DBR addressing, not a 32-bit &global pointer.
//
//   0x025060  0001  child entered
//   0x025062  0001  mul32(gA,gB) == 300000  (function call + i32 libcall worked)
//   0x025064  E0DD  child reached end (no crash)
//   0x025066  5050  parent reaped the child
#include <stdint.h>

extern int  fork(void *subr);
extern int  wait(int *status);
extern __attribute__((noreturn)) void _exit(int status);

#define M(a)  (*(volatile uint16_t *)(a))
#define BAD   0xDEAD

static volatile uint32_t gA = 100000;
static volatile uint32_t gB = 3;


static uint32_t __attribute__((noinline)) mul32(uint32_t x, uint32_t y) {
    return x * y;                        // real __mulsi3 libcall (uses $E0-$FF)
}


static void child(void) {
    uint32_t r;
    M(0x025060UL) = 0x0001;              // child entered on its fresh DP
    r = mul32(gA, gB);                   // fn-call + i32 libcall
    if (r == 300000UL) {
        M(0x025062UL) = 0x0001;
    }
    M(0x025064UL) = 0xE0DD;              // reached end -> no crash
    _exit(0);
}


int main(void) {
    int pid;
    int st;

    M(0x025060UL) = BAD;
    M(0x025062UL) = BAD;
    M(0x025064UL) = BAD;
    M(0x025066UL) = BAD;

    pid = fork((void *)child);
    if (pid > 0) {
        wait(&st);
        M(0x025066UL) = 0x5050;
    }
    for (volatile unsigned long j = 0; j < 300000UL; j++) {
    }
    return 0;
}
