ARCHITECTURE.md

Commit: 2a3b0c04 Author: jokerz Raw Copy
1
# Pactor OS — Raspberry Pi 5 (Cortex A76) Architecture Plan
2
3
## Target Hardware
4
5
```
6
SoC:           BCM2712 (Broadcom)
7
CPU:           4x Cortex-A76 (ARMv8.2-A, AArch64)
8
RAM:           1GB+ (LPDDR4X, starting at 0x00000000)
9
GPU:           VideoCore VII (handles boot, HDMI, framebuffer)
10
Storage:       microSD (via EMMC2 controller) or NVMe (via PCIe)
11
UART:          PL011 at 0xFE201000 (primary debug console)
12
Interrupts:    GIC-400 (Generic Interrupt Controller) at 0xFF840000
13
Timer:         ARM Generic Timer (CNTPCT_EL0, CNTP_TVAL_EL0)
14
Boot:          GPU firmware → kernel8.img loaded to 0x80000
15
```
16
17
## Exception Levels (ARM's Ring Model)
18
19
```
20
EL3  Secure Monitor    — TrustZone (we won't use this)
21
EL2  Hypervisor        — GPU firmware starts us here, we drop to EL1
22
EL1  Kernel            — Pactor kernel runs here (= ring 0)
23
EL0  Userspace         — Applications run here (= ring 3)
24
```
25
26
## Memory Map
27
28
```
29
0x00000000 - 0x3BFFFFFF  RAM (up to 1GB, minus VC memory)
30
0x3C000000 - 0x3FFFFFFF  VideoCore memory (GPU firmware)
31
0x40000000 - 0xFFFFFFFF  Peripheral space (MMIO)
32
  0xFE000000             GPIO
33
  0xFE200000             PL011 UART0
34
  0xFE201000             PL011 UART1 (used by firmware for BT)
35
  0xFE215000             PCM (audio)
36
  0xFE800000             EMMC2 (SD card)
37
  0xFF840000             GIC-400 (interrupt controller)
38
  0xFFE00000             Local timer / watchdog
39
40
Kernel loads at 0x80000 (512KB into RAM)
41
Kernel stack at 0x80000 (grows down from load address)
42
Page tables start at 0x40000 (below kernel)
43
```
44
45
## Boot Sequence
46
47
```
48
1. GPU firmware (start4.elf) loads kernel8.img to 0x80000
49
2. CPU starts in EL2 (Hypervisor) or EL1 (depending on config.txt)
50
3. Kernel entry (_start):
51
   a. Check current EL (read CurrentEL register)
52
   b. If EL2: configure EL1, drop to EL1 via ERET
53
   c. Set up exception vector table (VBAR_EL1)
54
   d. Set up page tables (TTBR1_EL1 for kernel, TTBR0_EL1 for users)
55
   e. Enable MMU (SCTLR_EL1.M = 1)
56
   f. Set up GIC-400 (enable interrupts)
57
   g. Set up ARM Generic Timer (100Hz tick)
58
   h. Initialize PL011 UART (serial console)
59
   i. Call kernel_main()
60
```
61
62
## Subsystem Mapping
63
64
```
65
┌─────────────────────┬──────────────────────┬───────────────────────┐
66
│ Subsystem           │ x86-64 (current)     │ ARM64 (Pi 5)         │
67
├─────────────────────┼──────────────────────┼───────────────────────┤
68
│ Boot                │ GRUB2 multiboot2     │ GPU firmware + config │
69
│ CPU mode            │ Protected → Long mode│ EL2 → EL1            │
70
│ GDT                 │ x86 GDT (8-byte ents)│ Not needed (no GDT)  │
71
│ IDT                 │ 256 x 16-byte entries│ VBAR_EL1 vector table│
72
│ Interrupt controller│ 8259 PIC             │ GIC-400              │
73
│ Timer               │ PIT (8253) 100Hz     │ ARM Generic Timer    │
74
│ Serial              │ 8250 UART (0x3F8)    │ PL011 (0xFE201000)   │
75
│ Paging              │ 4-level (PML4→PT)    │ 4-level (TTBR→L3)    │
76
│ Syscall             │ SYSCALL/SYSRET       │ SVC/ERET             │
77
│ Ring 0/3            │ CS.RPL               │ EL1/EL0              │
78
│ Context switch      │ IRETQ                │ ERET                 │
79
│ Userspace entry     │ SYSRET               │ ERET with SP_EL0     │
80
│ Page size           │ 2MB (huge) + 4KB     │ 4KB or 2MB (optional)│
81
│ DMA / disk          │ ATA PIO              │ EMMC2 / SDHOST       │
82
│ Display             │ VGA text (0xB8000)   │ Framebuffer (via VC) │
83
└─────────────────────┴──────────────────────┴───────────────────────┘
84
```
85
86
## File Structure
87
88
```
89
pactor-arm64/
90
├── boot/
91
│   ├── config.txt          # Pi 5 boot config (kernel=kernel8.img)
92
│   └── start.elf           # (copied from Pi firmware)
93
├── kernel/
94
│   ├── entry.S             # AArch64 entry, EL2→EL1, vector table
95
│   ├── vectors.S           # Exception vector table (sync/irq/fiq/error)
96
│   ├── gic.c / gic.h       # GIC-400 driver
97
│   ├── timer.c / timer.h   # ARM Generic Timer
98
│   ├── uart.c / uart.h     # PL011 UART driver
99
│   ├── mmu.c / mmu.h       # MMU / page table management
100
│   ├── console.c           # kprintf, serial output
101
│   ├── shell.c             # Interactive shell (shared code)
102
│   ├── syscall.c           # SVC handler (syscall dispatch)
103
│   ├── syscall_entry.S     # SVC entry/exit (save/restore regs)
104
│   ├── elf.c               # ELF64 loader (mostly shared)
105
│   ├── ext2.c              # ext2 filesystem (shared code)
106
│   ├── pmm.c               # Physical memory manager
107
│   └── main.c              # kernel_main()
108
├── libc/
109
│   ├── start.S             # _start entry (EL0, calls main)
110
│   ├── libc.h              # Userspace API header
111
│   └── start.c             # printf, malloc, string functions
112
├── applications/
113
│   ├── fibonacci.c         # Same apps, recompiled for ARM64
114
│   ├── primes.c
115
│   └── ...
116
├── include/
117
│   └── pactor.h            # Common types and declarations
118
├── linker.ld               # Kernel linker script (load at 0x80000)
119
├── userspace.ld            # Userspace linker script (load at 0x400000)
120
├── Makefile                # Build system
121
└── mkcard.sh               # Create bootable SD card image
122
```
123
124
## Key ARM64 Concepts for the Port
125
126
### 1. Exception Vector Table (replaces IDT)
127
```
128
; VBAR_EL1 points to this table
129
; 16 entries, 128 bytes each (0x800 alignment)
130
; 4 types × 4 exception sources = 16 entries
131
132
vector_table:
133
    ; Current EL with SP0
134
    b sync_handler_sp0      ; 0x000 Synchronous
135
    b irq_handler_sp0       ; 0x080 IRQ
136
    b fiq_handler_sp0       ; 0x100 FIQ
137
    b error_handler_sp0     ; 0x180 SError
138
139
    ; Current EL with SPx (kernel mode)
140
    b sync_handler_spx      ; 0x200 Synchronous (syscalls, faults)
141
    b irq_handler_spx       ; 0x280 IRQ (timer, peripherals)
142
    b fiq_handler_spx       ; 0x300 FIQ
143
    b error_handler_spx     ; 0x380 SError
144
145
    ; Lower EL (AArch64, from userspace)
146
    b sync_handler_el0_64   ; 0x400 SVC instruction
147
    b irq_handler_el0_64    ; 0x480 IRQ from userspace
148
    b fiq_handler_el0_64    ; 0x500 FIQ
149
    b error_handler_el0_64  ; 0x580 SError
150
151
    ; Lower EL (AArch32, unused)
152
    .space 0x100            ; 0x600-0x700
153
```
154
155
### 2. GIC-400 (replaces 8259 PIC)
156
```
157
GICD_BASE = 0xFF841000  ; Distributor
158
GICC_BASE = 0xFF842000  ; CPU interface
159
160
; Enable distributor
161
; Enable CPU interface
162
; Configure interrupt routing (IRQ → CPU core 0)
163
; Enable specific IRQs (timer = IRQ 27, UART = IRQ 33)
164
```
165
166
### 3. ARM Generic Timer (replaces PIT)
167
```
168
; Configure timer frequency (read CNTFRQ_EL0, typically 54MHz)
169
; Set next tick: CNTP_TVAL_EL0 = freq / 100 (100Hz)
170
; Enable timer: CNTP_CTL_EL0 = 1
171
; IRQ fires as PPI 14 (private peripheral interrupt)
172
```
173
174
### 4. PL011 UART (replaces 8250 UART)
175
```
176
UART0_BASE = 0xFE201000
177
; Different register layout than 8250
178
; IBRD, FBRD for baud rate
179
; LCR_H for line control
180
; CR for enable TX/RX
181
; FR for status (TXFF, RXFE)
182
```
183
184
### 5. SVC/ERET (replaces SYSCALL/SYSRET)
185
```
186
; Userspace invokes syscall:
187
;   MOV X8, #syscall_number
188
;   SVC #0
189
190
; Kernel handler:
191
;   Save all registers (X0-X30, SP_EL0, SPSR_EL1, ELR_EL1)
192
;   Dispatch syscall_table[X8]
193
;   Restore registers
194
;   ERET  ; returns to EL0
195
196
; Entry point (from userspace):
197
;   ERET with:
198
;     ELR_EL1 = user PC
199
;     SP_EL0  = user SP
200
;     SPSR_EL1 = user flags (EL0, AArch64)
201
```
202
203
### 6. Page Tables (replaces x86 page tables)
204
```
205
; 4-level translation tables (similar to x86):
206
;   TTBR1_EL1 → L0 table → L1 table → L2 table → L3 table
207
;   Each L3 entry maps a 4KB page
208
;   L2 entries can map 2MB blocks (like x86 huge pages)
209
;
210
; Attributes: AP[1]=1 for EL0 access (user), AP[1]=0 for EL1 only
211
;             SH (shareability), AF (access flag), UXN/PXN (execute never)
212
```
213
214
## Shared vs Port-Specific Code
215
216
```
217
SHARED (copy from x86-64, minimal changes):
218
  - shell.c (serial I/O abstraction)
219
  - ext2.c (block device abstraction)
220
  - elf.c (platform-specific page setup)
221
  - libc/start.c (printf, malloc, strings)
222
  - applications/*.c (recompile for ARM64)
223
224
PORT-SPECIFIC (rewrite from scratch):
225
  - entry.S (AArch64 boot, EL2→EL1, MMU setup)
226
  - vectors.S (exception vector table)
227
  - gic.c (GIC-400 driver)
228
  - timer.c (ARM Generic Timer)
229
  - uart.c (PL011 driver)
230
  - mmu.c (ARM64 translation tables)
231
  - syscall_entry.S (SVC handler, save/restore)
232
  - linker.ld (load at 0x80000)
233
  - Makefile (aarch64-none-elf toolchain)
234
```
235
236
## Build Toolchain
237
238
```bash
239
# Cross-compiler for ARM64
240
sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
241
242
# Or use LLVM
243
clang --target=aarch64-none-elf -mcpu=cortex-a76
244
245
# Build
246
make ARCH=arm64
247
248
# Deploy to SD card
249
# 1. Format SD card as FAT32
250
# 2. Copy firmware files (start4.elf, fixup4.dat, bootcode.bin)
251
# 3. Copy kernel8.img
252
# 4. Copy config.txt
253
# 5. Insert into Pi 5, power on
254
```
255
256
## config.txt (Pi 5 boot configuration)
257
258
```ini
259
arm_64bit=1
260
kernel=kernel8.img
261
disable_commandline_tags=1
262
armstub=armstub8.bin
263
enable_uart=1
264
uart_2ndstage=1
265
```
266
267
## Development Timeline
268
269
```
270
Phase 1: Bare metal boot (serial output)
271
  - entry.S: EL2→EL1, enable UART, print "Hello"
272
  - UART polling driver
273
  - Build toolchain setup
274
  → Test: boot on Pi 5, see "Pactor64" on serial
275
276
Phase 2: Interrupts + Timer
277
  - GIC-400 driver (enable distributor, CPU interface)
278
  - ARM Generic Timer (100Hz tick)
279
  - Exception vector table
280
  - Timer ISR, tick counter
281
  → Test: uptime command works
282
283
Phase 3: Memory Management
284
  - Physical memory allocator (parse ATAGS or DTB for memory map)
285
  - MMU setup (translation tables, identity map)
286
  - Kernel heap
287
  → Test: malloc works
288
289
Phase 4: Syscalls + Userspace
290
  - SVC handler (syscall dispatch)
291
  - EL0 entry (ERET to userspace)
292
  - ELF loader
293
  - hello.elf compiled for ARM64
294
  → Test: hello.elf runs in EL0
295
296
Phase 5: Filesystem + Applications
297
  - EMMC2 SD card driver
298
  - ext2 filesystem (shared code)
299
  - Application bundle (recompiled for ARM64)
300
  → Test: execute fibonacci on Pi 5
301
302
Phase 6: Embedded Features
303
  - GPIO driver (LED, buttons)
304
  - I2C/SPI drivers (sensors)
305
  - Framebuffer (HDMI output)
306
  - Network (Ethernet via PCIe/USB)
307
  → Test: real embedded application
308
```
309
310
## Estimated Effort
311
312
```
313
Phase 1: ~2-3 hours (boot + serial)
314
Phase 2: ~2-3 hours (GIC + timer + vectors)
315
Phase 3: ~3-4 hours (MMU + memory management)
316
Phase 4: ~3-4 hours (syscalls + userspace)
317
Phase 5: ~2-3 hours (SD card + filesystem)
318
Phase 6: ~4-8 hours (GPIO, I2C, framebuffer, network)
319
320
Total: ~16-25 hours of focused work
321
```
322