mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
exec_os: enrich all stubs to bootcamp-quality reference articles
Complete rewrite of 14 exec_os articles from stubs to comprehensive deep-dive technical references with architecture diagrams, pitfalls, and best practices. New: multitasking.md (scheduler, IPC, memory safety, real-world scenarios) Enriched: exec_base, tasks_processes, library_system, library_vectors, interrupts, exceptions_traps, memory_management, message_ports, signals, semaphores, io_requests, lists_nodes, resident_modules Updated indexes: 06_exec_os/README.md, root README.md
This commit is contained in:
parent
4d136b0672
commit
59929047d4
16 changed files with 4463 additions and 678 deletions
|
|
@ -4,101 +4,240 @@
|
|||
|
||||
## Overview
|
||||
|
||||
`ExecBase` is the root structure of AmigaOS, located at absolute address `$4`. It is a `struct Library` extended with all exec kernel state: memory lists, task queues, interrupt vectors, library lists, and hardware abstraction fields.
|
||||
`ExecBase` is the root structure of AmigaOS, located at absolute address `$4`. It is a `struct Library` extended with all exec kernel state: memory lists, task queues, interrupt vectors, library lists, and hardware abstraction fields. Every system call goes through `ExecBase` — it is the single point of truth for the entire running system.
|
||||
|
||||
---
|
||||
|
||||
## Locating ExecBase
|
||||
|
||||
```c
|
||||
/* C — standard method */
|
||||
struct ExecBase *SysBase = *((struct ExecBase **)4);
|
||||
|
||||
/* Or use the auto-open variable (SAS/C, GCC): */
|
||||
extern struct ExecBase *SysBase; /* Linker resolves from startup code */
|
||||
```
|
||||
|
||||
In assembly:
|
||||
```asm
|
||||
MOVEA.L 4.W, A6 ; A6 = SysBase
|
||||
; Assembly — canonical method
|
||||
MOVEA.L 4.W,A6 ; A6 = SysBase (short absolute addressing)
|
||||
; All exec LVO calls use JSR offset(A6)
|
||||
```
|
||||
|
||||
> **Why address $4?** The 68000 stores the initial Program Counter at address $4 in the exception vector table. During cold boot, the CPU reads this address to find the ROM entry point. After boot, Exec overwrites it with a pointer to ExecBase. This is the one absolute address every Amiga program can rely on.
|
||||
|
||||
---
|
||||
|
||||
## Structure Layout
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
EB["ExecBase at $4"] --> LIB["Library Header<br/>(struct Library)<br/>Offsets 0–33"]
|
||||
EB --> SOFT["Software Config<br/>SoftVer, ColdCapture,<br/>WarmCapture, SysStkUpper"]
|
||||
EB --> TASK["Task Scheduling<br/>TaskReady, TaskWait,<br/>ThisTask, IDNestCnt,<br/>TDNestCnt, Quantum"]
|
||||
EB --> MEM["Memory Management<br/>MemList, MaxLocMem,<br/>MaxExtMem"]
|
||||
EB --> LISTS["System Lists<br/>LibList, DeviceList,<br/>ResourceList, PortList,<br/>IntrList"]
|
||||
EB --> HW["Hardware Detection<br/>AttnFlags, ChipRevBits0,<br/>PowerSupplyFrequency,<br/>VBlankFrequency"]
|
||||
|
||||
style EB fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style TASK fill:#e8f5e9,stroke:#4caf50,color:#333
|
||||
style HW fill:#fff3e0,stroke:#ff9800,color:#333
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Field Groups
|
||||
|
||||
### Library Header (offset 0)
|
||||
### Library Header (Offset 0–33)
|
||||
|
||||
Every library starts with this — ExecBase is exec.library's own base:
|
||||
|
||||
```c
|
||||
struct Library LibNode; /* +0 — ln_Name = "exec.library" */
|
||||
/* +20 — lib_Version (40 = OS3.1, 44 = OS3.2) */
|
||||
struct Library LibNode; /* ln_Name = "exec.library" */
|
||||
/* lib_Version = 40 (OS 3.1), 45 (OS 3.2), 47 (OS 3.2.2) */
|
||||
/* lib_OpenCnt = open count */
|
||||
```
|
||||
|
||||
### Interrupts (offset +84)
|
||||
```c
|
||||
UWORD AttnFlags; /* +0x128 — processor capability flags */
|
||||
UWORD AttnResched; /* +0x12A — reschedule attention flag */
|
||||
```
|
||||
### Boot and Configuration
|
||||
|
||||
| Offset | Field | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `$22` | `SoftVer` | `UWORD` | Kickstart software revision |
|
||||
| `$24` | `LowMemChkSum` | `WORD` | Checksum of vectors $0–$200 |
|
||||
| `$26` | `ChkBase` | `ULONG` | ExecBase self-checksum |
|
||||
| `$2A` | `ColdCapture` | `APTR` | Cold reboot intercept vector |
|
||||
| `$2E` | `CoolCapture` | `APTR` | Warm reboot intercept vector (after Diag) |
|
||||
| `$32` | `WarmCapture` | `APTR` | Keyboard reset intercept vector |
|
||||
| `$36` | `SysStkUpper` | `APTR` | Top of supervisor stack |
|
||||
| `$3A` | `SysStkLower` | `APTR` | Bottom of supervisor stack |
|
||||
| `$3E` | `MaxLocMem` | `ULONG` | Top of Chip RAM (e.g., `$200000` for 2 MB) |
|
||||
| `$42` | `DebugEntry` | `APTR` | Entry point for ROM debugger (Wack) |
|
||||
| `$46` | `DebugData` | `APTR` | Data area for ROM debugger |
|
||||
| `$4A` | `AlertData` | `APTR` | Last Alert data |
|
||||
| `$4E` | `MaxExtMem` | `APTR` | Top of Extended RAM (or NULL) |
|
||||
|
||||
### Task Scheduling
|
||||
| Offset | Field | Description |
|
||||
|---|---|---|
|
||||
| +0x128 | `TaskReady` | `struct List` — tasks ready to run |
|
||||
| +0x132 | `TaskWait` | `struct List` — tasks waiting on signals |
|
||||
| +0x126 | `IDNestCnt` | Interrupt disable nesting count |
|
||||
| +0x127 | `TDNestCnt` | Task disable nesting count |
|
||||
|
||||
| Offset | Field | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `$126` | `IDNestCnt` | `BYTE` | Interrupt disable nesting (−1 = enabled) |
|
||||
| `$127` | `TDNestCnt` | `BYTE` | Task disable nesting (−1 = enabled) |
|
||||
| `$128` | `ThisTask` | `APTR` | Pointer to currently running Task |
|
||||
| `$12C` | `Quantum` | `UWORD` | Time slice for equal-priority round-robin |
|
||||
| `$12E` | `Elapsed` | `UWORD` | Ticks elapsed in current quantum |
|
||||
| `$130` | `SysFlags` | `UWORD` | Internal scheduler flags |
|
||||
| `$132` | `TaskReady` | `List` | Tasks ready to run (sorted by priority) |
|
||||
| `$146` | `TaskWait` | `List` | Tasks blocked on `Wait()` |
|
||||
|
||||
### Memory
|
||||
| Offset | Field | Description |
|
||||
|---|---|---|
|
||||
| +0x130 | `MemList` | `struct List` of `MemHeader` regions |
|
||||
| +0x134 | `ResourceList` | Resources list |
|
||||
|
||||
### Library and Device Lists
|
||||
| Offset | Field | Description |
|
||||
|---|---|---|
|
||||
| +0x17A | `LibList` | `struct List` — loaded libraries |
|
||||
| +0x182 | `DeviceList` | `struct List` — loaded devices |
|
||||
| +0x18A | `IntrList` | Interrupt server list |
|
||||
| +0x192 | `PortList` | Public message ports |
|
||||
| +0x19A | `TaskList` | All tasks (not just ready/waiting) |
|
||||
| Offset | Field | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `$15A` | `MemList` | `List` | All memory regions (`MemHeader` chain) |
|
||||
|
||||
### Vectors and ROM
|
||||
| Offset | Field | Description |
|
||||
|---|---|---|
|
||||
| +0x26 | `SoftVer` | Kickstart software revision |
|
||||
| +0x10 | `ChkBase` | Checksum of library header |
|
||||
| +0x222 | `PowerSupplyFrequency` | 50 or 60 Hz |
|
||||
| +0x21E | `ChipRevBits0` | Chip revision detection flags |
|
||||
### System Lists
|
||||
|
||||
### Chip Revision Flags (`ChipRevBits0`)
|
||||
| Offset | Field | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `$17A` | `LibList` | `List` | Loaded libraries (`NT_LIBRARY`) |
|
||||
| `$18E` | `DeviceList` | `List` | Loaded devices (`NT_DEVICE`) |
|
||||
| `$1A2` | `IntrList` | `List` | Interrupt server lists |
|
||||
| `$1B6` | `ResourceList` | `List` | System resources |
|
||||
| `$1CA` | `PortList` | `List` | Public message ports |
|
||||
| `$1DE` | `SemaphoreList` | `List` | Public semaphores |
|
||||
|
||||
| Bit | Constant | Chip |
|
||||
|---|---|---|
|
||||
| 4 | `ATNF_68010` | 68010 or better |
|
||||
| 5 | `ATNF_68020` | 68020 or better |
|
||||
| 6 | `ATNF_68030` | 68030 |
|
||||
| 7 | `ATNF_68040` | 68040 |
|
||||
| 10 | `ATNF_FPU40` | 68040 internal FPU |
|
||||
### Hardware Detection
|
||||
|
||||
| Offset | Field | Type | Description |
|
||||
|---|---|---|---|
|
||||
| `$128` | `AttnFlags` | `UWORD` | CPU and FPU capability flags |
|
||||
| `$212` | `VBlankFrequency` | `UBYTE` | VBL rate: 50 (PAL) or 60 (NTSC) |
|
||||
| `$213` | `PowerSupplyFrequency` | `UBYTE` | Mains: 50 or 60 Hz |
|
||||
| `$21E` | `ChipRevBits0` | `UBYTE` | Chip revision detection |
|
||||
|
||||
---
|
||||
|
||||
## Detecting CPU and Chipset
|
||||
## AttnFlags — CPU Detection
|
||||
|
||||
| Bit | Constant | Meaning |
|
||||
|---|---|---|
|
||||
| 0 | `AFF_68010` | 68010 or better detected |
|
||||
| 1 | `AFF_68020` | 68020 or better |
|
||||
| 2 | `AFF_68030` | 68030 or better |
|
||||
| 3 | `AFF_68040` | 68040 or better |
|
||||
| 4 | `AFF_68881` | 68881 FPU detected |
|
||||
| 5 | `AFF_68882` | 68882 FPU detected |
|
||||
| 6 | `AFF_FPU40` | 68040 internal FPU |
|
||||
| 7 | `AFF_68060` | 68060 detected (OS 3.1+) |
|
||||
| 10 | `AFF_PRIVATE` | Exec private — do not use |
|
||||
|
||||
### Usage
|
||||
|
||||
```c
|
||||
/* CPU: */
|
||||
if (SysBase->AttnFlags & AFF_68020) { /* 020+ */ }
|
||||
if (SysBase->AttnFlags & AFF_68040) { /* 040 */ }
|
||||
/* Check for 68020+ */
|
||||
if (SysBase->AttnFlags & AFF_68020)
|
||||
{
|
||||
/* Can use CACHE instructions, 32-bit multiply, etc. */
|
||||
}
|
||||
|
||||
/* Chipset (via graphics.library): */
|
||||
struct GfxBase *gfx = (struct GfxBase *)OpenLibrary("graphics.library", 36);
|
||||
if (gfx->ChipRevBits0 & GFXB_AA_ALICE) { /* AGA Alice chip */ }
|
||||
/* Check for FPU */
|
||||
if (SysBase->AttnFlags & (AFF_68881 | AFF_68882 | AFF_FPU40))
|
||||
{
|
||||
/* Floating-point hardware available */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ExecBase in IDA Pro
|
||||
## Detecting Chipset Revision
|
||||
|
||||
```c
|
||||
/* via graphics.library */
|
||||
struct GfxBase *gfx = (struct GfxBase *)OpenLibrary("graphics.library", 36);
|
||||
if (gfx)
|
||||
{
|
||||
if (gfx->ChipRevBits0 & GFXB_AA_ALICE) /* AGA Alice */
|
||||
if (gfx->ChipRevBits0 & GFXB_AA_LISA) /* AGA Lisa */
|
||||
if (gfx->ChipRevBits0 & GFXB_HR_AGNUS) /* ECS Agnus */
|
||||
if (gfx->ChipRevBits0 & GFXB_HR_DENISE) /* ECS Denise */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enumerating System Lists
|
||||
|
||||
### Walking the Library List
|
||||
|
||||
```c
|
||||
Forbid();
|
||||
struct Node *node;
|
||||
for (node = SysBase->LibList.lh_Head;
|
||||
node->ln_Succ != NULL;
|
||||
node = node->ln_Succ)
|
||||
{
|
||||
struct Library *lib = (struct Library *)node;
|
||||
Printf(" %s V%ld.%ld (open: %ld)\n",
|
||||
lib->lib_Node.ln_Name,
|
||||
lib->lib_Version,
|
||||
lib->lib_Revision,
|
||||
lib->lib_OpenCnt);
|
||||
}
|
||||
Permit();
|
||||
```
|
||||
|
||||
### Walking the Task Lists
|
||||
|
||||
```c
|
||||
Forbid();
|
||||
|
||||
/* Currently running */
|
||||
Printf("Running: %s\n", SysBase->ThisTask->tc_Node.ln_Name);
|
||||
|
||||
/* Ready to run */
|
||||
for (node = SysBase->TaskReady.lh_Head;
|
||||
node->ln_Succ; node = node->ln_Succ)
|
||||
{
|
||||
Printf(" Ready: %s (pri %ld)\n",
|
||||
node->ln_Name, node->ln_Pri);
|
||||
}
|
||||
|
||||
/* Waiting */
|
||||
for (node = SysBase->TaskWait.lh_Head;
|
||||
node->ln_Succ; node = node->ln_Succ)
|
||||
{
|
||||
Printf(" Wait: %s (pri %ld)\n",
|
||||
node->ln_Name, node->ln_Pri);
|
||||
}
|
||||
|
||||
Permit();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ExecBase Safety Rules
|
||||
|
||||
| Rule | Reason |
|
||||
|---|---|
|
||||
| **Never write to ExecBase fields** | Corrupts kernel state for all tasks |
|
||||
| **Use `Forbid()` when walking lists** | Lists change as libraries open/close, tasks start/stop |
|
||||
| **Don't cache pointers from lists** | Nodes may be removed between accesses |
|
||||
| **Always use LVO functions** | Direct field manipulation bypasses safety checks |
|
||||
| **Verify `SysBase` after warm reboot** | `ColdCapture`/`CoolCapture` may have altered it |
|
||||
|
||||
---
|
||||
|
||||
## ExecBase in IDA Pro / Ghidra
|
||||
|
||||
After loading Kickstart ROM:
|
||||
1. Create a segment at `$4` containing a pointer
|
||||
2. Follow the pointer to the ExecBase (in ROM)
|
||||
3. Apply `struct ExecBase` type (from NDK39 headers parsed via `File → Parse C header`)
|
||||
4. All `N(A6)` offsets auto-annotate as field names
|
||||
|
||||
1. **Create a segment** at `$000000–$000400` (exception vectors)
|
||||
2. **Mark `$4` as a pointer** — follow it to the ExecBase in ROM
|
||||
3. **Apply `struct ExecBase` type** from NDK39 headers
|
||||
- IDA: `File → Parse C header` with `exec/execbase.h`
|
||||
- Ghidra: Import C headers via Data Type Manager
|
||||
4. **All `N(A6)` offsets** in exec code auto-annotate as field names
|
||||
5. **Label the system lists** — `LibList`, `DeviceList`, `PortList` are entry points for understanding boot order
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -106,5 +245,6 @@ After loading Kickstart ROM:
|
|||
|
||||
- NDK39: `exec/execbase.h` — authoritative field definitions
|
||||
- ADCD 2.1: exec.library autodoc
|
||||
- See also: [Library System](library_system.md) — how libraries relate to ExecBase
|
||||
- See also: [Multitasking](multitasking.md) — TaskReady/TaskWait and scheduler internals
|
||||
- *Amiga ROM Kernel Reference Manual: Exec* — ExecBase chapter
|
||||
- http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node0072.html
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue