1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
|
.include "kernel/ppcconsts.S"
.section .text.intvects
.global _start
_start:
;// Check if first thread.
mfspr r1, PIR
li r2, 0x0003
and r1, r1, r2
li r2, 0x0
cmpl cr0, r1, r2
bnel cr0, _other_thread_spinlock
;// Relocate code
bl pre_relocate ;// fill LR with address
pre_relocate:
mflr r2
lis r1,0x0010
cmpl cr0,r2,r1 ;// Check LR is less than 1MB
blt finished_relocate ;// No need to relocate if less than 1MB
;// Get addresses for relocation.
;// Write address in r5
;// Read address in r1
li r5,0
lis r1, -1 ;// fill r1 with ffff..ff0000
and r1,r1,r2 ;// and with pre_relocate's address from r2 to get start of
;// rom section.
;// Update LR to low address.
clrldi r2,r2,48 ;// Equiv to ~(0x0FFFF)
mtlr 2
;// Moving 1MB , so load r2 with (1MB / 8 bytes per word)
lis r2, 0x2
mtctr r2
relocate_loop:
;// The dcbst/sync/icbi/isync sequence comes from PowerISA
ld r4, 0(r1)
std r4, 0(r5)
dcbst 0,r5
sync
icbi 0,r5
isync
addi r1,r1,8
addi r5,r5,8
bdnz+ relocate_loop
;// Now that we've relocated, erase exception prefix.
mfmsr r11
rldicl r11,r11,57,1 ;// Erase bit 6 ( equiv to r11 & ~(0x40))
rotldi r11,r11,7
mtmsr r11
;// Jump to low address.
blr
finished_relocate:
;// Jump to main.
b _main
;// Interrupt vectors.
#define UNIMPL_INTERRUPT(name, address) \
.org _start + address; \
intvect_##name: \
b intvect_##name
#define STD_INTERRUPT(name, address) \
.org _start + address; \
intvect_##name: \
mtsprg1 r1; /* Save GPR1 */ \
;/* Retrieve processing address for interrupt. */ \
lis r1, intvect_##name##_finish_save@h; \
ori r1, r1, intvect_##name##_finish_save@l; \
;/* Save interrupt address in SPRG0 */ \
mtsprg0 r1; \
mfsprg1 r1; /* Restore GPR1 */ \
b kernel_save_task ; /* Save current task. */ \
intvect_##name##_finish_save: \
; /* Get TOC entry for kernel C function */ \
lis r2, kernel_execute_##name##@h; \
ori r2, r2, kernel_execute_##name##@l; \
ld r0, 0(r2); /* Load call address */ \
mtlr r0; \
ld r2, 8(r2); /* Load TOC base. */ \
blrl; /* Call kernel function */ \
nop; \
b kernel_dispatch_task; /* Return to task */
.org _start + 0x100
intvect_system_reset:
b _start
.org _start + 0x17C
hbi_pre_phyp_breakpoint:
attn; /* TODO: Add actual breakpoint attention. */
b _start
UNIMPL_INTERRUPT(machine_check, 0x200)
UNIMPL_INTERRUPT(data_storage, 0x300)
UNIMPL_INTERRUPT(data_segment, 0x380)
UNIMPL_INTERRUPT(inst_storage, 0x400)
UNIMPL_INTERRUPT(inst_segment, 0x480)
UNIMPL_INTERRUPT(external, 0x500)
UNIMPL_INTERRUPT(alignment, 0x600)
STD_INTERRUPT(prog_ex, 0x700)
UNIMPL_INTERRUPT(fp_unavail, 0x800)
STD_INTERRUPT(decrementer, 0x900)
UNIMPL_INTERRUPT(hype_decrementer, 0x980)
STD_INTERRUPT(system_call, 0xC00)
UNIMPL_INTERRUPT(trace, 0xD00)
UNIMPL_INTERRUPT(hype_data_storage, 0xE00)
UNIMPL_INTERRUPT(hype_inst_storage, 0xE20)
UNIMPL_INTERRUPT(hype_emu_assist, 0xE40)
UNIMPL_INTERRUPT(hype_maint, 0xE60)
UNIMPL_INTERRUPT(perf_monitor, 0xF00)
UNIMPL_INTERRUPT(vector_unavail, 0xF20)
UNIMPL_INTERRUPT(vsx_unavail, 0xF40)
.section .text
;// _main:
;// Set up stack and TOC and call kernel's main.
_main:
;// Set up initial TOC Base
lis r2, main@h
ori r2, r2, main@l
ld r2,8(r2)
;// Set up initial stack, space for 8 double-words
lis r1, kernel_stack@h
ori r1, r1, kernel_stack@l
addi r1, r1, 16320
;// Call main.
bl main
_main_loop:
b _main_loop
;// _other_thread_spinlock:
;// Used for threads other than 0 to wait for the system to boot to a
;// stable point where we can start the other threads. At this point
;// nothing is initalized in the thread except r1 = thread ID.
_other_thread_spinlock:
;// Read spinlock value.
lis r2, kernel_other_thread_spinlock@h
ori r2, r2, kernel_other_thread_spinlock@l
ld r3, 0(r2)
;// Loop until value is not 0...
li r4, 0
cmp cr0, r3, r4
bne _other_thread_spinlock_complete
b _other_thread_spinlock
;// Now released by primary thread.
_other_thread_spinlock_complete:
;// Get CPU object from thread ID.
lis r2, _ZN10CpuManager7cv_cpusE@h
ori r2, r2, _ZN10CpuManager7cv_cpusE@l
muli r3, r1, 8
add r2, r3, r2
ld r3, 0(r2) ;// Load CPU object.
ld r1, 0(r3) ;// Load initial stack.
lis r2, smp_slave_main@h ;// Load TOC base.
ori r2, r2, smp_slave_main@l
ld r2, 8(r2)
bl smp_slave_main ;// Call smp_slave_main
b _main_loop
;// @fn kernel_save_task
;// Saves context to task structure and branches back to requested addr.
;//
;// Requires:
;// * SPRG3 -> Task Structure.
;// * SPRG0 -> Return address.
;// * SPRG1 -> Safe for scratch (temporary save of r1)
kernel_save_task:
mtsprg1 r1 ;// Save r1.
mfsprg3 r1 ;// Get task structure.
std r0, TASK_GPR_0(r1) ;// Save GPR0
mfsrr0 r0
std r0, TASK_NIP(r1) ;// Save NIP
mflr r0
std r0, TASK_LR(r1) ;// Save LR
mfcr r0
std r0, TASK_CR(r1) ;// Save CR
mfctr r0
std r0, TASK_CTR(r1) ;// Save CTR
mfxer r0
std r0, TASK_XER(r1) ;// Save XER
mfsprg1 r0
std r0, TASK_GPR_1(r1) ;// Save GPR1
std r2, TASK_GPR_2(r1) ;// Save GPR2
std r3, TASK_GPR_3(r1) ;// Save GPR3
std r4, TASK_GPR_4(r1) ;// Save GPR4
std r5, TASK_GPR_5(r1) ;// Save GPR5
std r6, TASK_GPR_6(r1) ;// Save GPR6
std r7, TASK_GPR_7(r1) ;// Save GPR7
std r8, TASK_GPR_8(r1) ;// Save GPR8
std r9, TASK_GPR_9(r1) ;// Save GPR9
std r10, TASK_GPR_10(r1) ;// Save GPR10
std r11, TASK_GPR_11(r1) ;// Save GPR11
std r12, TASK_GPR_12(r1) ;// Save GPR12
std r13, TASK_GPR_13(r1) ;// Save GPR13
std r14, TASK_GPR_14(r1) ;// Save GPR14
std r15, TASK_GPR_15(r1) ;// Save GPR15
std r16, TASK_GPR_16(r1) ;// Save GPR16
std r17, TASK_GPR_17(r1) ;// Save GPR17
std r18, TASK_GPR_18(r1) ;// Save GPR18
std r19, TASK_GPR_19(r1) ;// Save GPR19
std r20, TASK_GPR_20(r1) ;// Save GPR20
std r21, TASK_GPR_21(r1) ;// Save GPR21
std r22, TASK_GPR_22(r1) ;// Save GPR22
std r23, TASK_GPR_23(r1) ;// Save GPR23
std r24, TASK_GPR_24(r1) ;// Save GPR24
std r25, TASK_GPR_25(r1) ;// Save GPR25
std r26, TASK_GPR_26(r1) ;// Save GPR26
std r27, TASK_GPR_27(r1) ;// Save GPR27
std r28, TASK_GPR_28(r1) ;// Save GPR28
std r29, TASK_GPR_29(r1) ;// Save GPR29
std r30, TASK_GPR_30(r1) ;// Save GPR30
std r31, TASK_GPR_31(r1) ;// Save GPR31
ld r1, 0(r1) ;// Get CPU pointer
ld r1, 0(r1) ;// Get kernel stack pointer.
mfsprg0 r0 ;// Retrieve return address from SPRG0
mtlr r0 ;// Call
blr
;// @fn dispatch_task
;// Loads context from task structure and performs rfi.
;//
;// Requires:
;// * SPRG3 -> Task Structure.
;// * Current contents of registers are not needed.
kernel_dispatch_task:
.global kernel_dispatch_task
mfsprg3 r1 ;// Load task structure to r1.
ldarx r0, 0, r1 ;// Clear the reservation by loading / storing
stdcx. r0, 0, r1 ;// the CPU pointer in the task.
mfmsr r2 ;// Get current MSR
ori r2,r2, 0xC030 ;// Enable MSR[EE,PR,IR,DR].
rldicl r2,r2,1,1 ;// Clear ...
rotldi r2,r2,63 ;// MSR[TA]
mtsrr1 r2 ;// Set task MSR (SRR1)
ld r2, TASK_NIP(r1) ;// Load NIP from context.
mtsrr0 r2 ;// Set task NIP (SRR0)
;// Restore GPRs from context.
ld r0, TASK_GPR_0(r1) ;// GPR0
ld r2, TASK_GPR_2(r1) ;// GPR2
ld r3, TASK_GPR_3(r1) ;// GPR3
ld r4, TASK_GPR_4(r1) ;// GPR4
ld r5, TASK_GPR_5(r1) ;// GPR5
ld r6, TASK_GPR_6(r1) ;// GPR6
ld r7, TASK_GPR_7(r1) ;// GPR7
ld r8, TASK_GPR_8(r1) ;// GPR8
ld r9, TASK_GPR_9(r1) ;// GPR9
ld r10, TASK_GPR_10(r1) ;// GPR10
ld r11, TASK_GPR_11(r1) ;// GPR11
ld r12, TASK_GPR_12(r1) ;// GPR12
ld r13, TASK_GPR_13(r1) ;// GPR13
ld r14, TASK_GPR_14(r1) ;// GPR14
ld r15, TASK_GPR_15(r1) ;// GPR15
ld r16, TASK_GPR_16(r1) ;// GPR16
ld r17, TASK_GPR_17(r1) ;// GPR17
ld r18, TASK_GPR_18(r1) ;// GPR18
ld r19, TASK_GPR_19(r1) ;// GPR19
ld r20, TASK_GPR_20(r1) ;// GPR20
ld r21, TASK_GPR_21(r1) ;// GPR21
ld r22, TASK_GPR_22(r1) ;// GPR22
ld r23, TASK_GPR_23(r1) ;// GPR23
ld r24, TASK_GPR_24(r1) ;// GPR24
ld r25, TASK_GPR_25(r1) ;// GPR25
ld r26, TASK_GPR_26(r1) ;// GPR26
ld r27, TASK_GPR_27(r1) ;// GPR27
ld r28, TASK_LR(r1) ;// Load from context: LR, CR, CTR, XER
ld r29, TASK_CR(r1)
ld r30, TASK_CTR(r1)
ld r31, TASK_XER(r1)
mtlr r28 ;// Restore LR
mtcr r29 ;// Restore CR
mtctr r30 ;// Restore CTR
mtxer r31 ;// Restore XER
ld r28, TASK_GPR_28(r1) ;// GPR28
ld r29, TASK_GPR_29(r1) ;// GPR29
ld r30, TASK_GPR_30(r1) ;// GPR30
ld r31, TASK_GPR_31(r1) ;// GPR31
ld r1, TASK_GPR_1(r1) ;// GPR1
rfid ;// Execute task.
.section .data
.balign 1024
kernel_stack:
.space 16*1024
.global kernel_other_thread_spinlock
kernel_other_thread_spinlock:
.space 8
.section .text.hreset
hreset:
b _start
|