Revolution OS
Revolution OS is a part of the SDK that is always included. It does not handle security; IOS is responsible for that.
Contents
OSGetConsoleType
OSInit
calls a function called OSGetConsoleType
that logs platform information. The name is misleading, as it does not actually return any platform info.
Console types include:
- Retail
- NDEV 2.1
- NDEV 2.0
- NDEV 1.2
- NDEV 1.1
- NDEV 1.0
- Revolution Emulator
Information about the emulation environment is also printed if the platform is Revolution Emulator.
OSDBIntegrator
There is a string saying Installing OSDBIntegrator
. OSDBIntegrator seems to be a debug stub installed at 0x80000060 that branches to the address stored at 0x80000048. It is not known how this code is reached, as it is not jumped to by any retail code.
The code itself seems to be printing DBExceptionDestination
, printing the current OSContext
, and hanging the Broadway.
Logging
There appear to be different functions to log debug, info, and error messages; the logging level is controlled by the version of the SDK used, not a global variable. On retail SDKs, info and error are logged, but debug is a dummy function.
It is not known where the logs go.
Exceptions
With the exception of a system call, all exceptions have the same handler, which loads the appropriate exception-specific handler from the array at 0x80003000, or the default handler if the is no specific handler or the exception is not recoverable. Exception types are given IDs by Revolution OS; these numbers are used when setting an exception handler.
Type | ID | Handler location |
---|---|---|
System Reset | 0 | 80000100 |
Machine Check | 1 | 80000200 |
DSI | 2 | 80000300 |
ISI | 3 | 80000400 |
External (IRQ) | 4 | 80000500 |
Alignment | 5 | 80000600 |
Program | 6 | 80000700 |
FP unavailable | 7 | 80000800 |
Decrementer | 8 | 80000900 |
System call | 9 | 80000C00 |
Trace | 10 | 80000D00 |
Performance Monitor | 11 | 80000F00 |
IABR | 12 | 80001300 |
Reserved | 13 | 80001400 |
Thermal | 14 | 80001700 |
IRQs
IRQs are processed by handlers in the __OSInterrupt
table; the bit index of the each source is the same as the index in the table; integers built from these bits are used for functions that mask interrupts.
Index | Source |
---|---|
0 | MEM0 |
1 | MEM1 |
2 | MEM2 |
3 | MEM3 |
4 | All MI |
5 | DSP ADINT |
6 | DSP ARINT |
7 | DSP DSPINT |
8 | AI |
9 | EXI EXTINT low (channel 0) |
10 | EXI TCINT (channel 0) |
11 | EXI EXTINT high (channel 0) |
12 | EXI EXTINT low (channel 1) |
13 | EXI TCINT (channel 1) |
14 | EXI EXTINT high (channel 1) |
15 | EXI EXTINT low (channel 2) |
16 | EXI TCINT (channel 2) |
26 | HSP |
25 | DEBUG |
20 | PE FINISH |
19 | PE TOKEN |
24 | VI |
21 | Serial |
22 | DVD |
23 | Reset switch |
18 | CP FIFO |
27 | GP Runtime Error |
Context saving
When a non-syscall exception occurs, the current state is stored in a struct called OSContext
; the struct is 0x2c8 bytes long.
struct OSContext { u32 gprs[0x20]; // r0-r31 u32 cr; // 0x80 u32 lr; // 0x84 u32 ctr; // 0x88 u32 xer; // 0x8c u64 fprs[0x20]; // f0-f31 u32 unknown; // 0x190 u32 fpscr; // 0x194 u32 pc; // 0x198 u32 msr; // 0x19c u16 unknown2; // 0x1a0; possibly padding u16 state; // 0x1a2; last bit means OSSaveContext was called, second last bit means the GPRs were saved by the exception handler u32 unknown3; // 0x1a4 u32 gqrs[7]; // 0x1a8 u32 unknown4; // 0x1c4 u64 pairedSingles[0x20]; // starting at 0x1c8 }
Most OSContext
instances belong to threads, and are at the beginning of the OSThread struct. However, there are also some standalone OSContext
instances, such as the one used while waiting for an available thread.
Threads
Threads are stored in the OSThread
struct.
struct OSThread { struct OSContext ctx; u16 state; // 0x2c8; 0 = stopped, 1 = inactive, 2 = active, 4 = sleeping, 8 = returned result? u16 detached; // 0x2ca; zero = false, nonzero = true u32 suspend; // seems to be a balancing counter. 0 = active, 1 = suspended u32 priority; // 0x2d0; can range from 0-31 u32 basePriority; // 0x2d4 u32 returnValue; // 0x2d8 struct OSThreadQueue *queue; // 0x2dc struct OSThreadLink linkQueue; // 0x2e0 struct OSThreadQueue queueJoin; // 0x2e8 struct OSMutexQueue queueMutex; // 0x2f0 struct OSThreadLink linkActive; // 0x2fc void *stackStart; // 0x304 void *stackEnd; // 0x308 u32 unknown; // 0x30c u32 threadSpecifics[2]; // 0x310 } struct OSThreadQueue { struct OSThread *head; struct OSThread *tail; } struct OSThreadLink { struct OSThread *next; struct OSThread *prev; } struct OSMutex { struct OSThreadQueue waitingQueue; struct OSThread *holder; u32 timesLocked; // used if a mutex is locked multiple times by the same thread struct OSMutex *next; struct OSMutex *prev; } struct OSMutexQueue { struct OSMutex *waiting; // used for deadlock detection struct OSMutex *head; struct OSMutex *tail; } struct OSThreadInfo { // fields are sometimes directly accessed struct OSThread initialThread; struct OSMutexQueue RunQueue[0x20]; struct OSContext idleCtx; }