diff --git a/02_boot_sequence/README.md b/02_boot_sequence/README.md index bd5084f..be96389 100644 --- a/02_boot_sequence/README.md +++ b/02_boot_sequence/README.md @@ -2,11 +2,14 @@ # Boot Sequence — Overview +From power-on to Workbench desktop: hardware init, ROM validation, kernel creation, device enumeration, boot block execution, and startup scripts. + ## Section Index | File | Description | |---|---| -| [cold_boot.md](cold_boot.md) | Power-on to Kickstart: hardware init, ROM checksum | -| [kickstart_init.md](kickstart_init.md) | ROM scan, resident modules, ExecBase creation | -| [dos_boot.md](dos_boot.md) | BootStrap, eb_MountList, startup-sequence | -| [early_startup.md](early_startup.md) | Early Startup Control (ESC menu), boot priority | +| [cold_boot.md](cold_boot.md) | Power-on to Kickstart: CPU reset vectors, ROM checksum, hardware reset, memory detection, diagnostic indicators, capture vectors | +| [kickstart_rom.md](kickstart_rom.md) | **Kickstart ROM internals: binary structure, module inventory, extraction tools, custom ROM building, EPROM burning** | +| [kickstart_init.md](kickstart_init.md) | ExecBase creation, capture vectors, resident module scan algorithm, 4-phase initialization, bootstrap handoff | +| [dos_boot.md](dos_boot.md) | strap module, boot block format and execution, MountList/DOSDrivers, system assigns, Startup-Sequence walkthrough | +| [early_startup.md](early_startup.md) | Early Startup Control menu: boot device selection, display mode override, recovery scenarios | diff --git a/02_boot_sequence/cold_boot.md b/02_boot_sequence/cold_boot.md index 0135602..c09f478 100644 --- a/02_boot_sequence/cold_boot.md +++ b/02_boot_sequence/cold_boot.md @@ -4,98 +4,497 @@ ## Overview -When the Amiga powers on or is reset (Ctrl-Amiga-Amiga), the 68000 CPU begins execution from the ROM. The boot process progresses from raw hardware init through to a fully running AmigaOS desktop in approximately 3–8 seconds. +When the Amiga powers on or is reset (Ctrl-Amiga-Amiga), the 68000 CPU begins execution from the ROM. The boot process progresses from raw hardware initialization through to a fully running AmigaOS desktop in approximately 3–8 seconds. This document covers everything that happens from the moment power is applied to the moment the Kickstart ROM hands control to the OS initialization code. --- -## Hardware Initialisation (Pre-ROM) +## Boot Timeline -### 1. CPU Reset Vector +```mermaid +graph TB + POWER["⚡ Power On / Reset"] --> CPU["68k reads reset vectors
$000000: SSP
$000004: PC → ROM entry"] + CPU --> CHKSUM["ROM Checksum
Sum all longwords = $FFFFFFFF?"] + CHKSUM -->|FAIL| RED["🔴 Red Screen
System halts"] + CHKSUM -->|PASS| HWRESET["Hardware Reset
Disable DMA, interrupts
Reset custom chips, CIAs"] + HWRESET --> MEMDET["Memory Detection
Size Chip RAM
Probe expansion"] + MEMDET -->|FAIL| YELLOW["🟡 Yellow Screen
RAM test fail"] + MEMDET -->|PASS| EXEC["ExecBase Creation
Store pointer at $4"] + EXEC --> CAPTURE["Check ColdCapture
vector ($2A)"] + CAPTURE --> RESIDENT["ROM Scan
Find $4AFC RomTags"] + RESIDENT --> INIT["Initialize Residents
by priority"] -The 68000 reads two longwords from address `$000000`: -``` -$000000: Initial SSP (Supervisor Stack Pointer) -$000004: Initial PC (Program Counter) → ROM entry point + style POWER fill:#e8f4fd,stroke:#2196f3,color:#333 + style RED fill:#ffcdd2,stroke:#e53935,color:#333 + style YELLOW fill:#fff9c4,stroke:#f9a825,color:#333 + style EXEC fill:#e8f5e9,stroke:#4caf50,color:#333 ``` -On Amiga, these locations map to Kickstart ROM at `$FC0000` (256 KB) or `$F80000` (512 KB). The ROM image contains: -- Word 0–1: SSP value (typically `$000400`) -- Word 2–3: PC value → ROM entry point +--- -### 2. ROM Checksum +## Step 1: CPU Reset Vector Fetch -First code executed: compute checksum of entire ROM. If it fails → **red screen of death** (solid red background, no further boot). +The 68000 CPU has a hardwired reset sequence: -``` -Checksum: simple 32-bit additive checksum of all ROM longwords. -Result must equal $FFFFFFFF (complement to zero). -The last longword of the ROM is the complement value. +1. Enters supervisor mode, sets interrupt mask to level 7 (all masked) +2. Reads a longword from address `$000000` → loads into SSP (Supervisor Stack Pointer) +3. Reads a longword from address `$000004` → loads into PC (Program Counter) +4. Begins executing from the PC address + +On the Amiga, addresses `$000000–$000007` map to Kickstart ROM during reset (via the OVL — overlay — signal from Gary/Gayle). Once the boot code runs a few instructions, it clears the OVL pin, remapping `$000000` to Chip RAM. + +```asm +; ROM at $F80000 (512 KB Kickstart): +$F80000: dc.l $00000400 ; Initial SSP = $400 (supervisor stack in low memory) +$F80004: dc.l $F80008 ; Initial PC = next instruction in ROM + +; First instruction executed: +$F80008: LEA $F80000,A0 ; Load ROM base + ... ; Begin boot sequence ``` -### 3. Chip Register Reset +### The OVL (Overlay) Mechanism -``` -- Write $7FFF to INTENA ($DFF09A) — disable all interrupts -- Write $7FFF to INTREQ ($DFF09C) — clear all pending interrupts -- Write $7FFF to DMACON ($DFF096) — disable all DMA -- CIA chips: reset timer, serial, port registers +| State | Address $000000 maps to | Purpose | +|---|---|---| +| OVL = 1 (reset) | ROM ($F80000) | CPU reads SSP/PC from ROM | +| OVL = 0 (cleared) | Chip RAM | Normal operation — exception vectors in RAM | + +The boot code clears OVL by writing to CIA-A PRA (bit 0) within the first few instructions, switching $000000 back to Chip RAM. This allows the OS to install its own exception vectors. + +--- + +## Step 2: ROM Checksum Verification + +Immediately after gaining control, the boot code verifies ROM integrity: + +```c +/* ROM checksum algorithm */ +ULONG checksum = 0; +ULONG *rom = (ULONG *)ROM_BASE; +ULONG rom_size = ROM_SIZE / 4; /* longword count */ + +for (ULONG i = 0; i < rom_size; i++) +{ + ULONG old = checksum; + checksum += rom[i]; + if (checksum < old) /* carry occurred */ + checksum++; /* add carry back (ones' complement addition) */ +} + +if (checksum != 0xFFFFFFFF) +{ + /* FAIL — display solid red screen */ + custom.color[0] = 0x0F00; /* Red background */ + for (;;) ; /* Halt — no recovery */ +} ``` -### 4. Memory Detection +### Checksum Details -The ROM probes for available memory: -``` -1. Test Chip RAM at $000000 by writing test patterns -2. Size Chip RAM: 256 KB, 512 KB, 1 MB, or 2 MB -3. Probe for Fast RAM at $C00000 (Ranger), $200000 (Slow/Ranger) -4. Probe for Zorro II auto-config space at $E80000 -5. Probe for 32-bit fast RAM at $07000000+ (Zorro III) +| ROM Type | Size | Base Address | Checksum Location | +|---|---|---|---| +| Kickstart 1.x | 256 KB | `$FC0000` | `$FFFFE8` (last LW before vectors) | +| Kickstart 2.0+ | 512 KB | `$F80000` | `$FFFFF8` | +| Kickstart 3.1 | 512 KB | `$F80000` | `$FFFFF8` | + +The checksum is a **ones' complement additive checksum** — the sum of all longwords in the ROM, including carries, must equal `$FFFFFFFF`. The ROM builder calculates a complement value and places it near the end of the ROM image to ensure this. + +> **For FPGA developers**: If your ROM image produces a red screen, the checksum is wrong. Recalculate it with the complement value at the correct offset for your ROM size. + +--- + +## Step 3: Hardware Reset + +The boot code puts all hardware into a known safe state: + +```asm +; Disable everything before touching any hardware + MOVE.W #$7FFF,INTENA ; Clear all interrupt enable bits + MOVE.W #$7FFF,INTREQ ; Clear all pending interrupt requests + MOVE.W #$7FFF,DMACON ; Disable all DMA channels + MOVE.W #$7FFF,ADKCON ; Clear audio/disk control + +; Reset CIA chips + MOVE.B #$00,CIAA_CRA ; Stop CIA-A Timer A + MOVE.B #$00,CIAA_CRB ; Stop CIA-A Timer B + MOVE.B #$00,CIAB_CRA ; Stop CIA-B Timer A + MOVE.B #$00,CIAB_CRB ; Stop CIA-B Timer B + MOVE.B #$7F,CIAA_ICR ; Disable all CIA-A interrupts + MOVE.B #$7F,CIAB_ICR ; Disable all CIA-B interrupts + +; Set CIA-A port directions + MOVE.B #$03,CIAA_DDRA ; PA0=OVL(out), PA1=LED(out), rest input + MOVE.B #$FF,CIAA_DDRB ; Port B = parallel data (output) + +; Clear OVL — remap $000000 to Chip RAM + BCLR #0,CIAA_PRA ; Clear OVL bit → Chip RAM now at $0 ``` -### 5. Display Diagnostic Colours +### Hardware State After Reset -During boot, the background colour indicates progress: +| Subsystem | State | Register | +|---|---|---| +| All DMA | Disabled | DMACON = $0000 | +| All interrupts | Disabled | INTENA = $0000 | +| All interrupt requests | Cleared | INTREQ = $0000 | +| CIA timers | Stopped | CRA/CRB = $00 | +| Blitter | Idle | — | +| Copper | Idle | — | +| Audio | Silent | — | +| Floppy motor | Off | — | +| Video | Black screen | COLOR00 = $000 | -| Colour | Stage | +--- + +## Step 4: Memory Detection + +The ROM probes for available memory by writing test patterns and reading them back: + +### Chip RAM Detection + +```c +/* Test pattern write/read at progressively higher addresses */ +/* Typical patterns: $AAAAAAAA / $55555555 (alternating bits) */ + +ULONG chip_size = 0; +ULONG test_addrs[] = { 0x040000, 0x080000, 0x100000, 0x200000 }; /* 256K, 512K, 1M, 2M */ + +for (int i = 0; i < 4; i++) +{ + volatile ULONG *p = (ULONG *)test_addrs[i]; + *p = 0xAAAAAAAA; + if (*p == 0xAAAAAAAA) + { + *p = 0x55555555; + if (*p == 0x55555555) + chip_size = test_addrs[i]; + } +} +``` + +### Memory Probing Order + +| Step | Address Range | Memory Type | How Detected | +|---|---|---|---| +| 1 | `$000000–$03FFFF` | Chip RAM (256 KB min) | Test patterns | +| 2 | `$040000–$07FFFF` | Chip RAM (512 KB) | Test patterns | +| 3 | `$080000–$0FFFFF` | Chip RAM (1 MB) | Test patterns | +| 4 | `$100000–$1FFFFF` | Chip RAM (2 MB) | Test patterns | +| 5 | `$C00000–$C7FFFF` | Ranger/Slow RAM (A500) | Test patterns | +| 6 | `$200000–$9FFFFF` | Fast RAM (trapdoor/PCMCIA) | Test patterns | +| 7 | `$E80000–$EFFFFF` | Zorro II Autoconfig | Autoconfig protocol | +| 8 | `$07000000+` | Zorro III (32-bit) | Autoconfig protocol | + +### Autoconfig (Zorro II/III) + +Expansion boards are detected via the **Autoconfig** protocol: + +```c +/* Autoconfig space: $E80000 */ +/* Read manufacturer ID, product ID, board size from config registers */ +/* Assign board a base address */ +/* AddMemList() to register any RAM found on the board */ + +struct ConfigDev *cd; +while ((cd = FindConfigDev(cd, -1, -1)) != NULL) +{ + if (cd->cd_Rom.er_Type & ERTF_MEMLIST) + { + /* This board has RAM — add to system memory pool */ + AddMemList(cd->cd_BoardSize, MEMF_FAST | MEMF_PUBLIC, + 0, cd->cd_BoardAddr, "expansion memory"); + } +} +``` + +## Step 5: ROM Self-Test and Diagnostic Indicators + +The Amiga has a multi-layered diagnostic system that uses screen colours, power LED patterns, and keyboard LED blink codes to communicate status. Understanding these signals is essential for FPGA core development and hardware debugging. + +### Normal Boot Colour Sequence + +A healthy boot cycles through these colours rapidly (total <1 second on 68000): + +``` +┌─────────┐ ┌──────────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌─────────┐ +│ BLACK │───→│ DARK GREY│───→│ MED GREY │───→│LIGHT GREY │───→│ WHITE │───→│ GREEN │ +│ $000 │ │ $444 │ │ $888 │ │ $AAA │ │ $FFF │ │ $0F0 │ +│ CPU init│ │ ROM OK │ │ RAM sized │ │ Exec init │ │ Residents│ │ DOS boot│ +└─────────┘ └──────────┘ └───────────┘ └───────────┘ └──────────┘ └─────────┘ +``` + +If the sequence **stops** at any colour, that colour identifies the failure point. + +### Screen Colour Diagnostic Table + +| Colour | Hex | Phase | Indicates | What Failed | +|---|---|---|---|---| +| Black (stuck) | `$000` | Pre-init | CPU not executing | No clock, dead CPU, no ROM addressing | +| Dark grey | `$444` | Post-checksum | ROM checksum passed | (Normal — transient) | +| Medium grey | `$888` | Memory test | Chip RAM sized OK | (Normal — transient) | +| Light grey | `$AAA` | Exec init | ExecBase created | (Normal — transient) | +| White | `$FFF` | Resident scan | Modules initializing | (Normal — transient) | +| Green flash | `$0F0` | DOS boot | dos.library starting | (Normal — transient) | +| **Red** (stuck) | `$F00` | **Checksum** | **ROM checksum failed** | Bad ROM chip, wrong image, bit rot | +| **Yellow** (stuck) | `$FF0` | **RAM test** | **Chip RAM failed** | Dead RAM chips, Agnus addressing fault | +| **Green** (stuck) | `$0F0` | **Custom chips** | **Chipset failure** | Denise, Paula, or Agnus not responding | +| **Blue** (stuck) | `$00F` | **Exception** | **Alert / Guru** | CPU exception before handler installed | +| **Magenta** (stuck) | `$F0F` | **Exception** | **Hardware trap** | Unexpected interrupt or bus error | +| **Cyan** (stuck) | `$0FF` | **Misc** | **CIA or clock** | Timer initialization failure | + +### How the ROM Sets Diagnostic Colours + +```asm +; The boot code writes COLOR00 at each milestone: +; After ROM checksum passes: + MOVE.W #$0444,$DFF180 ; Dark grey → "ROM OK" + +; After Chip RAM test passes: + MOVE.W #$0888,$DFF180 ; Medium grey → "RAM OK" + +; On failure — set error colour and halt: +RomChecksumFailed: + MOVE.W #$0F00,$DFF180 ; Red screen +.hang: + BRA.S .hang ; Infinite loop — no recovery + +RamTestFailed: + MOVE.W #$0FF0,$DFF180 ; Yellow screen +.hang: + BRA.S .hang +``` + +### Power LED Behaviour + +| Pattern | Meaning | |---|---| -| Dark grey | ROM checksum passed | -| Light grey | Chip RAM sized | -| White | ExecBase initialised | -| Green flash | DOS boot starting | -| **Red** | ROM checksum fail | -| **Yellow** | Chip RAM test fail | -| **Blue** | Alert (Guru Meditation) | +| Solid ON | Normal operation | +| Slow blink (~1 Hz) | Low memory condition (filter signal) | +| Fast blink (~4 Hz) | Critical failure during boot | +| OFF | Power supply failure or CPU not running | +| Dim | Audio filter enabled (normal — controlled by CIA-A PA1) | + +> **Note**: The power LED's brightness is controlled by CIA-A PRA bit 1. The LED is active-low — writing 0 turns it ON, writing 1 turns it OFF. The "dim" state is actually the audio low-pass filter indicator. + +### Keyboard LED Blink Codes + +The Amiga keyboard has its own 6500/1 microcontroller that performs a self-test on power-up. Failures are reported via the Caps Lock LED: + +| Blinks | Failure | +|---|---| +| 1 | Keyboard ROM checksum error | +| 2 | Keyboard RAM test failed | +| 3 | Watchdog timer failure | +| 4 | Short circuit between key matrix lines | +| None (LED off) | Keyboard OK — or keyboard not connected | + +The keyboard communicates with the main system via a synchronous serial protocol through CIA-A. If the keyboard passes self-test, it sends a power-up key stream (`$FD` = initiate power-up, then `$FE` = terminate power-up). + +### Normal vs Abnormal Boot Behaviour + +**Normal boot** (A500/A1200 with Kickstart 3.1): + +``` +0 ms: Black screen +~5 ms: Dark grey (ROM checksum calculating) +~600 ms: Medium grey (checksum done, RAM test running) +~650 ms: Light grey (ExecBase init) +~700 ms: White (resident scan starting) +~900 ms: Colors flash rapidly (graphics.library init, display setup) +~1.2 s: Kickstart hand/checkmark animation appears +~1.5 s: Green (dos.library booting) +~2.0 s: Insert Disk screen (A500) or boot from HD (A1200) +~3-8 s: Workbench desktop appears +``` + +**Abnormal indicators — troubleshooting guide:** + +| Symptom | Diagnosis | Action | +|---|---|---| +| Solid black, no LED | No power or CPU not clocking | Check PSU, clock crystal, CPU socket | +| Solid red screen | ROM checksum fail | Reseat ROM chips; verify ROM image (FPGA) | +| Solid yellow screen | All Chip RAM failed | Check Agnus chip (provides RAM addressing); reseat RAM | +| Flashing red/yellow alternating | Intermittent RAM | Replace RAM chips; check address bus traces | +| Solid green screen | Custom chipset failure | Test Denise, Paula; check crystal oscillator | +| Blue screen with Guru | OS exception during init | Check for corrupted ROM modules; RAM address issues | +| White screen, hangs | Resident module crash | A specific library/device init is failing — try DiagROM | +| Boot logo appears but hangs | Trackdisk/filesystem issue | Check DF0: drive; boot without startup-sequence | +| Keyboard Caps Lock blinking | Keyboard failure | Keyboard self-test failed — replace keyboard controller | +| Screen rolls vertically | Wrong display mode | Check PAL/NTSC crystal; Agnus chip matches motherboard | +| Garbled display | Denise/Lisa failure | Check video output chip; RAM addressing | +| Audio noise/hum during boot | Paula or filter issue | Normal during init; persistent = check audio circuit | + +### DiagROM — Alternative Diagnostic ROM + +For machines that can't boot Kickstart, **DiagROM** (by Diagrom.com) is a replacement ROM that provides comprehensive hardware testing: + +- Tests CPU instructions and addressing modes +- Tests all Chip RAM with multiple patterns (march test, checkerboard) +- Tests custom chips individually (Agnus, Denise, Paula) +- Tests CIA timer accuracy +- Outputs diagnostics via serial port (for headless debugging) +- Tests keyboard, mouse, joystick +- Provides audio test tones + +> **For FPGA developers**: DiagROM is the gold standard for verifying your core's hardware implementation. If DiagROM passes all tests, your custom chip implementations are correct. + +--- + +## Step 6: ColdCapture / CoolCapture / WarmCapture + +Before and after ExecBase creation, the boot code checks three capture vectors. These are hooks that allow persistent code (memory-resident programs, hardware debuggers) to survive resets: + +| Vector | ExecBase Offset | When Called | Typical Use | +|---|---|---|---| +| `ColdCapture` | `$002A` | Before ExecBase init | Hardware debuggers (e.g., Action Replay), MMU setup | +| `CoolCapture` | `$002E` | After ExecBase init, before residents | Virus code (!), system patches, RAM disk preservation | +| `WarmCapture` | `$0032` | During warm reset (Ctrl-A-A) | Preserve state across resets | + +### How Captures Survive Reset + +Captures are stored in ExecBase, which is in Chip RAM. During a warm reset, the boot code: + +1. Reads the old ExecBase pointer from `$4` +2. Validates the old ExecBase (checksum `ChkBase` at offset `$26`) +3. If valid, reads `ColdCapture`/`CoolCapture`/`WarmCapture` from the old ExecBase +4. Calls them at the appropriate time + +During a **cold** reset (power cycle), RAM contents are undefined — captures are lost. But on a warm reset (Ctrl-Amiga-Amiga), RAM is preserved, so captures persist. + +```c +/* Typical ColdCapture installer (e.g., a trainer or freezer cartridge) */ +SysBase->ColdCapture = MyColdHandler; +SumKickData(); /* Update ExecBase checksums so it survives reset */ +``` + +> **Security note**: The `CoolCapture` vector was historically exploited by boot block viruses to survive warm resets. AntiVirus tools check this vector. --- ## ROM Layout -### 256 KB ROM (Kickstart 1.x) +### 256 KB ROM (Kickstart 1.2/1.3) ``` -$FC0000–$FFFFFF (256 KB) - $FC0000: Reset vectors (SSP + PC) - $FC0008: ROM header (version, checksum) - ... - $FC0020: First resident module (exec.library) - ... - $FFFFFC: Checksum complement word +$FC0000 ┌─────────────────────────┐ + │ Reset vectors (SSP, PC) │ 8 bytes +$FC0008 ├─────────────────────────┤ + │ ROM header │ 24 bytes + │ - version │ + │ - ROM size │ +$FC0020 ├─────────────────────────┤ + │ exec.library RomTag │ ← First resident module + ├─────────────────────────┤ + │ expansion.library │ + ├─────────────────────────┤ + │ ... more residents ... │ + ├─────────────────────────┤ + │ Boot code │ + ├─────────────────────────┤ + │ Diagnostic code │ + ├─────────────────────────┤ +$FFFFE8 │ Checksum complement │ 4 bytes +$FFFFFC │ ROM end marker │ 4 bytes +$FFFFFF └─────────────────────────┘ ``` -### 512 KB ROM (Kickstart 2.0+) +### 512 KB ROM (Kickstart 2.0–3.2) ``` -$F80000–$FFFFFF (512 KB) - $F80000: Reset vectors - $F80008: ROM header - ... - $F80020: exec.library resident tag - ... - $FFFFFC: Checksum complement +$F80000 ┌─────────────────────────┐ + │ Reset vectors (SSP, PC) │ 8 bytes +$F80008 ├─────────────────────────┤ + │ ROM header │ 24 bytes +$F80020 ├─────────────────────────┤ + │ exec.library RomTag │ ← First resident + ├─────────────────────────┤ + │ expansion.library │ + │ graphics.library │ + │ layers.library │ + │ intuition.library │ + │ dos.library │ + │ cia.resource │ + │ timer.device │ + │ keyboard.device │ + │ input.device │ + │ trackdisk.device │ + │ console.device │ + │ gameport.device │ + │ audio.device │ + │ ramlib │ + │ strap (bootstrap) │ + │ ... more ... │ + ├─────────────────────────┤ + │ Fonts (topaz 8/9) │ + ├─────────────────────────┤ +$FFFFF8 │ Checksum complement │ 4 bytes +$FFFFFC │ ROM end marker │ 4 bytes +$FFFFFF └─────────────────────────┘ ``` +### ROM Header + +```c +/* At ROM_BASE + 8 */ +struct RomHeader { + UWORD rh_Magic; /* $1114 or $1111 */ + UWORD rh_SizeKB; /* ROM size in KB (256 or 512) */ + UWORD rh_Flags; /* ROM type flags */ + UWORD rh_Version; /* Kickstart version */ + /* ... */ +}; +``` + +--- + +## Cold Boot vs Warm Reset + +| Aspect | Cold Boot (Power On) | Warm Reset (Ctrl-A-A) | +|---|---|---| +| RAM contents | Undefined (random) | Preserved | +| ColdCapture | Lost | Survives (if ExecBase valid) | +| CoolCapture | Lost | Survives | +| WarmCapture | Lost | Survives | +| ROM checksum | Always performed | Always performed | +| Memory detection | Full probe | May skip if ExecBase valid | +| Boot device | Highest priority | Highest priority | +| Timing | 3–8 seconds | 2–5 seconds | + +### Forcing a Cold Boot + +``` +Power cycle (turn off/on) → guaranteed cold start +Ctrl-A-A with both mouse buttons → invokes Early Startup Control +``` + +--- + +## Timing + +Approximate boot timing on a 7.09 MHz 68000 (A500): + +| Phase | Duration | Notes | +|---|---|---| +| Reset vector fetch | ~1 µs | Hardware | +| ROM checksum (256 KB) | ~300 ms | 64K longword additions | +| ROM checksum (512 KB) | ~600 ms | 128K longword additions | +| Hardware reset | ~5 ms | Register writes | +| Chip RAM detection | ~50 ms | Pattern tests | +| Expansion autoconfig | ~100 ms | Per-board | +| ExecBase creation | ~10 ms | Memory allocation + init | +| Resident scan | ~200 ms | ROM scan for $4AFC | +| Resident initialization | ~1–3 s | Library/device init | +| **Total to DOS prompt** | **~3–5 s** | A500 with floppy | +| **Total to Workbench** | **~5–8 s** | Including LoadWB | + +On a 68040/50 MHz (A4000): checksum is ~10× faster, total boot ~2–4 s to Workbench. + --- ## References +- Motorola: *MC68000 Family Programmer's Reference Manual* — reset processing - RKRM: *Hardware Reference Manual* — reset chapter +- NDK39: `exec/execbase.h` — ColdCapture, CoolCapture, WarmCapture fields +- See also: [Kickstart Init](kickstart_init.md) — ExecBase creation and resident module init +- See also: [Address Space](../01_hardware/common/address_space.md) — memory map diff --git a/02_boot_sequence/dos_boot.md b/02_boot_sequence/dos_boot.md index cf9e1f3..cc268fe 100644 --- a/02_boot_sequence/dos_boot.md +++ b/02_boot_sequence/dos_boot.md @@ -1,121 +1,451 @@ [← Home](../README.md) · [Boot Sequence](README.md) -# DOS Boot — Bootstrap, Mount List, Startup-Sequence +# DOS Boot — Bootstrap, Boot Block, Mount List, Startup-Sequence ## Overview -After the Kickstart ROM initialises the kernel and resident modules, `dos.library` takes over to mount filesystems and run the user's startup scripts. +After the Kickstart ROM initialises the kernel and resident modules, the `strap` (bootstrap) module takes over. It enumerates bootable devices, reads and executes the boot block, mounts filesystems, and runs the user's startup scripts. This phase transitions the system from "kernel initialized" to "fully running desktop." --- -## Boot Sequence Flow +## Architecture -``` -Kickstart ROM init complete - ↓ -dos.library creates initial CLI process - ↓ -BootStrap module (strap) reads boot block from boot device - ↓ -Boot block executed (OFS/FFS bootblock code) - ↓ -Mount configured devices from MountList (DEVS:DOSDrivers/) - ↓ -Execute S:Startup-Sequence - ↓ -Execute S:User-Startup - ↓ -LoadWB (start Workbench) +```mermaid +graph TB + subgraph "Phase 1: Device Enumeration" + STRAP["strap module
Priority -120"] + ENUM["Enumerate boot devices
Expansion boards + trackdisk"] + SORT["Sort by boot priority
(highest first)"] + end + + subgraph "Phase 2: Boot Block" + READ["Read sectors 0-1
from boot device"] + VALID["Validate:
DOS\\x magic + checksum"] + EXEC["Execute boot block code"] + end + + subgraph "Phase 3: DOS Init" + DOS["dos.library
creates initial CLI process"] + MOUNT["Mount devices
DEVS:DOSDrivers/"] + ASSIGN["SYS: = boot volume"] + end + + subgraph "Phase 4: User Scripts" + STARTUP["S:Startup-Sequence"] + USER["S:User-Startup"] + LOADWB["LoadWB
→ Workbench desktop"] + end + + STRAP --> ENUM + ENUM --> SORT + SORT --> READ + READ --> VALID + VALID -->|Valid| EXEC + VALID -->|Invalid| NEXT["Try next device"] + NEXT --> READ + EXEC --> DOS + DOS --> MOUNT + MOUNT --> ASSIGN + ASSIGN --> STARTUP + STARTUP --> USER + USER --> LOADWB + + style STRAP fill:#e8f4fd,stroke:#2196f3,color:#333 + style LOADWB fill:#e8f5e9,stroke:#4caf50,color:#333 ``` --- -## Boot Block Format +## Phase 1: The strap Module -The first 2 sectors (1024 bytes) of a bootable disk: +The `strap` module (bootstrap) is the last resident initialized by Kickstart. It bridges ROM init and disk boot: -``` -Offset Size Description -$000 4 Boot block ID: "DOS\0" (OFS), "DOS\1" (FFS), etc. -$004 4 Checksum (complement to zero) -$008 4 Root block pointer (usually 880) -$00C ... Boot code (up to 1012 bytes of 68000 code) +```c +/* strap pseudo-code: */ +void StrapInit(void) +{ + /* 1. Build list of bootable devices */ + struct BootNode *bootList = NULL; + + /* Check expansion boards (Zorro) for bootable devices */ + struct ConfigDev *cd = NULL; + while ((cd = FindConfigDev(cd, -1, -1)) != NULL) + { + if (cd->cd_Flags & CDF_BOOTABLE) + { + /* Add to boot list with priority from RDB */ + AddBootNode(cd->cd_BootPri, cd->cd_BootFlags, + cd->cd_DeviceNode, cd->cd_ConfigDev); + } + } + + /* Always add DF0: (trackdisk unit 0, boot priority 5) */ + AddBootNode(5, 0, df0_DeviceNode, NULL); + + /* 2. Sort boot list by priority (highest first) */ + SortBootNodes(&bootList); + + /* 3. Try each device in order */ + struct BootNode *bn; + for (bn = bootList; bn; bn = bn->bn_Next) + { + if (TryBootDevice(bn) == SUCCESS) + break; /* Booted successfully */ + } + + /* 4. If nothing bootable: "Insert Disk" screen */ + if (!bn) + ShowInsertDiskScreen(); +} ``` -### Boot Block Types +### Boot Priority -| ID | Hex | Type | +| Device | Default Priority | Source | |---|---|---| -| `DOS\0` | `444F5300` | OFS (Old File System) | -| `DOS\1` | `444F5301` | FFS (Fast File System) | -| `DOS\2` | `444F5302` | OFS + International | -| `DOS\3` | `444F5303` | FFS + International | -| `DOS\4` | `444F5304` | OFS + Dir Cache | -| `DOS\5` | `444F5305` | FFS + Dir Cache | -| `DOS\6` | `444F5306` | OFS + Long Filenames (OS 3.2) | -| `DOS\7` | `444F5307` | FFS + Long Filenames (OS 3.2) | +| DF0: | 5 | Hardcoded in trackdisk.device | +| DH0: | 0 | Set in RDB (Rigid Disk Block) partition table | +| DH1: | −5 | Set in RDB | +| DF1: | −10 | Hardcoded | +| CD0: | −20 | SCSI/IDE CD-ROM | ---- +Higher priority = tried first. A floppy in DF0: (pri 5) boots before a hard disk DH0: (pri 0) unless the hard disk partition has a higher boot priority set in HDToolBox. -## Boot Priority - -Devices are booted in priority order. Highest priority device boots first: - -| Device | Default Priority | Description | -|---|---|---| -| DF0: | 5 | First floppy drive | -| DH0: | 0 | First hard disk partition | -| DH1: | −5 | Second partition | -| DF1: | −10 | Second floppy | - -Set in mountlist: `BootPri = 0` or via HDToolBox. - ---- - -## Startup-Sequence - -Standard `S:Startup-Sequence` for OS 3.1: +### Changing Boot Priority ``` -C:SetPatch QUIET ; apply ROM patches -C:AddBuffers DH0: 50 ; filesystem buffers -C:Version >NIL: -FailAt 21 +; In HDToolBox: +; 1. Select partition → "Change..." → set Boot Priority +; 2. Priority > 5 = boots before floppy + +; From CLI (OS 3.1+): +1> Assign SYS: DH0: +; (Does not change boot priority — only the current session) +``` + +--- + +## Phase 2: Boot Block + +### Boot Block Format + +The first 2 sectors (1024 bytes total) of a bootable disk: + +``` +Offset Size Field Description +────────────────────────────────────────────────── +$000 4 DiskType "DOS\0" through "DOS\7" +$004 4 Checksum Ones' complement checksum of all 256 longwords +$008 4 RootBlock Root block number (usually 880 for DD floppy) +$00C 1012 BootCode 68000 machine code — entry point at $00C +``` + +### Disk Type Identifiers + +| ID Bytes | String | Hex | Filesystem | Features | +|---|---|---|---|---| +| `444F5300` | `DOS\0` | $00 | OFS | Original File System | +| `444F5301` | `DOS\1` | $01 | FFS | Fast File System | +| `444F5302` | `DOS\2` | $02 | OFS+I | OFS + International characters | +| `444F5303` | `DOS\3` | $03 | FFS+I | FFS + International characters | +| `444F5304` | `DOS\4` | $04 | OFS+DC | OFS + Directory Cache | +| `444F5305` | `DOS\5` | $05 | FFS+DC | FFS + Directory Cache | +| `444F5306` | `DOS\6` | $06 | OFS+LFN | OFS + Long Filenames (OS 3.2) | +| `444F5307` | `DOS\7` | $07 | FFS+LFN | FFS + Long Filenames (OS 3.2) | +| `4B49434B` | `KICK` | — | Kickstart disk | A1000 WCS boot floppy | +| Non-DOS | — | — | Custom | Game/demo custom bootblock | + +### Boot Block Checksum + +```c +/* Boot block checksum calculation */ +ULONG ComputeBootChecksum(ULONG *block) +{ + ULONG sum = 0; + ULONG saved = block[1]; /* Save current checksum */ + block[1] = 0; /* Clear for calculation */ + + for (int i = 0; i < 256; i++) /* 256 longwords = 1024 bytes */ + { + ULONG old = sum; + sum += block[i]; + if (sum < old) /* Carry */ + sum++; + } + + block[1] = saved; /* Restore */ + return ~sum; /* Ones' complement */ +} + +/* Verify: */ +if (ComputeBootChecksum(bootBlock) == bootBlock[1]) +{ + /* Checksum valid — execute boot code */ +} +``` + +### Boot Block Execution + +```c +/* The strap module loads sectors 0-1 into Chip RAM and calls the code: */ + +/* Entry conditions for boot block code: */ +/* A0 = pointer to boot block buffer in memory */ +/* A1 = pointer to IOStdReq used to read the boot block */ +/* A6 = SysBase (ExecBase) */ +/* D0 = 0 */ + +/* The boot block code typically: */ +/* 1. Finds dos.library */ +/* 2. Calls dos.library's boot entry point */ +/* Return value: 0 = success, non-zero = failure (try next device) */ +``` + +### Standard DOS Boot Block Code + +```asm +; Standard AmigaDOS boot block (abbreviated): +BootEntry: + LEA DosName(PC),A1 ; "dos.library" + JSR -96(A6) ; FindResident(A1) [exec LVO -96] + TST.L D0 + BEQ.S .fail + + MOVE.L D0,A0 + MOVE.L 22(A0),A0 ; rt_Init + MOVEQ #0,D0 + RTS ; Return to strap — which calls rt_Init + +.fail: + MOVEQ #-1,D0 + RTS + +DosName: + DC.B 'dos.library',0 + EVEN +``` + +### Custom Boot Blocks (Games/Demos) + +Games bypass the standard boot block to take full control of the hardware: + +```asm +; Typical game boot block: +BootEntry: + ; Disable interrupts and DMA + MOVE.W #$7FFF,$DFF09A ; INTENA = all off + MOVE.W #$7FFF,$DFF096 ; DMACON = all off + + ; Load the game's loader from disk + LEA $80000,A0 ; Destination in Chip RAM + MOVEQ #10,D0 ; Load 10 sectors + BSR ReadSectors ; Custom disk reading routine + + ; Jump to game code + JMP $80000 + +; The game now has full hardware control — no OS running +``` + +> **Note**: Non-DOS boot blocks are why some games don't work with hard disk installers — they expect to take over the hardware immediately. + +--- + +## Phase 3: DOS Initialization + +Once the standard boot block returns successfully, `dos.library` takes over: + +### Initial CLI Process + +```c +/* dos.library creates the initial CLI process: */ +/* 1. Create a Process (struct Process) — the "Initial CLI" */ +/* 2. Set up stdin/stdout to the boot console */ +/* 3. Set SYS: assign to the boot volume */ +/* 4. Set C:, S:, L:, LIBS:, DEVS:, FONTS: assigns */ +/* 5. Execute S:Startup-Sequence */ +``` + +### Mount List Processing + +Devices are mounted from two sources: + +#### DEVS:MountList (Legacy) + +``` +/* DEVS:MountList format (text file): */ +DH1: Handler = L:FastFileSystem + Priority = 5 + Stacksize = 4000 + GlobVec = -1 + BufMemType = 1 + Device = scsi.device + Unit = 1 + Flags = 0 + Surfaces = 4 + BlocksPerTrack = 63 + LowCyl = 200 + HighCyl = 400 + Buffers = 50 + BootPri = -5 + DosType = 0x444F5301 +# +``` + +#### DEVS:DOSDrivers/ (Modern — OS 2.0+) + +Each file in `DEVS:DOSDrivers/` is a mount specification for one device. These are auto-mounted at boot: + +``` +; DEVS:DOSDrivers/DH1 (icon file with tooltypes): +HANDLER = L:FastFileSystem +DEVICE = scsi.device +UNIT = 1 +FLAGS = 0 +SURFACES = 4 +BLOCKSPERTRACK = 63 +LOWCYL = 200 +HIGHCYL = 400 +BUFFERS = 50 +DOSTYPE = 0x444F5301 +BOOTPRI = -5 +STACKSIZE = 4000 +GLOBVEC = -1 +ACTIVATE = 1 +``` + +### System Assigns + +After mounting, the boot process sets up standard logical device assignments: + +| Assign | Points To | Purpose | +|---|---|---| +| `SYS:` | Boot volume root | System root | +| `C:` | `SYS:C` | System commands | +| `S:` | `SYS:S` | Scripts and startup files | +| `L:` | `SYS:L` | Handlers and loaders | +| `LIBS:` | `SYS:Libs` | Shared libraries | +| `DEVS:` | `SYS:Devs` | Device drivers and mount info | +| `FONTS:` | `SYS:Fonts` | System fonts | +| `T:` | `RAM:T` | Temporary files | +| `CLIPS:` | `RAM:Clipboards` | Clipboard data | +| `ENV:` | `RAM:ENV` | Environment variables (volatile) | +| `ENVARC:` | `SYS:Prefs/Env-Archive` | Env variables (persistent) | + +--- + +## Phase 4: Startup-Sequence + +### Standard Startup-Sequence (OS 3.1) + +``` +; S:Startup-Sequence — master boot script +; Executed by the initial CLI process + +C:SetPatch QUIET ; Apply ROM patches for this OS version +C:Version >NIL: ; Display version (redirected to NIL:) +FailAt 21 ; Don't abort on warnings (error level < 21) + +; Create RAM: directories MakeDir RAM:T RAM:Clipboards RAM:ENV RAM:ENV/Sys -Copy >NIL: ENVARC: RAM:ENV ALL NOREQ -Assign >NIL: T: RAM:T -Assign >NIL: CLIPS: RAM:Clipboards -Assign >NIL: REXX: S: -Assign >NIL: PRINTERS: DEVS:Printers -Assign >NIL: KEYMAPS: DEVS:Keymaps -Assign >NIL: LOCALE: SYS:Locale -Assign >NIL: LIBS: SYS:Classes ADD -Assign >NIL: HELP: LOCALE:Help DEFER +; Copy persistent environment to volatile RAM: +Copy >NIL: ENVARC: RAM:ENV ALL NOREQ + +; Set up logical assignments +Assign >NIL: T: RAM:T +Assign >NIL: CLIPS: RAM:Clipboards +Assign >NIL: REXX: S: +Assign >NIL: PRINTERS: DEVS:Printers +Assign >NIL: KEYMAPS: DEVS:Keymaps +Assign >NIL: LOCALE: SYS:Locale +Assign >NIL: LIBS: SYS:Classes ADD +Assign >NIL: HELP: LOCALE:Help DEFER + +; Initialize preferences C:IPrefs +; Start clipboard daemon ConClip >NIL: -; Launch Workbench: + +; Run user's custom startup +IF EXISTS S:User-Startup + Execute S:User-Startup +ENDIF + +; Launch Workbench LoadWB + +; End the initial CLI — Workbench takes over EndCLI >NIL: ``` +### Startup-Sequence Commands Explained + +| Command | Purpose | +|---|---| +| `SetPatch` | Patches known bugs in ROM libraries for this OS version | +| `FailAt 21` | Continue script even if commands return warning codes (1–20) | +| `Copy ENVARC: RAM:ENV` | Copy persistent prefs to fast volatile RAM for speed | +| `IPrefs` | Apply system preferences (screen mode, fonts, palette, input) | +| `ConClip` | Clipboard manager daemon — enables cut/paste between apps | +| `LoadWB` | Start Workbench — opens the desktop, mounts icons | +| `EndCLI` | Close the initial CLI window — Workbench is now primary UI | + +### User-Startup + +`S:User-Startup` is the user's personal script — runs after system init but before LoadWB: + +``` +; S:User-Startup — user customizations +Assign WORK: DH1: +Path SYS:Tools ADD +Path WORK:Bin ADD + +; Start background daemons +Run >NIL: C:CrossDOS +Run >NIL: C:PCTaskX + +; Load custom keymaps +SetKeyboard usa1 +``` + --- -## Early Startup Control (Boot Menu) +## Error Handling During Boot -Hold **both mouse buttons** during boot to access the Early Startup Control menu: +| Error | Symptom | Recovery | +|---|---|---| +| No bootable disk | "Insert Disk" animation | Insert bootable floppy in DF0: | +| Bad boot block checksum | Skips device, tries next | Fix boot block with `Install` command | +| dos.library not found | Guru Meditation | Corrupted ROM — reflash | +| Startup-Sequence error | CLI prompt with error message | Fix script manually | +| Assign to missing volume | "Please insert volume X" requester | Insert disk or skip | +| LoadWB fails | CLI remains visible | Check `SYS:System/Workbench` exists | -| Option | Description | -|---|---| -| Boot With No Startup-Sequence | Skip S:Startup-Sequence | -| Boot Standard | Normal boot | -| Boot With: [device list] | Select boot device | -| Display Mode: [NTSC/PAL] | Override display standard | +### Emergency Recovery + +``` +; Boot with no Startup-Sequence (hold both mouse buttons): +; → Early Startup Control → "Boot With No Startup-Sequence" +; → Get a CLI prompt with SYS: mounted + +; Fix corrupt startup: +1> ED S:Startup-Sequence + +; Reinstall boot block: +1> Install DF0: +; or for hard disk: +1> Install DH0: +``` --- ## References -- RKRM: Boot chapter -- NDK39: `dos/dosextens.h` — BootStrap +- NDK39: `dos/dosextens.h`, `dos/filehandler.h` +- ADCD 2.1: `BootStrap`, `AddBootNode`, `MakeDosEntry` +- See also: [Kickstart Init](kickstart_init.md) — what happens before strap +- See also: [Early Startup](early_startup.md) — boot menu options +- See also: [Filesystem](../07_dos/filesystem.md) — FFS/OFS block layout +- *Amiga ROM Kernel Reference Manual: Exec* — boot chapter diff --git a/02_boot_sequence/early_startup.md b/02_boot_sequence/early_startup.md index b73d4cd..eabf814 100644 --- a/02_boot_sequence/early_startup.md +++ b/02_boot_sequence/early_startup.md @@ -1,51 +1,246 @@ [← Home](../README.md) · [Boot Sequence](README.md) -# Early Startup Control — Boot Options +# Early Startup Control — Boot Menu, Display Mode, Recovery ## Overview -The **Early Startup Control** (ESC) menu appears when both mouse buttons are held during power-on or reset. It provides boot device selection, display mode override, and emergency recovery options. +The **Early Startup Control** (ESC) menu is a built-in boot manager available on all Amigas with Kickstart 2.0+. It provides boot device selection, display mode override, and emergency recovery options. It appears when both mouse buttons are held during the early boot phase — before the OS loads from disk. --- ## Activation -- **Both mouse buttons held** before the boot screen hand animation completes -- On A1200: hold both buttons during "floppy click" phase -- Requires Kickstart 2.0+ (not available on 1.3) +### How to Trigger + +Hold **both mouse buttons** (left + right) immediately after power-on or during the Ctrl-Amiga-Amiga reset sequence. The timing window is: + +| Kickstart | When to Hold | Visual Cue | +|---|---|---| +| 2.0–3.0 | During boot colour sequence | Before "Insert Disk" or disk activity | +| 3.1 | During the hand/checkmark animation | While the Amiga hand appears | +| 3.1.4 / 3.2 | Same as 3.1 | Same timing window | + +> **Tip**: Hold both buttons before powering on — this guarantees you catch the window. Release them once the menu appears. + +### Not Available On + +- Kickstart 1.2 / 1.3 (no boot menu feature) +- Any system where the ROM is corrupted (red screen before menu) +- Systems with custom boot ROMs that bypass standard init --- -## Menu Options (OS 3.1) +## Menu Layout + +### OS 3.1 Early Startup Control ``` -┌──────────────────────────────────┐ -│ EARLY STARTUP CONTROL │ -│ │ -│ Boot With No Startup-Sequence │ -│ Boot Standard │ -│ │ -│ Boot Device: │ -│ DF0: (pri 5) │ -│ DH0: (pri 0) │ -│ │ -│ Display Mode: │ -│ ● PAL ○ NTSC │ -│ │ -│ [BOOT] │ -└──────────────────────────────────┘ +╔══════════════════════════════════════════╗ +║ EARLY STARTUP CONTROL ║ +║ ║ +║ Boot Options: ║ +║ ○ Boot With No Startup-Sequence ║ +║ ● Boot Standard ║ +║ ║ +║ Boot Device: ║ +║ ● DF0: (pri 5) ║ +║ ○ DH0: (pri 0) ║ +║ ○ DH1: (pri -5) ║ +║ ║ +║ Display Mode: ║ +║ ● PAL ○ NTSC ║ +║ ║ +║ [ BOOT ] ║ +╚══════════════════════════════════════════╝ ``` +### OS 3.2 Early Startup Control + +OS 3.2 adds additional options: + +``` +╔══════════════════════════════════════════╗ +║ EARLY STARTUP CONTROL ║ +║ ║ +║ Boot Options: ║ +║ ○ Boot With No Startup-Sequence ║ +║ ● Boot Standard ║ +║ ○ Boot (Debug) ║ +║ ║ +║ Boot Device: ║ +║ ● DF0: (pri 5) ║ +║ ○ DH0: (pri 0) "System3.1" ║ +║ ○ DH1: (pri -5) "Work" ║ +║ ○ CD0: (pri -20) ║ +║ ║ +║ Display Mode: ║ +║ ○ PAL ○ NTSC ● Best Available ║ +║ ║ +║ ROM Modules: ║ +║ [x] Enable SetPatch ║ +║ [x] Enable 68040.library ║ +║ ║ +║ [ BOOT ] ║ +╚══════════════════════════════════════════╝ +``` + +--- + +## Menu Options + +### Boot Options + +| Option | Effect | +|---|---| +| **Boot Standard** | Normal boot — executes S:Startup-Sequence | +| **Boot With No Startup-Sequence** | Boots to a CLI prompt. S:Startup-Sequence is NOT executed. Assigns (SYS:, C:, etc.) are still set. | +| **Boot (Debug)** | (OS 3.2) Boots with debugging enabled — serial debug output, extended logging | + +### Boot Device Selection + +Lists all devices registered with `AddBootNode()`: + +- Floppy drives: DF0:, DF1: (always present if trackdisk.device loaded) +- Hard disk partitions: DH0:, DH1:, etc. (from RDB on SCSI/IDE) +- CD-ROM: CD0: (if device driver available) +- Network: (if SANA-II device registered as bootable) + +Select a device and click BOOT — the system uses that device as `SYS:` regardless of configured boot priority. + +### Display Mode + +| Option | Effect | +|---|---| +| **PAL** | Force PAL display (50 Hz, 283 visible lines) | +| **NTSC** | Force NTSC display (60 Hz, 241 visible lines) | +| **Best Available** | (OS 3.2) Auto-detect from hardware and monitor | + +> **Why this matters**: If someone changes the display mode to a setting their monitor can't sync to (e.g., PAL on an NTSC-only monitor), the screen goes blank. The ESC menu renders using the most basic display mode, so it's always visible — even when the configured mode is incompatible. + +--- + +## How It Works Internally + +### Detection + +```c +/* During boot, before strap runs: */ +/* intuition.library checks both mouse buttons via CIA-A/B port registers */ + +UBYTE ciaA_pra = ciaa.ciapra; /* CIA-A Port A — mouse button 1 (bit 6) */ +UBYTE potgor = custom.potgor; /* POT port — mouse button 2 (bit 10) */ + +BOOL leftButton = !(ciaA_pra & 0x40); /* Active low */ +BOOL rightButton = !(potgor & 0x0400); /* Active low */ + +if (leftButton && rightButton) +{ + /* Both buttons held — enter Early Startup Control */ + ShowBootMenu(); +} +``` + +### Display + +The ESC menu uses the lowest-level graphics possible: + +- Opens a 640×200 (or 640×256 PAL) 2-colour screen +- Uses the Topaz 8 ROM font (always available — no disk access needed) +- Renders using direct `RastPort` calls — no windows, no layers +- Mouse pointer uses hardware sprite 0 + +### Boot Menu Rendering Order + +1. `graphics.library` init completes → display hardware ready +2. `intuition.library` init completes → input handling ready +3. Check mouse buttons +4. If held: create the boot menu screen +5. Wait for user selection + BOOT button +6. Close screen, continue boot with selected options + --- ## Recovery Scenarios -| Scenario | Fix | -|---|---| -| Corrupted Startup-Sequence | Boot with No Startup-Sequence, then `ED S:Startup-Sequence` | -| Wrong display mode (no image) | Hold both buttons → change PAL/NTSC | -| Boot from floppy instead of HD | Select DF0: as boot device | -| Assign loops / infinite boot | No Startup-Sequence → fix assigns manually | +### Corrupted Startup-Sequence + +``` +Problem: System hangs during boot — bad script +Fix: + 1. Hold both mouse buttons → ESC menu + 2. Select "Boot With No Startup-Sequence" + 3. Boot → CLI prompt appears + 4. Edit the script: ED S:Startup-Sequence + 5. Reboot normally +``` + +### Wrong Display Mode (No Picture) + +``` +Problem: Changed to PAL on NTSC monitor (or vice versa) — screen blank +Fix: + 1. Power off + 2. Hold both mouse buttons, power on + 3. ESC menu appears (uses safe display mode) + 4. Select correct display mode (PAL/NTSC) + 5. Click BOOT +``` + +### Boot from Floppy Instead of Hard Disk + +``` +Problem: Hard disk is corrupted, need to boot from floppy +Fix: + 1. Insert bootable Workbench floppy in DF0: + 2. Hold both mouse buttons during boot + 3. Select DF0: as boot device + 4. Click BOOT + 5. System boots from floppy — hard disk accessible as DH0: +``` + +### Assign Loops / Infinite Requester + +``` +Problem: Startup-Sequence has an Assign to a missing volume + → "Please insert volume X" in infinite loop +Fix: + 1. ESC menu → "Boot With No Startup-Sequence" + 2. Fix the Assign in S:Startup-Sequence + 3. Or: Add NOREQ flag to the problematic Assign + Assign >NIL: WORK: DH1: +``` + +### Hard Disk Not Appearing in Boot Menu + +``` +Problem: DH0: doesn't show in the ESC boot device list +Possible causes: + 1. IDE/SCSI device not detected — check cables + 2. No valid RDB (Rigid Disk Block) — use HDToolBox + 3. Boot priority not set — use HDToolBox to set BootPri + 4. Partition table corrupt — try mounting from floppy boot +``` + +### Testing Multiple OS Versions + +``` +Scenario: Two OS versions on different partitions + 1. Install OS 3.1 on DH0: (BootPri 0) + 2. Install OS 3.2 on DH1: (BootPri -5) + 3. Normal boot → DH0: (OS 3.1) + 4. ESC menu → select DH1: → boots OS 3.2 + 5. Or: change BootPri in HDToolBox to swap default +``` + +--- + +## Keyboard Alternative + +On Amiga 1000 (no right mouse button connector) or when mouse is unavailable: + +- Some A1000 models use a key combination instead of mouse buttons +- External button boxes connected to the joystick port can substitute +- DiagROM provides keyboard-driven boot menu alternatives --- @@ -53,3 +248,6 @@ The **Early Startup Control** (ESC) menu appears when both mouse buttons are hel - RKRM: Early Startup chapter - OS 3.1 AmigaGuide: `System/BootMenu` +- OS 3.2 Release Notes: new ESC menu options +- See also: [DOS Boot](dos_boot.md) — what happens after device selection +- See also: [Cold Boot](cold_boot.md) — hardware init before ESC menu diff --git a/02_boot_sequence/kickstart_init.md b/02_boot_sequence/kickstart_init.md index 8681bbd..4916c71 100644 --- a/02_boot_sequence/kickstart_init.md +++ b/02_boot_sequence/kickstart_init.md @@ -1,104 +1,406 @@ [← Home](../README.md) · [Boot Sequence](README.md) -# Kickstart Initialisation — ROM Scan, ExecBase, Resident Modules +# Kickstart Initialisation — ExecBase, ROM Scan, Resident Modules ## Overview -After hardware init, the Kickstart ROM creates `ExecBase` and scans for **resident modules** — the OS components compiled into ROM. This process builds the entire OS kernel from tagged structures embedded in the ROM image. +After hardware init and ROM checksum pass, the Kickstart ROM creates `ExecBase` and scans for **resident modules** — the OS components embedded in ROM. This process builds the entire OS kernel from tagged structures in the ROM image, progressing through three initialization phases before handing control to the bootstrap module. + +--- + +## Architecture + +```mermaid +graph TB + subgraph "Phase 0: Pre-Exec" + HW["Hardware Init Complete
DMA off, interrupts off"] + EXEC_ALLOC["Allocate ExecBase
at top of Chip RAM"] + EXEC_INIT["Initialize ExecBase
MemList, LibList, TaskReady,
TaskWait, interrupt vectors"] + SYSBASE["Store pointer at $4
*(ULONG*)4 = SysBase"] + end + + subgraph "Phase 1: Capture Vectors" + COLD["ColdCapture
(offset $2A)"] + COOL["CoolCapture
(offset $2E)"] + end + + subgraph "Phase 2: ROM Scan" + SCAN["Scan ROM for $4AFC
Build ResModules table"] + SORT["Sort by rt_Pri
(highest first)"] + end + + subgraph "Phase 3: Module Init" + SINGLE["RTF_SINGLETASK
exec, expansion"] + COLDST["RTF_COLDSTART
graphics → dos"] + MULTI["Enable Multitasking
Scheduler starts"] + AFTER["RTF_AFTERDOS
disk-based modules"] + end + + HW --> EXEC_ALLOC + EXEC_ALLOC --> EXEC_INIT + EXEC_INIT --> SYSBASE + SYSBASE --> COLD + COLD --> COOL + COOL --> SCAN + SCAN --> SORT + SORT --> SINGLE + SINGLE --> COLDST + COLDST --> MULTI + MULTI --> AFTER + + style EXEC_ALLOC fill:#e8f4fd,stroke:#2196f3,color:#333 + style MULTI fill:#e8f5e9,stroke:#4caf50,color:#333 +``` --- ## ExecBase Creation -1. Allocate ExecBase structure at a known address (end of Chip RAM) -2. Initialise memory lists, library list, device list, resource list -3. Store ExecBase pointer at **address `$000004`** — the global `SysBase` -4. Initialise the Supervisor stack, interrupt vectors, trap vectors +### Memory Allocation + +ExecBase is allocated at the **top of Chip RAM**, below the supervisor stack: ``` -After this step: - *(ULONG *)4 == ExecBase pointer - SysBase->LibNode.lib_Version == Kickstart version +Top of Chip RAM (e.g., $200000 for 2 MB): + ┌─────────────────────┐ $1FFFFF + │ Supervisor Stack │ ~1 KB + ├─────────────────────┤ + │ ExecBase │ ~632 bytes (struct ExecBase) + ├─────────────────────┤ + │ exec.library JMP tbl│ ~1.5 KB (negative offsets) + ├─────────────────────┤ + │ Interrupt vectors │ saved copies of $000–$400 + ├─────────────────────┤ + │ Available Chip RAM │ + │ (for AllocMem) │ + └─────────────────────┘ $000000 +``` + +### Initialization Sequence + +```c +/* Pseudo-code — what the ROM boot code does: */ + +/* 1. Determine Chip RAM size */ +ULONG chipSize = ProbeChipRAM(); /* 256K, 512K, 1M, or 2M */ + +/* 2. Allocate ExecBase at top of Chip RAM */ +APTR execBase = (APTR)(chipSize - EXECBASE_SIZE - SSP_SIZE); + +/* 3. Clear ExecBase to zero */ +memset(execBase, 0, EXECBASE_SIZE); + +/* 4. Initialize the Library header */ +execBase->LibNode.lib_Node.ln_Type = NT_LIBRARY; +execBase->LibNode.lib_Node.ln_Name = "exec.library"; +execBase->LibNode.lib_Version = 40; /* Kickstart 3.1 */ +execBase->LibNode.lib_Revision = 70; + +/* 5. Initialize system lists */ +NewList(&execBase->MemList); +NewList(&execBase->LibList); +NewList(&execBase->DeviceList); +NewList(&execBase->ResourceList); +NewList(&execBase->IntrList); +NewList(&execBase->PortList); +NewList(&execBase->SemaphoreList); +NewList(&execBase->TaskReady); +NewList(&execBase->TaskWait); + +/* 6. Set up memory — add Chip RAM as first memory region */ +AddMemList(chipSize - RESERVED_TOP, + MEMF_CHIP | MEMF_PUBLIC | MEMF_LOCAL, + 0, /* priority 0 */ + (APTR)0, /* starts at address 0 */ + "chip memory"); + +/* 7. Initialize nesting counters */ +execBase->IDNestCnt = -1; /* Interrupts enabled */ +execBase->TDNestCnt = -1; /* Task switching enabled */ + +/* 8. Set Quantum */ +execBase->Quantum = 4; /* 4 ticks = ~80 ms at 50 Hz */ + +/* 9. Detect CPU type */ +execBase->AttnFlags = ProbeCPU(); /* Test for 010/020/030/040/060/FPU */ + +/* 10. Set VBlank frequency */ +execBase->VBlankFrequency = IsPAL() ? 50 : 60; +execBase->PowerSupplyFrequency = IsPAL() ? 50 : 60; + +/* 11. Install exception vectors */ +InstallExceptionVectors(execBase); + +/* 12. Store ExecBase pointer at absolute address $4 */ +*(ULONG *)4 = (ULONG)execBase; + +/* 13. Add exec.library to LibList */ +AddLibrary((struct Library *)execBase); +``` + +### ExecBase Validation (Warm Reset) + +On warm reset, the boot code checks if a valid ExecBase already exists: + +```c +/* Read candidate from $4 */ +struct ExecBase *old = *(struct ExecBase **)4; + +/* Validate using ChkBase checksum */ +ULONG sum = 0; +UWORD *p = (UWORD *)&old->SoftVer; +for (int i = 0; i < (offsetof(ExecBase, ChkSum) - offsetof(ExecBase, SoftVer)) / 2; i++) + sum += *p++; + +if (sum == 0xFFFF) /* Valid checksum */ +{ + /* ExecBase survived reset — preserve ColdCapture, etc. */ + coldCapture = old->ColdCapture; + coolCapture = old->CoolCapture; + warmCapture = old->WarmCapture; + kickMemPtr = old->KickMemPtr; + kickTagPtr = old->KickTagPtr; +} +``` + +--- + +## Capture Vector Processing + +### ColdCapture ($002A) + +Called very early — before ExecBase is fully initialized: + +```c +if (coldCapture) +{ + /* Jump to capture code in supervisor mode */ + /* The capture code MUST return to continue boot */ + ((void (*)(void))coldCapture)(); +} +``` + +**Use cases**: Action Replay / HRTmon cartridges, MMU pre-initialization, hardware debugger setup. + +### CoolCapture ($002E) + +Called after ExecBase is initialized, before resident modules: + +```c +if (coolCapture) +{ + ((void (*)(void))coolCapture)(); +} +``` + +**Use cases**: System patches that must load before libraries, memory-resident disk preservation, virus persistence (historically exploited). + +### WarmCapture ($0032) + +Called only during warm reset (Ctrl-Amiga-Amiga): + +```c +if (warmCapture && isWarmReset) +{ + ((void (*)(void))warmCapture)(); +} +``` + +**Use cases**: Preserving application state across resets. + +### KickTagPtr / KickMemPtr — Resident Extensions + +These fields allow modules loaded into RAM to survive warm resets: + +```c +/* KickTagPtr points to an array of Resident pointers in RAM */ +/* KickMemPtr points to MemList entries that must be preserved */ + +/* Used by: */ +/* - SetPatch (patches modules in RAM) */ +/* - RAD: (recoverable RAM disk) */ +/* - Memory-resident applications */ ``` --- ## Resident Module Scan -The ROM scanner searches for **RomTag** markers (`$4AFC`) throughout the ROM address range: - -```c -struct Resident { - UWORD rt_MatchWord; /* $4AFC — magic marker */ - struct Resident *rt_MatchTag; /* pointer to self (verification) */ - APTR rt_EndSkip; /* skip past this address */ - UBYTE rt_Flags; /* RTF_COLDSTART, RTF_SINGLETASK, etc. */ - UBYTE rt_Version; /* version number */ - UBYTE rt_Type; /* NT_LIBRARY, NT_DEVICE, NT_RESOURCE */ - BYTE rt_Pri; /* init priority (higher = earlier) */ - char *rt_Name; /* module name */ - char *rt_IdString; /* version string */ - APTR rt_Init; /* init function or auto-init table */ -}; -``` - ### Scan Algorithm +```c +/* The ROM scanner searches for RomTag markers */ +struct Resident **resTable = AllocMem(MAX_RESIDENTS * sizeof(APTR), MEMF_CLEAR); +int count = 0; + +UWORD *addr = (UWORD *)ROM_BASE; +UWORD *romEnd = (UWORD *)(ROM_BASE + ROM_SIZE); + +while (addr < romEnd) +{ + if (*addr == 0x4AFC) /* RomTag magic */ + { + struct Resident *res = (struct Resident *)addr; + + /* Verify self-pointer */ + if (res->rt_MatchTag == res) + { + resTable[count++] = res; + /* Skip past this module */ + addr = (UWORD *)res->rt_EndSkip; + continue; + } + } + addr++; /* Next word (must be word-aligned) */ +} + +/* Also scan KickTagPtr list (RAM-resident modules from previous boot) */ +if (SysBase->KickTagPtr) +{ + struct Resident **kt = (struct Resident **)SysBase->KickTagPtr; + while (*kt) + { + if ((ULONG)*kt & 0x80000000) + { + /* Bit 31 set = pointer to another KickTag array (chaining) */ + kt = (struct Resident **)((ULONG)*kt & 0x7FFFFFFF); + continue; + } + resTable[count++] = *kt++; + } +} + +/* Store table in ExecBase */ +SysBase->ResModules = resTable; ``` -for addr in ROM_START to ROM_END step 2: - if *(UWORD *)addr == $4AFC: - tag = (struct Resident *)addr - if tag->rt_MatchTag == tag: /* self-pointer validates */ - add to resident list - addr = tag->rt_EndSkip /* skip past module */ + +### Sorting + +After scanning, modules are sorted by `rt_Pri` (descending). Higher priority = initialized first: + +``` +Priority 126: exec.library ← First +Priority 120: expansion.library +Priority 105: 68040.library +Priority 100: utility.library +... +Priority -50: dos.library +Priority -120: ramlib / strap ← Last ``` --- ## Initialisation Phases -Residents are initialised in **priority order** within each phase: +### Phase 1: RTF_SINGLETASK -### Phase 1: RTF_COLDSTART (flags bit 0) +Before multitasking starts. Only the boot task exists: -Called during cold boot, single-tasking (no scheduler yet): +```c +for (int i = 0; i < count; i++) +{ + if (resTable[i]->rt_Flags & RTF_SINGLETASK) + { + InitResident(resTable[i], NULL); + } +} +``` -| Priority | Module | Description | +| Priority | Module | What It Does | |---|---|---| -| 126 | `exec.library` | Core kernel | -| 120 | `expansion.library` | AutoConfig Zorro boards | -| 105 | `68040.library` | CPU trap handlers (if present) | -| 100 | `utility.library` | Tag/hook support | -| 70 | `graphics.library` | Display init | -| 50 | `layers.library` | Clipping layers | -| 50 | `intuition.library` | GUI subsystem | -| 40 | `timer.device` | Timing services | -| 30 | `keyboard.device` | Keyboard | -| 20 | `input.device` | Input event merging | -| 10 | `trackdisk.device` | Floppy | -| −50 | `dos.library` | AmigaDOS file system | -| −120 | `ramlib` | Disk-based library/device loader | +| 126 | exec.library | Already running — just builds JMP table | +| 120 | expansion.library | Scans Zorro bus, configures Autoconfig boards, adds RAM | -### Phase 2: RTF_SINGLETASK +### Phase 2: RTF_COLDSTART -Runs after all COLDSTART modules but before multitasking begins. Used by strap (bootstrap) module. +The bulk of the OS. Still single-task context: -### Phase 3: RTF_AFTERDOS +| Priority | Module | What It Does | +|---|---|---| +| 105 | 68040.library | Installs Line-F trap handler for FPU instruction emulation | +| 100 | utility.library | TagItem parsing, hooks, date/time | +| 96 | mathieeesingbas.library | IEEE single-precision math | +| 70 | graphics.library | Initializes chipset, builds display, allocates bitmaps | +| 60 | layers.library | Window clipping layer system | +| 55 | cia.resource | CIA chip interrupt management | +| 50 | intuition.library | GUI subsystem, screen/window management | +| 40 | timer.device | VBLANK and ECLOCK timer services | +| 35 | keyboard.device | Keyboard serial protocol handler | +| 30 | gameport.device | Mouse and joystick input | +| 20 | input.device | Merges keyboard/mouse events into input stream | +| 10 | trackdisk.device | Floppy disk controller — motor, read/write, MFM | +| 5 | audio.device | DMA audio channel allocation | +| 0 | console.device | Text console — escape sequences, cursor | +| −50 | dos.library | File system, CLI, process management | +| −50 | filesystem (FFS) | Fast File System handler | +| −120 | ramlib | Loads disk-based libraries/devices on demand | -Runs after DOS is available. External disk-based modules. +### Phase 3: Enable Multitasking + +After all COLDSTART modules are initialized: + +```c +/* The boot task becomes the first schedulable task */ +/* TDNestCnt transitions from -1 (disabled) to -1 (enabled, unnested) */ +/* The scheduler begins running at the next VBL interrupt */ +``` + +### Phase 4: RTF_AFTERDOS + +Modules that require DOS (file access): + +```c +for (int i = 0; i < count; i++) +{ + if (resTable[i]->rt_Flags & RTF_AFTERDOS) + { + InitResident(resTable[i], NULL); + } +} +``` + +Typically: disk-based fonts, locale, workbench.library. --- -## After Resident Init +## Bootstrap (strap) Module -1. Multitasking enabled (scheduler starts) -2. `dos.library` creates initial CLI process -3. Boot task launches `strap` → reads boot block from DF0: or boot device -4. Control passes to `startup-sequence` +The `strap` module is the last thing Kickstart initializes. It bridges the gap between ROM init and the disk-based boot: + +```c +/* strap module: */ +/* 1. Enumerate bootable devices (from expansion boards + trackdisk) */ +/* 2. Sort by boot priority */ +/* 3. Read boot block (sectors 0-1) from highest-priority device */ +/* 4. Validate boot block checksum */ +/* 5. Execute boot block code — which typically calls dos.library */ +/* 6. dos.library runs S:Startup-Sequence */ +``` + +See [DOS Boot](dos_boot.md) for the complete boot block and startup-sequence flow. + +--- + +## Timing Reference + +| Phase | A500 (7 MHz) | A1200 (14 MHz) | A4000/040 (25 MHz) | +|---|---|---|---| +| ExecBase creation | ~10 ms | ~5 ms | ~2 ms | +| ROM scan ($4AFC) | ~200 ms | ~100 ms | ~30 ms | +| expansion.library init | ~100 ms | ~50 ms | ~20 ms | +| graphics.library init | ~300 ms | ~150 ms | ~60 ms | +| intuition.library init | ~200 ms | ~100 ms | ~40 ms | +| dos.library init | ~100 ms | ~50 ms | ~20 ms | +| **Total to strap** | **~1.5 s** | **~700 ms** | **~300 ms** | --- ## References -- NDK39: `exec/resident.h` -- RKRM: Resident modules chapter +- NDK39: `exec/resident.h`, `exec/execbase.h` +- ADCD 2.1: `InitResident`, `FindResident`, `AddLibrary` +- See also: [Cold Boot](cold_boot.md) — hardware init before this phase +- See also: [ExecBase](../06_exec_os/exec_base.md) — structure reference +- See also: [Resident Modules](../06_exec_os/resident_modules.md) — RomTag structure +- See also: [Kickstart ROM](kickstart_rom.md) — ROM binary format and module layout +- *Amiga ROM Kernel Reference Manual: Exec* — initialization chapter diff --git a/02_boot_sequence/kickstart_rom.md b/02_boot_sequence/kickstart_rom.md new file mode 100644 index 0000000..a4b0cfc --- /dev/null +++ b/02_boot_sequence/kickstart_rom.md @@ -0,0 +1,446 @@ +[← Home](../README.md) · [Boot Sequence](README.md) + +# Kickstart ROM — Internal Structure, Module Layout, Custom ROMs + +## Overview + +The Kickstart ROM is a single binary image containing the entire AmigaOS kernel — exec.library, graphics.library, dos.library, device drivers, system resources, and boot code. Understanding its internal structure is essential for ROM modding, FPGA core development, and reverse engineering. This document covers the binary layout, how modules are organized, how to extract and rebuild ROMs, and how to create custom Kickstart images. + +--- + +## ROM Types + +| Kickstart | Size | Base Address | Models | ROM Chips | +|---|---|---|---|---| +| 1.0–1.1 | 256 KB | `$FC0000` | A1000 (WCS) | 2× 128 KB | +| 1.2 | 256 KB | `$FC0000` | A500 (early), A2000 | 2× 128 KB | +| 1.3 | 256 KB | `$FC0000` | A500, A2000 | 2× 128 KB (27C010) | +| 2.04 | 512 KB | `$F80000` | A500+ | 2× 256 KB (27C020) | +| 2.05 | 512 KB | `$F80000` | A600 | 1× 512 KB (27C040) | +| 3.0 | 512 KB | `$F80000` | A1200, A4000 | 1× 512 KB (27C040) | +| 3.1 | 512 KB | `$F80000` | All models | 1× 512 KB or 2× 256 KB | +| 3.1.4 | 512 KB | `$F80000` | All models | 1× 512 KB | +| 3.2 | 512 KB | `$F80000` | All models | 1× 512 KB | +| CD32 ext | 512 KB | `$E00000` | CD32 | Extension ROM bank | + +--- + +## Binary Structure + +### Memory Layout (512 KB Kickstart) + +``` +$F80000 ┌──────────────────────────────────┐ + │ Reset Vectors (8 bytes) │ + │ $F80000: Initial SSP ($000400) │ + │ $F80004: Initial PC │ +$F80008 ├──────────────────────────────────┤ + │ ROM Header (16 bytes) │ + │ Magic word ($1114 or $1111) │ + │ ROM size in KB (512) │ + │ Flags / version info │ +$F80018 ├──────────────────────────────────┤ + │ Boot Code │ + │ Hardware init │ + │ ROM checksum │ + │ Memory detection │ + │ OVL clear │ + ├──────────────────────────────────┤ + │ Resident Module Area │ + │ ┌────────────────────────────┐ │ + │ │ exec.library │ │ + │ │ RomTag ($4AFC) │ │ + │ │ Code + data │ │ + │ ├────────────────────────────┤ │ + │ │ expansion.library │ │ + │ ├────────────────────────────┤ │ + │ │ graphics.library │ │ + │ ├────────────────────────────┤ │ + │ │ layers.library │ │ + │ ├────────────────────────────┤ │ + │ │ intuition.library │ │ + │ ├────────────────────────────┤ │ + │ │ dos.library │ │ + │ ├────────────────────────────┤ │ + │ │ ... more modules ... │ │ + │ └────────────────────────────┘ │ + ├──────────────────────────────────┤ + │ System Fonts │ + │ Topaz 8, Topaz 9 │ + ├──────────────────────────────────┤ + │ Resident Module Pointer Table │ + │ (Array of pointers to RomTags) │ + ├──────────────────────────────────┤ + │ Exec ROM Entry (boot entry point)│ + ├──────────────────────────────────┤ +$FFFFF8 │ Checksum Complement (4 bytes) │ +$FFFFFC │ ROM End Marker (4 bytes) │ +$FFFFFF └──────────────────────────────────┘ +``` + +### ROM Header + +```c +/* At ROM_BASE + 8 */ +struct KickstartHeader { + UWORD kh_Magic; /* $1114 (512KB) or $1111 (256KB) */ + UWORD kh_SizeKB; /* ROM size / 1024 */ + ULONG kh_Flags; /* ROM type flags */ + UWORD kh_Version; /* Major.Minor */ + UWORD kh_Revision; /* Revision number */ +}; +``` + +| Magic | Meaning | +|---|---| +| `$1111` | 256 KB ROM (Kickstart 1.x) | +| `$1114` | 512 KB ROM (Kickstart 2.0+) | + +### Checksum Complement + +The checksum complement is located at a fixed offset near the end of the ROM: + +| ROM Size | Complement Offset | Absolute Address | +|---|---|---| +| 256 KB | `$3FFE8` | `$FFFFE8` | +| 512 KB | `$7FFE8` | `$FFFFE8` | + +--- + +## Resident Module Layout + +Modules are packed sequentially in the ROM. Each module starts with a RomTag (`$4AFC`): + +``` +Module N: + ┌─────────────────────────┐ + │ RomTag ($4AFC) │ 26 bytes + │ rt_MatchWord = $4AFC │ + │ rt_MatchTag → self │ + │ rt_EndSkip → past end │ + │ rt_Flags, rt_Version │ + │ rt_Type, rt_Pri │ + │ rt_Name → name string │ + │ rt_IdString → ID │ + │ rt_Init → init func │ + ├─────────────────────────┤ + │ Function Code │ Variable size + │ Library functions │ + │ Internal routines │ + ├─────────────────────────┤ + │ Data / Constants │ + │ String tables │ + │ Default values │ + ├─────────────────────────┤ + │ Name String │ "exec.library\0" + │ ID String │ "exec 40.70 (16.7.93)\r\n\0" + └─────────────────────────┘ + ← rt_EndSkip points here +``` + +### Kickstart 3.1 (40.068) Module Inventory + +| Module | Type | Size (approx) | Init Priority | +|---|---|---|---| +| exec.library | `NT_LIBRARY` | ~48 KB | 126 | +| expansion.library | `NT_LIBRARY` | ~8 KB | 120 | +| 68040.library | `NT_LIBRARY` | ~12 KB | 105 | +| utility.library | `NT_LIBRARY` | ~6 KB | 100 | +| mathieeesingbas.library | `NT_LIBRARY` | ~2 KB | 96 | +| alib (private) | `NT_LIBRARY` | ~1 KB | 80 | +| graphics.library | `NT_LIBRARY` | ~80 KB | 70 | +| layers.library | `NT_LIBRARY` | ~14 KB | 60 | +| cia.resource | `NT_RESOURCE` | ~3 KB | 55 | +| potgo.resource | `NT_RESOURCE` | ~1 KB | 52 | +| misc.resource | `NT_RESOURCE` | ~1 KB | 50 | +| intuition.library | `NT_LIBRARY` | ~70 KB | 50 | +| timer.device | `NT_DEVICE` | ~4 KB | 40 | +| keyboard.device | `NT_DEVICE` | ~4 KB | 35 | +| gameport.device | `NT_DEVICE` | ~3 KB | 30 | +| input.device | `NT_DEVICE` | ~6 KB | 20 | +| trackdisk.device | `NT_DEVICE` | ~14 KB | 10 | +| carddisk.device | `NT_DEVICE` | ~4 KB | 5 | +| audio.device | `NT_DEVICE` | ~6 KB | 5 | +| console.device | `NT_DEVICE` | ~22 KB | 0 | +| dos.library | `NT_LIBRARY` | ~50 KB | −50 | +| filesystem (FFS) | handler | ~18 KB | −50 | +| ramlib | module | ~4 KB | −120 | +| strap (bootstrap) | module | ~4 KB | −120 | +| **Total** | | **~400 KB** | | + +The remaining ~112 KB contains fonts, boot code, ROM entry, padding, and the checksum. + +--- + +## Extracting Modules from a ROM + +### Using Python (romtool from amitools) + +```bash +# Install amitools +pip install amitools + +# List all modules in a ROM: +romtool list kick31.rom +# Output: +# 0: exec.library V40.70 pri=126 flags=COLDSTART +# 1: expansion.library V40.2 pri=120 flags=COLDSTART +# ... + +# Extract (split) all modules: +romtool split kick31.rom output_dir/ +# Creates individual module files + index.txt + +# Show ROM info: +romtool info kick31.rom +# Output: +# Size: 524288 (512 KB) +# Header: $1114 +# Checksum: OK ($FFFFFFFF) +# Version: 40.068 +``` + +### Using Manual Scanning + +```python +#!/usr/bin/env python3 +"""Scan a Kickstart ROM for resident modules""" +import struct + +def scan_rom(filename): + with open(filename, 'rb') as f: + data = f.read() + + rom_base = 0xF80000 if len(data) == 524288 else 0xFC0000 + + offset = 0 + while offset < len(data) - 26: + # Look for RomTag magic word $4AFC + word = struct.unpack('>H', data[offset:offset+2])[0] + if word == 0x4AFC: + # Read rt_MatchTag (self-pointer) + match_tag = struct.unpack('>I', data[offset+2:offset+6])[0] + expected = rom_base + offset + + if match_tag == expected: + # Valid RomTag — extract fields + end_skip = struct.unpack('>I', data[offset+6:offset+10])[0] + flags = data[offset+10] + version = data[offset+11] + rt_type = data[offset+12] + pri = struct.unpack('>b', bytes([data[offset+13]]))[0] + name_ptr = struct.unpack('>I', data[offset+14:offset+18])[0] + id_ptr = struct.unpack('>I', data[offset+18:offset+22])[0] + + # Read name string + name_off = name_ptr - rom_base + name = data[name_off:data.index(0, name_off)].decode('ascii') + + print(f" ${rom_base+offset:08X}: {name:30s} V{version} pri={pri:4d}") + + # Skip to end of this module + offset = end_skip - rom_base + continue + + offset += 2 # Must be word-aligned + +scan_rom('kick31.rom') +``` + +### Dumping from Real Hardware + +``` +; On a real Amiga — dump ROM to disk: +; Using transrom: +1> transrom >RAM:kick.rom + +; Or via shell: +1> C:Copy ROM: RAM:kick.rom + +; The ROM: device provides direct access to the Kickstart ROM image +``` + +--- + +## Building Custom Kickstart ROMs + +### Using romtool (amitools) + +```bash +# Start with extracted modules: +romtool split kick31.rom modules/ + +# Edit index.txt to add/remove/reorder modules +# Replace a module: +cp my_patched_dos.library modules/dos.library + +# Rebuild: +romtool build modules/ custom_kick.rom +# romtool automatically: +# 1. Packs all modules sequentially +# 2. Builds the ResModules pointer table +# 3. Calculates and inserts checksum complement +# 4. Verifies the final image + +# Verify: +romtool info custom_kick.rom +``` + +### Using Remus (Amiga-native) + +Remus is a GUI-based Kickstart editor: + +1. Load a base ROM image +2. Drag modules between ROM images +3. Replace individual modules with patched versions +4. Click "Build" — handles packing, alignment, checksum +5. Save the result and burn to EPROM + +### Manual ROM Assembly + +```python +#!/usr/bin/env python3 +"""Minimal ROM builder — calculates checksum""" +import struct + +def build_rom(modules, rom_size=524288): + rom = bytearray(rom_size) + rom_base = 0xF80000 if rom_size == 524288 else 0xFC0000 + + # 1. Write reset vectors + struct.pack_into('>I', rom, 0, 0x00000400) # Initial SSP + struct.pack_into('>I', rom, 4, rom_base + 0x0008) # Initial PC + + # 2. Write ROM header + struct.pack_into('>H', rom, 8, 0x1114) # Magic (512KB) + struct.pack_into('>H', rom, 10, rom_size // 1024) + + # 3. Pack modules starting at offset $20 + offset = 0x20 + for mod_data in modules: + rom[offset:offset+len(mod_data)] = mod_data + offset += len(mod_data) + # Align to word boundary + if offset & 1: + offset += 1 + + # 4. Calculate checksum complement + checksum = 0 + # Clear complement location first + ck_offset = rom_size - 24 + struct.pack_into('>I', rom, ck_offset, 0) + + for i in range(0, rom_size, 4): + val = struct.unpack('>I', rom[i:i+4])[0] + checksum = (checksum + val) & 0xFFFFFFFF + if checksum < val: # Carry + checksum = (checksum + 1) & 0xFFFFFFFF + + complement = (0xFFFFFFFF - checksum) & 0xFFFFFFFF + struct.pack_into('>I', rom, ck_offset, complement) + + return bytes(rom) +``` + +--- + +## ROM Variants and Extensions + +### Extended ROMs (CD32, A4000T) + +Some systems have a secondary ROM mapped at `$E00000`: + +| System | Main ROM | Extension ROM | +|---|---|---| +| CD32 | `$F80000` (512 KB) | `$E00000` (512 KB) — CD filesystem, NVRAM | +| A4000T | `$F80000` (512 KB) | (None — all in main ROM) | +| A1000 | WCS (256 KB) | Loaded from floppy into WCS RAM | + +### MapROM / Soft-Kickstart + +Many accelerator boards support **MapROM** — loading a Kickstart image into Fast RAM and remapping the ROM address range: + +``` +1> LoadModule ROM:68040.library ; Load replacement module +1> MapROM kick32.rom ; Copy to Fast RAM, remap $F80000 +1> Reset ; Warm reset — boots from RAM copy +``` + +This allows running newer Kickstart versions without burning EPROMs. + +### 1 MB ROM Images + +Some setups combine a 512 KB Kickstart with a 512 KB extension ROM: + +``` +$E00000–$E7FFFF: Extension ROM (512 KB) +$F80000–$FFFFFF: Main Kickstart (512 KB) +``` + +Tools like Remus and Capitoline can build combined 1 MB images. + +--- + +## Burning Physical ROMs + +| ROM Size | EPROM Type | Pin Count | Notes | +|---|---|---|---| +| 256 KB | 27C020 | 32-pin | Used in pairs (Hi/Lo byte) | +| 512 KB | 27C040 / 27C400 | 32/40-pin | Single chip (A600/A1200) | +| 512 KB | 29F040 (Flash) | 32-pin | Reflashable — recommended for development | + +### Programming Steps + +1. Build or verify your ROM image with correct checksum +2. Program the EPROM/Flash using a TL866-II+ or similar programmer +3. For 256 KB pairs: split the image into even/odd bytes +4. Insert into the correct socket(s) — verify orientation +5. Power on — should boot cleanly if image is valid + +```bash +# Split 512 KB image into Hi/Lo bytes for dual-chip setups: +romtool split-bytes custom_kick.rom kick_hi.bin kick_lo.bin +# Or manually: +python3 -c " +d = open('kick.rom','rb').read() +open('kick_hi.bin','wb').write(d[1::2]) # Odd bytes +open('kick_lo.bin','wb').write(d[0::2]) # Even bytes +" +``` + +--- + +## Verifying a ROM Image + +```bash +# Verify checksum: +romtool info kick.rom | grep Checksum +# Expected: "Checksum: OK ($FFFFFFFF)" + +# Verify size: +ls -la kick.rom +# Expected: 262144 (256 KB) or 524288 (512 KB) + +# Quick checksum in Python: +python3 -c " +import struct +d = open('kick.rom','rb').read() +s = 0 +for i in range(0, len(d), 4): + v = struct.unpack('>I', d[i:i+4])[0] + s += v + if s >= 0x100000000: + s = (s + 1) & 0xFFFFFFFF +print(f'Checksum: \${ s:08X}', '✓' if s == 0xFFFFFFFF else '✗ BAD') +" +``` + +--- + +## References + +- NDK39: `exec/resident.h`, `exec/execbase.h` +- amitools: `romtool` — https://github.com/cnvogelg/amitools +- See also: [Cold Boot](cold_boot.md) — boot sequence using the ROM +- See also: [Kickstart Init](kickstart_init.md) — how residents are initialized +- See also: [Resident Modules](../06_exec_os/resident_modules.md) — RomTag structure diff --git a/README.md b/README.md index e376e2a..b0b5549 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,11 @@ The Amiga's documentation was scattered across out-of-print manuals, Usenet post ### 02 — Boot Sequence | File | Topic | |---|---| -| [cold_boot.md](02_boot_sequence/cold_boot.md) | Power-on, ROM checksum, memory detection | -| [kickstart_init.md](02_boot_sequence/kickstart_init.md) | ROM scan, ExecBase creation, resident modules | -| [dos_boot.md](02_boot_sequence/dos_boot.md) | Bootstrap, mount list, startup-sequence | -| [early_startup.md](02_boot_sequence/early_startup.md) | Early Startup Control menu, boot options | +| [cold_boot.md](02_boot_sequence/cold_boot.md) | Power-on: CPU reset vectors, ROM checksum, hardware reset, memory detection, diagnostic indicators | +| [**kickstart_rom.md**](02_boot_sequence/kickstart_rom.md) | **Kickstart ROM internals: binary structure, module inventory, extraction tools, custom ROM building** | +| [kickstart_init.md](02_boot_sequence/kickstart_init.md) | ExecBase creation, capture vectors, ROM scan algorithm, 4-phase resident init | +| [dos_boot.md](02_boot_sequence/dos_boot.md) | strap module, boot block format and execution, MountList, Startup-Sequence walkthrough | +| [early_startup.md](02_boot_sequence/early_startup.md) | Early Startup Control menu: device selection, display mode, recovery scenarios | ### 03 — Executable Loader & HUNK Format | File | Topic |