1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# gbos
A tiny **Unix-flavored OS for the Game Boy Color** — a from-scratch cooperative
microkernel with fork/exec, a shell with pipes, a persistent filesystem, a
color terminal on the LCD, and a **real TCP/IP stack over the link cable**.
It boots, gets a DHCP lease, pings, resolves DNS, fetches web pages, and hangs
out on IRC. On a 1997 handheld (well, an emulated one).

*Real capture: cold boot → DHCP lease → `ping` → an IRC session, typed live
into the on-screen console. Regenerate it anytime with `tools/gbdemo` (below).*
## What's in the box
- **Processes, the V7 way**: `fork`/`exec`/`wait`/`exit`, zombies + reaping,
background jobs (`spin &`), `ps`, `kill` — round-robin cooperative
scheduling across banked memory with an HRAM context switch.
- **A shell** (written in C, running *on* the GB) with I/O redirection
(`>` `<` `>>`) and pipes (`|`), argument passing, and a cwd-aware prompt —
with `grep` to put on the other end of the pipe, `tee` to fork it, and
`more` to page anything longer than the 18-row screen.
- **Shell scripts**: a shell fed from a file (`sh < script`) runs it with no
prompt and no echo, and init runs **`/rc`** at boot if the cart has one —
so a Game Boy can come up with its own startup script.
- **Networking, for real**: the kernel owns SLIP over the link port, IPv4,
ICMP, UDP and TCP; userland gets BSD-ish sockets via one syscall. On top:
`dhcp` (boot-time lease), `ping`, `nslookup` (real DNS), `wget` (HTTP),
`nc` (netcat: `nc HOST PORT` interactively, or `nc -s HOST PORT < file` to
pipe a request in and print the reply), `chat`, and a colorized **IRC
client** (`irc HOST [NICK]`, `/join` and friends, SELECT for the keyboard).
- **It serves, too**: the kernel does passive opens (`listen`/`accept`, one
socket per client), so the Game Boy runs daemons. `httpd` puts the cart's
filesystem on the web — `httpd &`, then point a browser at it: files come
from battery-backed RAM, directories as clickable listings. `ircd` is a
real IRC server — `ircd &`, then `irssi -c 10.0.0.2`: NICK/USER/JOIN/
PRIVMSG/PING/NAMES/PART/QUIT, with the channel relayed between clients.
A laptop and a second Game Boy can sit in the same channel, hosted by a
Game Boy.
- **A network to plug into**: `tools/gbhub` is a virtual switch + DHCP server +
NAT gateway — spawn a fleet of Game Boys that ping *each other* and reach
the real internet; `tools/gbjoin` attaches an interactive GB to it, and
`tools/gbtype` types into any GB's shell from the host.
- **40×18 color terminal** on the LCD (4×8 font, two chars per tile, ANSI-ish
colors) + an **on-screen keyboard** on the window layer (SELECT toggles it).
- **Persistent filesystem** on battery-backed cart RAM: inodes, nested
directories, per-process cwd — survives power-off (files up to 3 KiB).
`ls -l` and `df` report sizes and free space; `poweroff` is the only safe
way to stop the machine (the battery save is written on a clean exit).
- **`/bin` in the tree**: the builtins are not files on the disk, but they
show up as one anyway — `ls /bin` enumerates the kernel's own command
table, `cd /bin` works, and `xxd -l 16 /bin/uname` dumps the program's ROM
bank. Read-only, since it is ROM.
- **A C toolchain**: userland is plain C compiled with SDCC (`sm83`); ~50
tools ship in `usr/` (`cat`, `wc`, `head`, `tail`, `grep`, `cp`, `mv`,
`tee`, `tr`, `cut`, `uniq`, `rev`, `more`, `ls`, `df`, `xxd`,
`touch`, `sleep`, `uptime`, …) — `help` lists them all on
the Game Boy itself. Adding a program is one `.c` file + a table entry.
## Quick start
```sh
git config core.hooksPath hooks # once: clang-format pre-commit hook
make # -> gbos.gb (needs RGBDS + SDCC)
# solo, in the sl0pboy emulator (~/dev/gbc):
~/dev/gbc/build/sl0pboy --sixel 3 --chrome gbos.gb
# networked — hub in one terminal, Game Boys in others:
sudo tools/gbhub --daemon # virtual net + DHCP + NAT (needs root)
tools/gbjoin # a windowed GB joins 10.0.0.0/24
tools/gbtype 'ping 10.0.0.3' # or type into it from the host
# serve the Game Boy's filesystem to your browser:
tools/gbtype 'httpd &' # then open http://10.0.0.2/
curl http://10.0.0.2/readme # files straight out of cart RAM
# or host an IRC network on it:
tools/gbtype 'ircd &' # then, from the host:
irssi -c 10.0.0.2 # /join #gbos
tools/gbtype -g 1 'irc 10.0.0.2 gb2' # a second GB joins the same channel
```
On the Game Boy: **SELECT** toggles the on-screen keyboard, d-pad + **A**
types, **START** sends the line.
```
/# uname -a
gbos sm83 (Game Boy Color)
/# ping 10.0.0.1
PING 10.0.0.1
reply from 10.0.0.1 seq=1
...
-- 4/4 received
/# irc 10.0.0.1 sl0pboy
-!- registering as sl0pboy (SELECT = keyboard)
```
## The demo GIF
The GIF above is produced by a scripted, self-syncing demo driver:
`tools/gbdemo` runs a step file (`demo/readme.gbd`), injects console text and
button events at the right moments — syncing on the *actual screen contents*
(the terminal's WRAM shadow, read over the emulator's debug socket) rather
than timers — while the emulator records every frame, then renders the GIF:
```sh
sudo tools/gbhub --daemon # network up (once)
tools/gbdemo demo/readme.gbd # inside tmux; writes demo/gbos-demo.gif
```
Edit `demo/readme.gbd` to choreograph your own (verbs: `type`, `slowtype`,
`key`, `waitfor`, `record`, `gif`, …).
## Docs
- [docs/internals.md](docs/internals.md) — the full technical breakdown:
memory model, syscall ABI, fork/exec/context-switch internals, the network
stack, the filesystem layout, C toolchain notes, war stories, roadmap.
Built and tested against the [sl0pboy](../gbc) emulator; runs on anything that
emulates a CGB + MBC5 cartridge with battery RAM. No MMU, no protection, no
regrets.
|