ARM9 OS: Difference between revisions

Hallowizer (talk | contribs)
Threads: info on how the scheduler works
Hallowizer (talk | contribs)
Threads: kernelSp is a system stack used for thread cleanup and SVCs
 
(10 intermediate revisions by the same user not shown)
Line 4: Line 4:
The scheduler only runs the thread with the highest priority, and does not switch between threads if two threads have the same priority. Because of this, rescheduling only happens when a thread-related function is called and the thread with the highest priority can no longer run.
The scheduler only runs the thread with the highest priority, and does not switch between threads if two threads have the same priority. Because of this, rescheduling only happens when a thread-related function is called and the thread with the highest priority can no longer run.
<pre>
<pre>
struct OSFpContext {
struct OSMathContext {
f64 REG_DIV_NUMER; // 0x0
u64 REG_DIV_NUMER; // 0x0
f64 REG_DIV_DENOM; // 0x8
u64 REG_DIV_DENOM; // 0x8
f64 SQRT_PARAM; // 0x10
u64 SQRT_PARAM; // 0x10
u16 REG_DIVCNT; // 0x18
u16 REG_DIVCNT; // 0x18
u16 REG_SQRTCNT; // 0x1a
u16 REG_SQRTCNT; // 0x1a
Line 30: Line 30:
void *lr; // 0x3c
void *lr; // 0x3c
void *pc; // 0x40
void *pc; // 0x40
void *kernelSp; // 0x44
void *systemStack; // 0x44
struct OSFpContext fp; // 0x48
struct OSMathContext math; // 0x48
}
}


Line 43: Line 43:
struct OSThreadQueue *queue; // 0x78
struct OSThreadQueue *queue; // 0x78
struct OSThreadLink linkQueue; // 0x7c
struct OSThreadLink linkQueue; // 0x7c
u32 unknown2; // 0x80
struct OSMutex *mutex; // 0x84 - set to the mutex the thread is currently trying to lock
struct OSMutexQueue *queueMutex; // 0x84
struct OSMutexQueue queueMutex; // 0x88
// more unknown fields - the total length is not known
void *stackLo; // 0x90
void *stackHi; // 0x94
void *unknown2; // 0x98
struct OSThreadQueue queueJoin; // 0x9c
u32 unknown3[3]; // 0xa4
struct OSAlarm *timedSleepAlarm; // 0xb0
void (*cleanupFunc)(u32 res); // 0xb4
u32 unknown4[2];
}
}


Line 67: Line 74:


struct OSMutexQueue {
struct OSMutexQueue {
struct OSMutex *waiting;
struct OSMutex *head;
struct OSMutex *head;
struct OSMutex *tail;
struct OSMutex *tail;
Line 87: Line 93:
== Memory allocation ==
== Memory allocation ==
3 types of heaps exist: EXPH (exponential heap), FRMH (frame heap), and UNTH (unit heap).
3 types of heaps exist: EXPH (exponential heap), FRMH (frame heap), and UNTH (unit heap).
== Time ==
Timer 0 is used to keep track of global time by manually incrementing a global, while timer 1 is used to generate an interrupt for alarms. The OS orders the alarms by alert time, so that it only needs to keep track of the frontmost alarm.
<pre>
struct OSAlarm {
void (*handler)(void *userData);
void *userData;
u32 unknown;
u64 alertTime;
struct OSAlarm *prev;
struct OSAlarm *next;
u64 repeatInterval; // 0 for non-repeating alarms
u64 repeatStart; // undefined value for non-repeating alarms
}
struct OSAlarmQueue {
u32 unknown;
struct OSAlarm *head;
struct OSAlarm *tail;
}
</pre>
== Interrupts ==
The interrupt handler called by the [[ARM9 BIOS]] calls a handler in a table mapping the raw IRQ IDs to handlers. Each handler is either a no-op (not listed in the table below) or a stub that calls <code>__OSDispatchInterrupt</code> with an OS interrupt ID. <code>__OSDispatchInterrupt</code> then calls the handler registered with <code>__OSSetInterruptHandler</code>.
{| class="wikitable sortable"
! Hardware ID
! Translated ID
! Name
|-
| 3
| 8
| Timer 0 overflow
|-
| 4
| 9
| Timer 1 overflow
|-
| 5
| 10
| Timer 2 overflow
|-
| 6
| 11
| Timer 3 overflow
|-
| 8
| 0
| DMA 0
|-
| 9
| 1
| DMA 1
|-
| 10
| 2
| DMA 2
|-
| 11
| 3
| DMA 3
|-
| 28
| 4
| New DMA 0
|-
| 29
| 5
| New DMA 1
|-
| 30
| 6
| New DMA 2
|-
| 31
| 7
| New DMA 3
|}