# 26 — bare-metal syscalls the virt port's `micro_syscall` returned -1 for every op. the gate itself was already there (`SYSGATE`, the same numbers the hosted core uses), and `port_stub.c` still returns -1, so a board with no devices keeps building. `port_linux.c` and `core.c`'s `hostcall` grew the three new numbers too: 7 exits the process, 8 is a counter, 9 reports `MW` and the heap. the genome did not change. the test programs pass the numbers as literals, so `src/rt.zc` stays as it was. ## console, and eof that waits `examples/echo.zc` is `while (!eof()) putc(getc())`. on the host, `micro_eof` blocks in `getchar` until the next byte or a real end. the old UART port returned immediately, and an empty FIFO counted as "not the end", so a `0x04` that had not arrived yet was read by `getc` as a failure and then printed. it also could not see an end that was sitting behind more than 16 bytes, which is the 16550's FIFO. `BARE_INPUT=1` now waits in both `micro_getc` and `micro_eof` until a byte is in the register. `0x04` is the end and is not returned. a pause with an empty FIFO is just a wait, so the length of the stream does not matter. `run` mode is still `BARE_INPUT=0`: eof is true, getc is -1, and a program that never reads does not sit on the UART. the compiler's backtick is unchanged. the opcode that reads a byte then probes eof, and that probe used to deadlock if it waited, because the probe runs before the compiler has noticed the backtick. `compile` therefore writes the source, a backtick, and a `0x04`. the probe after the backtick finds the `0x04` and returns. hello, fact and wide compiled over the UART still print what they printed before. `io` mode is a run-only image with the UART open. the script appends `0x04` to stdin. both boards, fed `abcdefghijklmnopqrstuvwxyz0123456789` (36 bytes, past the FIFO), printed that string and exited 0. the hosted interpreter, given the same letters after the backtick, printed the same string. ## the rest of the gate time is the hardware counter. RISC-V is `rdtime` (the virt machine's `mtime`). AArch64 is `cntvct_el0`. neither is unix seconds, so `tests/sys.zc` is still a hosted test. `tests/bareio.zc` reads it, spins, reads it again, and prints `tick` when the second value is at least the first and neither is negative. both boards did. exit is a status, not only success or failure. RISC-V writes the SiFive test device at `0x100000`: `0x5555` exits 0, and `(status << 16) | 0x3333` exits with that status. the high half is 16 bits. AArch64 is semihosting `SYS_EXIT`: `hlt #0xf000` with `x0 = 0x18` and `x1` pointing at `{0x20026, status}` (`ADP_Stopped_ApplicationExit`). the first try hung because the stack pointer was unset in a throwaway ELF, and because PSCI `SYSTEM_OFF` cannot carry a status. the boot path already has a stack. QEMU is started with `-semihosting-config enable=on,target=native`. `tests/bareexit.zc` prints `bye` and calls exit 3. both boards exited 3 and did not print `still`. a guest that returns from `micro_run` with an error now exits 1 on AArch64 too. open, close, read and write are four RAM files, 128 bytes each, names up to 31 characters. they are not the host filesystem. `tests/bareio.zc` writes `zy` to `note` and reads it back: `2 zy`. getenv answers `BOARD` with `riscv` or `aarch64` and -1 for anything else. random is an xorshift seeded from the counter, and it is never -1. memory op 0 is `MW`, which on the run-only image is 32768. the line from both boards was `tick 2 zy rand board 32768`. `port_stub.c` and a freestanding compile of it are unchanged in behaviour. the linux port still serves real files for ops 1 to 4. `test.sh` runs the echo, the bareio line, the exit text and the exit code on each board that is present. with both virt boards, that is eight checks on top of the 295 from stage 25. the full script passed 303, and failed 0. the fixpoint is still 91158 words.