entry.S

Commit: 2a3b0c04 Author: jokerz Raw Copy
1
// ============================================================================
2
// Pactor64 — Raspberry Pi 5 (Cortex A76) Kernel Entry
3
// AArch64 assembly, clang assembler syntax
4
//
5
// GPU firmware loads kernel8.img to 0x80000 and starts CPU in EL2.
6
// We transition to EL1, set up stack, init UART, and call kernel_main.
7
// ============================================================================
8
9
.section .text
10
11
// ============================================================================
12
// Constants
13
// ============================================================================
14
15
// PL011 UART (BCM2712, Pi 5)
16
.equ UART0_BASE,    0xFE201000
17
.equ UART_DR,       0x00    // Data register
18
.equ UART_FR,       0x18    // Flag register
19
.equ UART_IBRD,     0x24    // Integer baud rate divisor
20
.equ UART_FBRD,     0x28    // Fractional baud rate divisor
21
.equ UART_LCR_H,    0x2C    // Line control register
22
.equ UART_CR,       0x30    // Control register
23
.equ UART_IMSC,     0x38    // Interrupt mask
24
.equ UART_ICR,      0x44    // Interrupt clear
25
26
// PL011 CR bits
27
.equ CR_UARTEN,     (1 << 0)
28
.equ CR_TXE,        (1 << 8)
29
.equ CR_RXE,        (1 << 9)
30
31
// PL011 FR bits
32
.equ FR_TXFF,       (1 << 5)    // TX FIFO full
33
.equ FR_RXFE,       (1 << 4)    // RX FIFO empty
34
35
// PL011 LCR_H bits
36
.equ LCR_H_WLEN_8,  (3 << 5)   // 8-bit word
37
.equ LCR_H_FEN,     (1 << 4)   // FIFO enable
38
39
// Exception levels
40
.equ EL2,           8
41
.equ EL1,           4
42
.equ EL0,           0
43
44
// Kernel load address
45
.equ KERNEL_BASE,   0x80000
46
47
// ============================================================================
48
// Entry Point
49
// ============================================================================
50
51
.globl _start
52
_start:
53
    // ------------------------------------------------------------------
54
    // Step 1: Check current exception level
55
    // ------------------------------------------------------------------
56
    mrs     x0, CurrentEL
57
    and     x0, x0, #0xC           // Extract EL bits [3:2]
58
    lsr     x0, x0, #2             // EL = CurrentEL >> 2
59
60
    // If already EL1, skip EL2→EL1 transition
61
    cmp     x0, #1
62
    beq     .Lsetup_el1
63
64
    // ------------------------------------------------------------------
65
    // Step 2: EL2 → EL1 transition
66
    // ------------------------------------------------------------------
67
    // Configure HCR_EL2: set RW bit (EL1 is AArch64)
68
    mrs     x1, hcr_el2
69
    orr     x1, x1, #(1 << 31)     // HCR_EL2.RW = 1 (AArch64 at EL1)
70
    msr     hcr_el2, x1
71
72
    // Configure SCTLR_EL1 to known state (all disabled initially)
73
    mov     x1, #0x0800             // RES1 bits
74
    movk    x1, #0x30D0, lsl #16    // RES1 bits
75
    msr     sctlr_el1, x1
76
77
    // Configure SPSR_EL2 for return to EL1
78
    // SPSR: DAIF masked, EL1h mode
79
    mov     x1, #0x3C5              // EL1h | DAIF masked
80
    msr     spsr_el2, x1
81
82
    // Set return address for ERET
83
    adr     x1, .Lsetup_el1
84
    msr     elr_el2, x1
85
86
    // Drop to EL1
87
    eret
88
89
.Lsetup_el1:
90
    // ------------------------------------------------------------------
91
    // Step 3: Set up stack pointer (EL1)
92
    // ------------------------------------------------------------------
93
    // Stack grows down from kernel load address
94
    // (We'll set up a proper stack in BSS later)
95
    ldr     x0, =_stack_top
96
    mov     sp, x0
97
98
    // Also set SP_EL0 (for userspace later)
99
    ldr     x0, =0x1000000          // 16MB — userspace stack base
100
    msr     sp_el0, x0
101
102
    // ------------------------------------------------------------------
103
    // Step 4: Zero BSS section
104
    // ------------------------------------------------------------------
105
    ldr     x0, =__bss_start
106
    ldr     x1, =__bss_end
107
.Lbss_loop:
108
    cmp     x0, x1
109
    bge     .Lbss_done
110
    str     xzr, [x0], #8
111
    b       .Lbss_loop
112
.Lbss_done:
113
114
    // ------------------------------------------------------------------
115
    // Step 5: Initialize PL011 UART
116
    // ------------------------------------------------------------------
117
    bl      uart_init
118
119
    // ------------------------------------------------------------------
120
    // Step 6: Print boot banner
121
    // ------------------------------------------------------------------
122
    ldr     x0, =msg_banner
123
    bl      uart_puts
124
125
    // ------------------------------------------------------------------
126
    // Step 7: Call kernel_main
127
    // ------------------------------------------------------------------
128
    bl      kernel_main
129
130
    // If kernel_main returns, halt
131
.Lhalt:
132
    wfe
133
    b       .Lhalt
134
135
// ============================================================================
136
// uart_init — Initialize PL011 UART for serial output
137
// BCM2712 UART0 at 0xFE201000
138
// Baud rate: 115200, 8N1
139
// ============================================================================
140
141
.globl uart_init
142
uart_init:
143
    ldr     x0, =UART0_BASE
144
145
    // Disable UART
146
    str     wzr, [x0, #UART_CR]
147
148
    // Wait for TX to finish
149
.Luart_wait:
150
    ldr     w1, [x0, #UART_FR]
151
    tbnz    w1, #3, .Luart_wait     // BUSY bit
152
153
    // Clear interrupts
154
    mov     w1, #0x7FF
155
    str     w1, [x0, #UART_ICR]
156
157
    // Set baud rate: 115200
158
    // IBRD = 48000000 / (16 * 115200) = 26.0416...
159
    // IBRD = 26, FBRD = round(0.0416 * 64) = 3
160
    mov     w1, #26
161
    str     w1, [x0, #UART_IBRD]
162
    mov     w1, #3
163
    str     w1, [x0, #UART_FBRD]
164
165
    // 8-bit, no parity, 1 stop, FIFO enabled
166
    mov     w1, #(LCR_H_WLEN_8 | LCR_H_FEN)
167
    str     w1, [x0, #UART_LCR_H]
168
169
    // Mask all interrupts
170
    str     wzr, [x0, #UART_IMSC]
171
172
    // Enable UART, TX, RX
173
    mov     w1, #(CR_UARTEN | CR_TXE | CR_RXE)
174
    str     w1, [x0, #UART_CR]
175
176
    ret
177
178
// ============================================================================
179
// uart_putc — Write a character to UART
180
// x0 = character
181
// ============================================================================
182
183
.globl uart_putc
184
uart_putc:
185
    ldr     x1, =UART0_BASE
186
.Lputc_wait:
187
    ldr     w2, [x1, #UART_FR]
188
    tbnz    w2, #5, .Lputc_wait     // Wait while TX FIFO full
189
    str     w0, [x1, #UART_DR]
190
    ret
191
192
// ============================================================================
193
// uart_puts — Write a null-terminated string to UART
194
// x0 = pointer to string
195
// ============================================================================
196
197
.globl uart_puts
198
uart_puts:
199
    stp     x29, x30, [sp, #-16]!
200
    mov     x29, sp
201
    mov     x19, x0                 // Save string pointer
202
.Lputs_loop:
203
    ldrb    w0, [x19], #1
204
    cbz     w0, .Lputs_done
205
    bl      uart_putc
206
    b       .Lputs_loop
207
.Lputs_done:
208
    ldp     x29, x30, [sp], #16
209
    ret
210
211
// ============================================================================
212
// uart_getc — Read a character from UART (blocking)
213
// Returns character in x0, or -1 if no data
214
// ============================================================================
215
216
.globl uart_getc
217
uart_getc:
218
    ldr     x1, =UART0_BASE
219
    ldr     w2, [x1, #UART_FR]
220
    tbnz    w2, #4, .Lgetc_empty   // RX FIFO empty
221
    ldr     w0, [x1, #UART_DR]
222
    and     w0, w0, #0xFF
223
    ret
224
.Lgetc_empty:
225
    mov     x0, #-1
226
    ret
227
228
// ============================================================================
229
// uart_poll — Check if UART has data available
230
// Returns 1 if data available, 0 otherwise
231
// ============================================================================
232
233
.globl uart_poll
234
uart_poll:
235
    ldr     x0, =UART0_BASE
236
    ldr     w1, [x0, #UART_FR]
237
    lsr     w1, w1, #4              // FR_RXFE is bit 4
238
    and     w0, w1, #1
239
    eor     w0, w0, #1              // Invert: 1 = data available
240
    ret
241
242
// ============================================================================
243
// Data Section
244
// ============================================================================
245
246
.section .rodata
247
msg_banner:
248
    .asciz  "\r\n"
249
    .asciz  "  ================================\r\n"
250
    .asciz  "  Pactor64 on Raspberry Pi 5\r\n"
251
    .asciz  "  Cortex A76 (AArch64)\r\n"
252
    .asciz  "  ================================\r\n"
253
    .asciz  "\r\n"
254
255
// ============================================================================
256
// BSS — Kernel Stack (16KB)
257
// ============================================================================
258
259
.section .bss
260
.align 12                       // 4KB aligned
261
.space 16384                    // 16KB stack
262
_stack_top:
263