typo..
[AROS.git] / arch / ppc-sam440 / kernel / kernel_startup.c
blob1dd8949b2467dac4d849f37030c60facb57cedaf
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 1
8 #include <aros/kernel.h>
9 #include <aros/libcall.h>
10 #include <aros/symbolsets.h>
11 #include <inttypes.h>
12 #include <exec/libraries.h>
13 #include <exec/execbase.h>
14 #include <aros/debug.h>
15 #include <exec/memory.h>
16 #include "memory.h"
17 #include <utility/tagitem.h>
18 #include <asm/amcc440.h>
19 #include <asm/io.h>
20 #include <strings.h>
22 #include <proto/exec.h>
24 #include LC_LIBDEFS_FILE
25 #include <kernel_romtags.h>
26 #include "kernel_intern.h"
28 /* forward declarations */
29 static void __attribute__((used)) kernel_cstart(struct TagItem *msg);
31 extern void exec_main(struct TagItem *msg, void *entry);
33 /* A very very very.....
34 * ... very ugly code.
36 * The AROS kernel gets executed at this place. The stack is unknown here, might be
37 * set properly up, might be totally broken aswell and thus one cannot trust the contents
38 * of %r1 register. Even worse, the kernel has been relocated most likely to some virtual
39 * address and the MMU mapping might not be ready now.
41 * The strategy is to create one MMU entry first, mapping first 16MB of ram into last 16MB
42 * of address space in one turn and then making proper MMU map once the bss sections are cleared
43 * and the startup routine in C is executed. This "trick" assumes two evil things:
44 * - the kernel will be loaded (and will fit completely) within first 16MB of RAM, and
45 * - the kernel will be mapped into top (last 16MB) of memory.
47 * Yes, I'm evil ;)
48 */
50 asm(".section .aros.init,\"ax\"\n\t"
51 ".globl start\n\t"
52 ".type start,@function\n"
53 "start:\n\t"
54 "mr %r29,%r3\n\t" /* Don't forget the message */
55 "lis %r5,0x4152\n\t" /* Load AROS magic value */
56 "ori %r5,%r5,0x4f53\n\t"
57 "cmpw %r5,%r4\n\t" /* Check if it was passed as 2nd parameter */
58 "bnelr\n\t" /* No, then return to caller */
59 "lis %r9,0xff00\n\t" /* Virtual address 0xff000000 */
60 "li %r10,0\n\t" /* Physical address 0x00000000 */
61 "ori %r9,%r9,0x0270\n\t" /* 16MB page. Valid one */
62 "li %r11,0x043f\n\t" /* Write through cache. RWX enabled :) */
63 "li %r0,0\n\t" /* TLB entry number 0 */
64 "tlbwe %r9,%r0,0\n\t"
65 "tlbwe %r10,%r0,1\n\t"
66 "tlbwe %r11,%r0,2\n\t"
67 "isync\n\t" /* Invalidate shadow TLB's */
68 "li %r9,0; mttbl %r9; mttbu %r9; mttbl %r9\n\t"
69 "lis %r9,tmp_stack_end@ha\n\t" /* Use temporary stack while clearing BSS */
70 "lwz %r1,tmp_stack_end@l(%r9)\n\t"
71 "bl __clear_bss_tagged\n\t" /* Clear 'em ALL!!! */
72 "lis %r11,target_address@ha\n\t" /* Load the address of init code in C */
73 "mr %r3,%r29\n\t" /* restore the message */
74 "lwz %r11,target_address@l(%r11)\n\t"
75 "lis %r9,stack_end@ha\n\t" /* Use brand new stack to do evil things */
76 "mtctr %r11\n\t"
77 "lwz %r1,stack_end@l(%r9)\n\t"
78 "bctr\n\t" /* And start the game... */
79 ".string \"Native/CORE v3 (" __DATE__ ")\""
80 "\n\t.text\n\t"
83 static void __attribute__((used)) __clear_bss_tagged(struct TagItem *msg)
85 struct KernelBSS *bss = (struct KernelBSS *) krnGetTagData(KRN_KernelBss, 0, msg);
87 __clear_bss(bss);
90 static union {
91 struct TagItem bootup_tags[64];
92 uint32_t tmp_stack [128];
93 } tmp_struct __attribute__((used, section(".data"), aligned(16)));
94 static const uint32_t *tmp_stack_end __attribute__((used, section(".text"))) = &tmp_struct.tmp_stack[124];
95 static uint32_t stack[STACK_SIZE] __attribute__((used, aligned(16)));
96 static const uint32_t *stack_end __attribute__((used, section(".text"))) = &stack[STACK_SIZE-4];
97 static const void *target_address __attribute__((used, section(".text"))) = (void*)kernel_cstart;
98 static char CmdLine[200] __attribute__((used));
100 struct MinList *modlist;
101 uintptr_t memlo;
102 struct ExecBase *SysBase;
104 static uint32_t exec_SelectMbs440(uint32_t bcr)
106 uint32_t val;
108 wrdcr(SDRAM0_CFGADDR, bcr);
109 val = rddcr(SDRAM0_CFGDATA);
111 switch (val & SDRAM_SDSZ_MASK)
113 case SDRAM_SDSZ_256MB: return 256;
114 case SDRAM_SDSZ_128MB: return 128;
115 case SDRAM_SDSZ_64MB: return 64;
116 case SDRAM_SDSZ_32MB: return 32;
117 case SDRAM_SDSZ_16MB: return 16;
118 case SDRAM_SDSZ_8MB: return 8;
121 return 0;
124 static uint32_t exec_SelectMbs460(uint32_t val)
126 D(bug("[%s] DCR 0x%08x\n", __func__, val));
127 switch (val & MQ0_BASSZ_MASK)
129 case MQ0_BASSZ_4096MB: return 4096;
130 case MQ0_BASSZ_2048MB: return 2048;
131 case MQ0_BASSZ_1024MB: return 1024;
132 case MQ0_BASSZ_512MB: return 512;
133 case MQ0_BASSZ_256MB: return 256;
134 case MQ0_BASSZ_128MB: return 128;
135 case MQ0_BASSZ_64MB: return 64;
136 case MQ0_BASSZ_32MB: return 32;
137 case MQ0_BASSZ_16MB: return 16;
138 case MQ0_BASSZ_8MB: return 8;
141 return 0;
144 /* Detect and report amount of available memory in mega bytes via device control register bus */
145 static uint32_t exec_GetMemory()
147 uint32_t mem = 0;
148 uint32_t pvr = rdspr(PVR);
150 if (krnIsPPC440(pvr)) {
151 mem += exec_SelectMbs440(SDRAM0_B0CR);
152 mem += exec_SelectMbs440(SDRAM0_B1CR);
153 mem += exec_SelectMbs440(SDRAM0_B2CR);
154 mem += exec_SelectMbs440(SDRAM0_B3CR);
155 } else if (krnIsPPC460(pvr)) {
156 /* Hmm. Probably a 460EX */
157 mem += exec_SelectMbs460(rddcr(MQ0_B0BAS));
158 mem += exec_SelectMbs460(rddcr(MQ0_B1BAS));
159 mem += exec_SelectMbs460(rddcr(MQ0_B2BAS));
160 mem += exec_SelectMbs460(rddcr(MQ0_B3BAS));
161 } else {
162 bug("Memory: Unrecognized PVR model 0x%08x\n", pvr);
163 bug("Memory: Assuming you have 64M of RAM\n");
164 mem = 64;
167 return mem;
170 void exec_main(struct TagItem *msg, void *entry)
172 UWORD *memrange[3];
173 uint32_t mem, krnLowest, krnHighest, memLowest;
174 struct MemHeader *mh;
176 D(bug("[exec] AROS for Sam440 - The AROS Research OS\n"));
178 /* Prepare the exec base */
179 D(bug("[exec] Preparing the ExecBase...\n"));
181 /* Get the kernel memory locations */
182 krnLowest = krnGetTagData(KRN_KernelLowest, 0, msg);
183 krnHighest = krnGetTagData(KRN_KernelHighest, 0, msg);
185 memLowest = (krnHighest + 0xffff) & 0xffff0000;
187 D(bug("[exec] Kernel and romtags: @%p - %p\n", krnLowest, krnHighest));
188 D(bug("[exec] Create memory header @%p - %p\n", memLowest, 0x01000000-1));
189 krnCreateMemHeader("RAM", -10, (APTR)(memLowest), 0x01000000 - (IPTR)memLowest,
190 MEMF_CHIP | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL | MEMF_24BITDMA);
192 memrange[0] = (UWORD *)(krnLowest + 0xff000000);
193 memrange[1] = (UWORD *)(krnHighest + 0xff000000);
194 memrange[2] = (UWORD *)-1;
196 mh = (struct MemHeader *)memLowest;
198 D(bug("[exec] Prepare exec base in %p\n", mh));
199 krnPrepareExecBase(memrange, mh, msg);
200 D(bug("[exec] ExecBase at %08x\n", SysBase));
202 /* Set up %r2 to point to SysBase
203 * For now, this is only used by the mmu_handler
204 * to patch up the damage that Parthenope does
205 * when it loads modules, and assumes that
206 * &SysBase == (void **)4;
208 asm volatile ("mr %%r2, %0\n" :: "r"(SysBase));
210 mem = exec_GetMemory();
211 D(bug("[exec] Adding memory (%uM)\n", mem));
213 AddMemList((mem - 16) * 1024*1024,
214 MEMF_FAST | MEMF_PUBLIC | MEMF_KICK | MEMF_LOCAL,
216 (APTR)0x01000000,
217 "Fast RAM");
219 D(bug("[exec] InitCode(RTF_SINGLETASK)\n"));
220 InitCode(RTF_SINGLETASK, 0);
222 D(bug("[exec] InitCode(RTF_COLDSTART)\n"));
223 InitCode(RTF_COLDSTART, 0);
225 D(bug("[exec] I should never get here...\n"));
229 static void __attribute__((used)) kernel_cstart(struct TagItem *msg)
231 struct TagItem *tmp = tmp_struct.bootup_tags;
232 int modlength;
234 /* Lowest usable kernel memory */
235 memlo = 0xff000000;
237 /* Disable interrupts and let FPU work */
238 wrmsr((rdmsr() & ~(MSR_CE | MSR_EE | MSR_ME)) | MSR_FP);
240 /* Enable FPU */
241 wrspr(CCR0, rdspr(CCR0) & ~0x00100000);
243 /* First message after FPU is enabled, otherwise illegal instruction */
244 D(bug("[KRN] Sam440 Kernel built on %s\n", __DATE__));
246 wrspr(SPRG0, 0);
247 wrspr(SPRG1, 0);
248 wrspr(SPRG2, 0);
249 wrspr(SPRG3, 0);
250 wrspr(SPRG4, 0); /* Clear KernelBase */
251 wrspr(SPRG5, 0); /* Clear SysBase */
253 D(bug("[KRN] Kernel resource pre-exec init\n"));
254 D(bug("[KRN] MSR=%08x CRR0=%08x CRR1=%08x\n", rdmsr(), rdspr(CCR0), rdspr(CCR1)));
255 D(bug("[KRN] USB config %08x\n", rddcr(SDR0_USB0)));
257 D(bug("[KRN] msg @ %p\n", msg));
258 D(bug("[KRN] Copying msg data\n"));
259 while(msg->ti_Tag != TAG_DONE)
261 *tmp = *msg;
263 if (tmp->ti_Tag == KRN_CmdLine)
265 strcpy(CmdLine, (char*) msg->ti_Data);
266 tmp->ti_Data = (STACKIPTR) CmdLine;
267 D(bug("[KRN] CmdLine: %s\n", tmp->ti_Data));
269 else if (tmp->ti_Tag == KRN_BootLoader)
271 tmp->ti_Data = (STACKIPTR) memlo;
272 strcpy((char*)tmp->ti_Data, (const char*) msg->ti_Data);
273 memlo += (strlen((char *)memlo) + 4) & ~3;
274 D(bug("[KRN] BootLoader: %s\n", tmp->ti_Data));
276 else if (tmp->ti_Tag == KRN_DebugInfo)
278 int i;
279 struct MinList *mlist = (struct MinList *)tmp->ti_Data;
280 module_t *mod;
282 D(bug("[KRN] DebugInfo at %08x\n", mlist));
284 modlist = (struct MinList *)memlo;
285 memlo += sizeof(*modlist);
286 NEWLIST(modlist);
288 mod = (module_t *)memlo;
290 ListLength(mlist, modlength);
291 memlo = (uintptr_t)&mod[modlength];
293 D(bug("[KRN] Bootstrap loaded debug info for %d modules\n", modlength));
294 /* Copy the module entries */
295 for (i=0; i < modlength; i++)
297 module_t *m = (module_t *)REMHEAD(mlist);
298 symbol_t *sym;
299 ULONG str_l = ~0, str_h = 0;
301 D(bug("[KRN] Module %s\n", m->m_name));
303 /* Discover size of the string table */
304 ForeachNode(&m->m_symbols, sym) {
305 ULONG end = (ULONG)sym->s_name + strlen(sym->s_name) + 1 + 1;
306 if ((ULONG)sym->s_name < str_l)
307 str_l = (ULONG)sym->s_name;
308 if (end > str_h)
309 str_h = end;
312 if (str_l > str_h)
313 str_h = str_l = 0;
315 mod[i].m_lowest = m->m_lowest;
316 mod[i].m_highest = m->m_highest;
317 mod[i].m_str = (char *)memlo;
318 memcpy(mod[i].m_str, (char *)str_l, str_h - str_l);
319 memlo += ((str_h - str_l) + 3) & ~3;
320 mod[i].m_name = (char *)memlo;
321 memlo += (strlen(m->m_name) + 4) & ~3;
322 strcpy(mod[i].m_name, m->m_name);
324 NEWLIST(&mod[i].m_symbols);
326 ForeachNode(&m->m_symbols, sym)
328 symbol_t *newsym = (symbol_t *)memlo;
329 memlo += sizeof(symbol_t);
331 newsym->s_name = (IPTR)sym->s_name - str_l + mod[i].m_str;
332 newsym->s_lowest = sym->s_lowest;
333 newsym->s_highest = sym->s_highest;
335 ADDTAIL(&mod[i].m_symbols, newsym);
338 ADDTAIL(modlist, &mod[i]);
341 D(bug("[KRN] Debug info uses %d KB of memory\n", ((intptr_t)memlo - (intptr_t)modlist) >> 10));
342 D(bug("[KRN] Debug info relocated from %p to %p\n", tmp->ti_Data, modlist));
344 /* Ugh. Parthenope doesn't use the ELF_ModuleInfo format.
345 * Prevent debug.library from becoming confused.
347 tmp->ti_Data = 0;
350 ++tmp;
351 ++msg;
354 memlo = (memlo + 4095) & ~4095;
356 BootMsg = tmp_struct.bootup_tags;
357 D(bug("[KRN] BootMsg @ %p\n", BootMsg));
359 /* Do a slightly more sophisticated MMU map */
360 mmu_init(BootMsg);
361 intr_init();
363 /* Initialize exec.library */
364 exec_main(BootMsg, NULL);
366 bug("[KRN] Uhm? Nothing to do?\n[KRN] STOPPED\n");
369 * Do never ever try to return. This code would attempt to go back to the physical address
370 * of asm trampoline, not the virtual one!
372 for (;;);
375 void SetupClocking440(struct PlatformData *pd)
377 /* PLL divisors */
378 wrdcr(CPR0_CFGADDR, CPR0_PLLD0);
379 uint32_t reg = rddcr(CPR0_CFGDATA);
381 uint32_t fbdv = (reg >> 24) & 0x1f;
382 if (fbdv == 0)
383 fbdv = 32;
384 uint32_t fwdva = (reg >> 16) & 0x1f;
385 if (fwdva == 0)
386 fwdva = 16;
387 uint32_t fwdvb = (reg >> 8) & 7;
388 if (fwdvb == 0)
389 fwdvb = 8;
390 uint32_t lfbdv = reg & 0x3f;
391 if (lfbdv == 0)
392 lfbdv = 64;
394 /* OPB clock divisor */
395 wrdcr(CPR0_CFGADDR, CPR0_OPBD0);
396 reg = rddcr(CPR0_CFGDATA);
397 uint32_t opbdv0 = (reg >> 24) & 3;
398 if (opbdv0 == 0)
399 opbdv0 = 4;
401 /* Peripheral clock divisor */
402 wrdcr(CPR0_CFGADDR, CPR0_PERD0);
403 reg = rddcr(CPR0_CFGDATA);
404 uint32_t perdv0 = (reg >> 24) & 7;
405 if (perdv0 == 0)
406 perdv0 = 8;
408 /* PCI clock divisor */
409 wrdcr(CPR0_CFGADDR, CPR0_SPCID);
410 reg = rddcr(CPR0_CFGDATA);
411 uint32_t spcid0 = (reg >> 24) & 3;
412 if (spcid0 == 0)
413 spcid0 = 4;
415 /* Primary B divisor */
416 wrdcr(CPR0_CFGADDR, CPR0_PRIMBD0);
417 reg = rddcr(CPR0_CFGDATA);
418 uint32_t prbdv0 = (reg >> 24) & 7;
419 if (prbdv0 == 0)
420 prbdv0 = 8;
422 /* All divisors there. Read PLL control register and calculate the m value (see 44ep.book) */
423 wrdcr(CPR0_CFGADDR, CPR0_PLLC0);
424 reg = rddcr(CPR0_CFGDATA);
425 uint32_t m;
426 switch ((reg >> 24) & 3) /* Feedback selector */
428 case 0:/* PLL output (A or B) */
429 if ((reg & 0x20000000)) /* PLLOUTB */
430 m = lfbdv * fbdv * fwdvb;
431 else
432 m = lfbdv * fbdv * fwdva;
433 break;
434 case 1: /* CPU */
435 m = fbdv * fwdva;
436 default:
437 m = perdv0 * opbdv0 * fwdvb;
440 uint32_t vco = (m * 66666666) + m/2;
441 pd->pd_CPUFreq = vco / fwdva;
442 pd->pd_PLBFreq = vco / fwdvb / perdv0;
443 pd->pd_OPBFreq = pd->pd_PLBFreq / opbdv0;
444 pd->pd_EPBFreq = pd->pd_PLBFreq / perdv0;
445 pd->pd_PCIFreq = pd->pd_PLBFreq / spcid0;
448 * Slow down the decrement interrupt a bit. Rough guess is that UBoot has left us with
449 * 1kHz DEC counter. Enable decrementer timer and automatic reload of decrementer value.
451 reg = rdspr(TCR);
452 wrspr(TCR, reg & ~(TCR_DIE | TCR_ARE));
453 wrspr(CCR1, rdspr(CCR1) | (0x80000000 >> 24));
454 wrspr(DECAR, pd->pd_OPBFreq / 50);
455 wrspr(TCR, reg | TCR_DIE | TCR_ARE);
459 const uint8_t fbdv_map[256] = {
460 1, 123, 117, 251, 245, 69, 111, 125,
461 119, 95, 105, 197, 239, 163, 63, 253,
462 247, 187, 57, 223, 233, 207, 157, 71,
463 113, 15, 89, 37, 191, 19, 99, 127,
464 121, 109, 93, 61, 185, 155, 13, 97,
465 107, 11, 9, 81, 31, 49, 83, 199,
466 241, 33, 181, 143, 217, 173, 51, 165,
467 65, 85, 151, 147, 227, 41, 201, 255,
468 249, 243, 195, 237, 221, 231, 35, 189,
469 59, 183, 79, 29, 141, 215, 145, 225,
470 235, 219, 27, 139, 137, 135, 175, 209,
471 159, 53, 45, 177, 211, 23, 167, 73,
472 115, 67, 103, 161, 55, 205, 87, 17,
473 91, 153, 7, 47, 179, 171, 149, 39,
474 193, 229, 77, 213, 25, 133, 43, 21,
475 101, 203, 5, 169, 75, 131, 3, 129,
476 1, 250, 244, 124, 118, 196, 238, 252,
477 246, 222, 232, 70, 112, 36, 190, 126,
478 120, 60, 184, 96, 106, 80, 30, 198,
479 240, 142, 216, 164, 64, 146, 226, 254,
480 248, 236, 220, 188, 58, 28, 140, 224,
481 234, 138, 136, 208, 158, 176, 210, 72,
482 114, 160, 54, 16, 90, 46, 178, 38,
483 192, 212, 24, 20, 100, 168, 74, 128,
484 122, 116, 68, 110, 94, 104, 162, 62,
485 186, 56, 206, 156, 14, 88, 18, 98,
486 108, 92, 154, 12, 10, 8, 48, 82,
487 32, 180, 172, 50, 84, 150, 40, 200,
488 242, 194, 230, 34, 182, 78, 214, 144,
489 218, 26, 134, 174, 52, 44, 22, 166,
490 66, 102, 204, 86, 152, 6, 170, 148,
491 228, 76, 132, 42, 202, 4, 130, 2,
494 static const uint8_t fwdv_map[16] = {
495 1, 2, 14, 9, 4, 11, 16, 13,
496 12, 5, 6, 15, 10, 7, 8, 3,
499 void SetupClocking460(struct PlatformData *pd)
501 uint32_t reg;
503 /* PLL divisors */
504 wrdcr(CPR0_CFGADDR, CPR0_PLLD);
505 reg = rddcr(CPR0_CFGDATA);
507 uint32_t fbdv = fbdv_map[(reg >> 24) & 0xff];
508 uint32_t fwdva = fwdv_map[((reg >> 16) & 0xf)];
509 uint32_t fwdvb = fwdv_map[(reg >> 8) & 0xf];
510 (void)fwdvb; // Unused
512 /* Early PLL divisor */
513 wrdcr(CPR0_CFGADDR, CPR0_PLBED);
514 reg = rddcr(CPR0_CFGDATA);
515 uint32_t plbed = (reg >> 24) & 7;
516 if (plbed == 0)
517 plbed = 8;
519 /* OPB clock divisor */
520 wrdcr(CPR0_CFGADDR, CPR0_OPBD);
521 reg = rddcr(CPR0_CFGDATA);
522 uint32_t opbd = (reg >> 24) & 3;
523 if (opbd == 0)
524 opbd = 4;
526 /* Peripheral clock divisor */
527 wrdcr(CPR0_CFGADDR, CPR0_PERD);
528 reg = rddcr(CPR0_CFGDATA);
529 uint32_t perd = (reg >> 24) & 3;
530 if (perd == 0)
531 perd = 4;
533 /* AHB clock divisor */
534 wrdcr(CPR0_CFGADDR, CPR0_AHBD);
535 reg = rddcr(CPR0_CFGDATA);
536 uint32_t ahbd = (reg >> 24) & 1;
537 if (ahbd == 0)
538 ahbd = 2;
540 /* All divisors there.
541 * Read PLL control register and calculate the m value
543 wrdcr(CPR0_CFGADDR, CPR0_PLLC);
544 reg = rddcr(CPR0_CFGDATA);
546 uint32_t m;
547 if (((reg >> 24) & 3) == 0) {
548 /* PLL internal feedback */
549 m = fbdv;
550 } else {
551 /* PLL Per-Clock feedback */
552 m = fwdva * plbed * opbd * perd;
555 D(bug("fbdv %d, fwdva = %d, fwdvb = %d\n", fbdv, fwdva, fwdvb));
556 D(bug("plbed %d, opbd = %d, perd = %d, ahbd = %d\n",
557 plbed, opbd, perd, ahbd));
559 /* FIXME: Some boards have 50Mhz and others 55MHz. How to distinguish? */
560 uint64_t vco = m * 50000000 + m / 2;
561 pd->pd_CPUFreq = vco / fwdva;
562 pd->pd_PLBFreq = vco / fwdva / plbed;
563 pd->pd_OPBFreq = pd->pd_PLBFreq / opbd;
564 pd->pd_EPBFreq = pd->pd_OPBFreq / perd;
565 pd->pd_PCIFreq = pd->pd_PLBFreq / ahbd;
567 /* Set decrementer interrupt to fire at a frequency of 50 Hz.*/
568 reg = rdspr(TCR);
569 wrspr(TCR, reg & ~(TCR_DIE | TCR_ARE));
570 wrspr(CCR1, rdspr(CCR1) & ~(0x80000000 >> 24));
571 wrspr(DECAR, pd->pd_CPUFreq / 50);
572 /* Enable decrementer timer interrupt and automatic reload of decrementer value. */
573 wrspr(TCR, reg | TCR_DIE | TCR_ARE);
576 static int Kernel_Init(LIBBASETYPEPTR LIBBASE)
578 int i;
579 struct PlatformData *pd;
581 uintptr_t krn_lowest = krnGetTagData(KRN_KernelLowest, 0, BootMsg);
582 uintptr_t krn_highest = krnGetTagData(KRN_KernelHighest, 0, BootMsg);
584 D(bug("[KRN] Entered Kernel_Init()\n"));
585 /* Get the PLB and CPU speed */
587 pd = AllocMem(sizeof(struct PlatformData), MEMF_PUBLIC|MEMF_CLEAR);
588 if (!pd)
589 return FALSE;
591 LIBBASE->kb_PlatformData = pd;
593 /* Stash the PVR value */
594 pd->pd_PVR = rdspr(PVR);
595 D(bug("[KRN] PVR: 0x%08x\n", pd->pd_PVR));
597 if (krnIsPPC440(pd->pd_PVR)) {
598 SetupClocking440(pd);
599 } else if (krnIsPPC460(pd->pd_PVR)) {
600 SetupClocking460(pd);
601 } else {
602 bug("kernel.resource: Unknown PVR model 0x%08x\n", pd->pd_PVR);
603 for (;;);
606 D(bug("[KRN] CPU Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_CPUFreq / 1000000));
607 D(bug("[KRN] PLB Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_PLBFreq / 1000000));
608 D(bug("[KRN] OPB Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_OPBFreq / 1000000));
609 D(bug("[KRN] EPB Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_EPBFreq / 1000000));
610 D(bug("[KRN] PCI Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_PCIFreq / 1000000));
612 /* 4K granularity for data sections */
613 krn_lowest &= 0xfffff000;
614 /* 64K granularity for code sections */
615 krn_highest = (krn_highest + 0xffff) & 0xffff0000;
617 D(bug("[KRN] Allowing userspace to flush caches\n"));
618 wrspr(MMUCR, rdspr(MMUCR) & ~0x000c0000);
620 for (i=0; i < 16; i++)
621 NEWLIST(&LIBBASE->kb_Exceptions[i]);
623 for (i=0; i < 64; i++)
624 NEWLIST(&LIBBASE->kb_Interrupts[i]);
626 LIBBASE->kb_ContextSize = sizeof(context_t);
628 D(bug("[KRN] Setting DebugInfo to %p\n", modlist));
629 LIBBASE->kb_PlatformData->pd_DebugInfo = (APTR)modlist;
631 D(bug("[KRN] Preparing kernel private memory\n"));
634 * Add MemHeader about kernel memory to public MemList to avoid invalid
635 * pointer debug messages for pointer that reference correctly into these
636 * mem regions.
638 krnCreateMemHeader("Kernel Memory", -10, (APTR)memlo, krn_lowest - ((uintptr_t)memlo & 0x00ffffff), MEMF_FAST | MEMF_KICK | MEMF_LOCAL | MEMF_24BITDMA);
639 krnCreateROMHeader("Kernel Reserved",
640 (APTR)0xff000000, (APTR)(memlo - 1));
641 krnCreateROMHeader("Kernel Code + Data Sections",
642 (APTR) ((uintptr_t) 0xff000000 + krn_lowest - 1),
643 (APTR) ((uintptr_t) 0xff000000 + krn_highest - 1));
646 * kernel.resource is ready to run, leave supervisor mode. External interrupts
647 * will be enabled during late exec init.
650 wrmsr(rdmsr() | MSR_PR);
651 D(bug("[KRN] Entered user mode \n"));
653 return TRUE;
656 ADD2INITLIB(Kernel_Init, 0)