Kernel¶
The iPod classic runs a small real-time kernel of the RTXC family, and Chikuma reproduces it - not a
stub that pretends to be one, but the firmware's own design with the behaviour that programs on top of
it depend on. It lives in chikuma/kernel/, and its logic is covered by host tests that pass with
"kernel logic tests: all passed".
What the kernel provides¶
Everything a preemptive real-time system is expected to have, reproduced because the rest of the system leans on all of it:
- Tasks with fixed priorities and preemption - a higher-priority task that becomes runnable takes the processor from a lower one.
- Mutexes with priority inheritance - a low-priority task holding a lock that a high-priority task wants is temporarily lifted, so the high-priority task is not left waiting behind an unrelated middle one.
- Timers, and slots and events for the message-passing the UI and drivers are built on.
- A heap with boundary tags for allocation.
- A service dispatch - the single entry through which tasks ask the kernel to do things. Every one of its dispatch slots has been read and classified.
The task table is the device's own¶
The kernel is brought up with the firmware's real task table: the tasks carry the names, ids and priorities the original uses, not invented ones. The great majority were recovered directly from the image's own strings, and where two independent recovery routes both name a task, they agree - which is the check that turns a plausible name into a recovered one. The result is that when Chikuma spawns a thread, it can take that thread's number from the recovered table rather than choosing one.
Priorities are assigned the way the firmware assigns them: a thread is spawned with a priority class,
which the kernel maps to a concrete run-time priority. That mapping was recovered and then
cross-checked against tasks whose priorities had been established by an entirely separate route; every
one agreed. The details are in reports/thread_priorities.md.
The disk is behind a queue, and that shapes everything¶
The single most load-bearing fact about the kernel's arrangement is how disk work is scheduled. The filesystem does not call the disk. It posts a request to a work queue and blocks, and a dedicated pair of tasks - one that owns the work loop and one that handles the completion interrupt - does the bulk transfer and wakes the caller. The disk tasks block rather than spin, so the rest of the system keeps running while a transfer is in flight.
This is not an implementation detail that could have gone either way. It is why a stack trace taken at the moment a disk command is issued can never name the code that asked for the data: by construction, the requester is in another task, already blocked. Reproductions and probes that assume a direct call chain from filesystem to disk are looking in the wrong place. See Storage for how the layers above the queue are arranged.
Timekeeping¶
The kernel tick and the timers built on it are reproduced, and the real-time clock is read from the platform the way the firmware reads it, so time-of-day is correct on screens that show it. On the emulated machine the clock is served from the host, and can be pinned to a fixed value to reproduce a device whose backup cell has been cleared.