Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / arch / ppc-sam440 / kernel / kernel_startup.c
blobd6137930fa0137a2702308d2f79713b07ef676ce
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);
242 wrspr(CCR1, rdspr(CCR1) | (0x80000000 >> 24));
244 /* First message after FPU is enabled, otherwise illegal instruction */
245 D(bug("[KRN] Sam440 Kernel built on %s\n", __DATE__));
247 wrspr(SPRG0, 0);
248 wrspr(SPRG1, 0);
249 wrspr(SPRG2, 0);
250 wrspr(SPRG3, 0);
251 wrspr(SPRG4, 0); /* Clear KernelBase */
252 wrspr(SPRG5, 0); /* Clear SysBase */
254 D(bug("[KRN] Kernel resource pre-exec init\n"));
255 D(bug("[KRN] MSR=%08x CRR0=%08x CRR1=%08x\n", rdmsr(), rdspr(CCR0), rdspr(CCR1)));
256 D(bug("[KRN] USB config %08x\n", rddcr(SDR0_USB0)));
258 D(bug("[KRN] msg @ %p\n", msg));
259 D(bug("[KRN] Copying msg data\n"));
260 while(msg->ti_Tag != TAG_DONE)
262 *tmp = *msg;
264 if (tmp->ti_Tag == KRN_CmdLine)
266 strcpy(CmdLine, (char*) msg->ti_Data);
267 tmp->ti_Data = (STACKIPTR) CmdLine;
268 D(bug("[KRN] CmdLine: %s\n", tmp->ti_Data));
270 else if (tmp->ti_Tag == KRN_BootLoader)
272 tmp->ti_Data = (STACKIPTR) memlo;
273 strcpy((char*)tmp->ti_Data, (const char*) msg->ti_Data);
274 memlo += (strlen((char *)memlo) + 4) & ~3;
275 D(bug("[KRN] BootLoader: %s\n", tmp->ti_Data));
277 else if (tmp->ti_Tag == KRN_DebugInfo)
279 int i;
280 struct MinList *mlist = (struct MinList *)tmp->ti_Data;
281 module_t *mod;
283 D(bug("[KRN] DebugInfo at %08x\n", mlist));
285 modlist = (struct MinList *)memlo;
286 memlo += sizeof(*modlist);
287 NEWLIST(modlist);
289 mod = (module_t *)memlo;
291 ListLength(mlist, modlength);
292 memlo = (uintptr_t)&mod[modlength];
294 D(bug("[KRN] Bootstrap loaded debug info for %d modules\n", modlength));
295 /* Copy the module entries */
296 for (i=0; i < modlength; i++)
298 module_t *m = (module_t *)REMHEAD(mlist);
299 symbol_t *sym;
300 ULONG str_l = ~0, str_h = 0;
302 D(bug("[KRN] Module %s\n", m->m_name));
304 /* Discover size of the string table */
305 ForeachNode(&m->m_symbols, sym) {
306 ULONG end = (ULONG)sym->s_name + strlen(sym->s_name) + 1 + 1;
307 if ((ULONG)sym->s_name < str_l)
308 str_l = (ULONG)sym->s_name;
309 if (end > str_h)
310 str_h = end;
313 if (str_l > str_h)
314 str_h = str_l = 0;
316 mod[i].m_lowest = m->m_lowest;
317 mod[i].m_highest = m->m_highest;
318 mod[i].m_str = (char *)memlo;
319 memcpy(mod[i].m_str, (char *)str_l, str_h - str_l);
320 memlo += ((str_h - str_l) + 3) & ~3;
321 mod[i].m_name = (char *)memlo;
322 memlo += (strlen(m->m_name) + 4) & ~3;
323 strcpy(mod[i].m_name, m->m_name);
325 NEWLIST(&mod[i].m_symbols);
327 ForeachNode(&m->m_symbols, sym)
329 symbol_t *newsym = (symbol_t *)memlo;
330 memlo += sizeof(symbol_t);
332 newsym->s_name = (IPTR)sym->s_name - str_l + mod[i].m_str;
333 newsym->s_lowest = sym->s_lowest;
334 newsym->s_highest = sym->s_highest;
336 ADDTAIL(&mod[i].m_symbols, newsym);
339 ADDTAIL(modlist, &mod[i]);
342 D(bug("[KRN] Debug info uses %d KB of memory\n", ((intptr_t)memlo - (intptr_t)modlist) >> 10));
343 D(bug("[KRN] Debug info relocated from %p to %p\n", tmp->ti_Data, modlist));
345 /* Ugh. Parthenope doesn't use the ELF_ModuleInfo format.
346 * Prevent debug.library from becoming confused.
348 tmp->ti_Data = 0;
351 ++tmp;
352 ++msg;
355 memlo = (memlo + 4095) & ~4095;
357 BootMsg = tmp_struct.bootup_tags;
358 D(bug("[KRN] BootMsg @ %p\n", BootMsg));
360 /* Do a slightly more sophisticated MMU map */
361 mmu_init(BootMsg);
362 intr_init();
364 /* Initialize exec.library */
365 exec_main(BootMsg, NULL);
367 bug("[KRN] Uhm? Nothing to do?\n[KRN] STOPPED\n");
370 * Do never ever try to return. This code would attempt to go back to the physical address
371 * of asm trampoline, not the virtual one!
373 for (;;);
376 void SetupClocking440(struct PlatformData *pd)
378 /* PLL divisors */
379 wrdcr(CPR0_CFGADDR, CPR0_PLLD0);
380 uint32_t reg = rddcr(CPR0_CFGDATA);
382 uint32_t fbdv = (reg >> 24) & 0x1f;
383 if (fbdv == 0)
384 fbdv = 32;
385 uint32_t fwdva = (reg >> 16) & 0x1f;
386 if (fwdva == 0)
387 fwdva = 16;
388 uint32_t fwdvb = (reg >> 8) & 7;
389 if (fwdvb == 0)
390 fwdvb = 8;
391 uint32_t lfbdv = reg & 0x3f;
392 if (lfbdv == 0)
393 lfbdv = 64;
395 /* OPB clock divisor */
396 wrdcr(CPR0_CFGADDR, CPR0_OPBD0);
397 reg = rddcr(CPR0_CFGDATA);
398 uint32_t opbdv0 = (reg >> 24) & 3;
399 if (opbdv0 == 0)
400 opbdv0 = 4;
402 /* Peripheral clock divisor */
403 wrdcr(CPR0_CFGADDR, CPR0_PERD0);
404 reg = rddcr(CPR0_CFGDATA);
405 uint32_t perdv0 = (reg >> 24) & 7;
406 if (perdv0 == 0)
407 perdv0 = 8;
409 /* PCI clock divisor */
410 wrdcr(CPR0_CFGADDR, CPR0_SPCID);
411 reg = rddcr(CPR0_CFGDATA);
412 uint32_t spcid0 = (reg >> 24) & 3;
413 if (spcid0 == 0)
414 spcid0 = 4;
416 /* Primary B divisor */
417 wrdcr(CPR0_CFGADDR, CPR0_PRIMBD0);
418 reg = rddcr(CPR0_CFGDATA);
419 uint32_t prbdv0 = (reg >> 24) & 7;
420 if (prbdv0 == 0)
421 prbdv0 = 8;
423 /* All divisors there. Read PLL control register and calculate the m value (see 44ep.book) */
424 wrdcr(CPR0_CFGADDR, CPR0_PLLC0);
425 reg = rddcr(CPR0_CFGDATA);
426 uint32_t m;
427 switch ((reg >> 24) & 3) /* Feedback selector */
429 case 0:/* PLL output (A or B) */
430 if ((reg & 0x20000000)) /* PLLOUTB */
431 m = lfbdv * fbdv * fwdvb;
432 else
433 m = lfbdv * fbdv * fwdva;
434 break;
435 case 1: /* CPU */
436 m = fbdv * fwdva;
437 default:
438 m = perdv0 * opbdv0 * fwdvb;
441 uint32_t vco = (m * 66666666) + m/2;
442 pd->pd_CPUFreq = vco / fwdva;
443 pd->pd_PLBFreq = vco / fwdvb / perdv0;
444 pd->pd_OPBFreq = pd->pd_PLBFreq / opbdv0;
445 pd->pd_EPBFreq = pd->pd_PLBFreq / perdv0;
446 pd->pd_PCIFreq = pd->pd_PLBFreq / spcid0;
449 * Slow down the decrement interrupt a bit. Rough guess is that UBoot has left us with
450 * 1kHz DEC counter. Enable decrementer timer and automatic reload of decrementer value.
452 wrspr(DECAR, pd->pd_OPBFreq / 50);
453 wrspr(TCR, rdspr(TCR) | TCR_DIE | TCR_ARE);
457 const uint8_t fbdv_map[256] = {
458 1, 123, 117, 251, 245, 69, 111, 125,
459 119, 95, 105, 197, 239, 163, 63, 253,
460 247, 187, 57, 223, 233, 207, 157, 71,
461 113, 15, 89, 37, 191, 19, 99, 127,
462 121, 109, 93, 61, 185, 155, 13, 97,
463 107, 11, 9, 81, 31, 49, 83, 199,
464 241, 33, 181, 143, 217, 173, 51, 165,
465 65, 85, 151, 147, 227, 41, 201, 255,
466 249, 243, 195, 237, 221, 231, 35, 189,
467 59, 183, 79, 29, 141, 215, 145, 225,
468 235, 219, 27, 139, 137, 135, 175, 209,
469 159, 53, 45, 177, 211, 23, 167, 73,
470 115, 67, 103, 161, 55, 205, 87, 17,
471 91, 153, 7, 47, 179, 171, 149, 39,
472 193, 229, 77, 213, 25, 133, 43, 21,
473 101, 203, 5, 169, 75, 131, 3, 129,
474 1, 250, 244, 124, 118, 196, 238, 252,
475 246, 222, 232, 70, 112, 36, 190, 126,
476 120, 60, 184, 96, 106, 80, 30, 198,
477 240, 142, 216, 164, 64, 146, 226, 254,
478 248, 236, 220, 188, 58, 28, 140, 224,
479 234, 138, 136, 208, 158, 176, 210, 72,
480 114, 160, 54, 16, 90, 46, 178, 38,
481 192, 212, 24, 20, 100, 168, 74, 128,
482 122, 116, 68, 110, 94, 104, 162, 62,
483 186, 56, 206, 156, 14, 88, 18, 98,
484 108, 92, 154, 12, 10, 8, 48, 82,
485 32, 180, 172, 50, 84, 150, 40, 200,
486 242, 194, 230, 34, 182, 78, 214, 144,
487 218, 26, 134, 174, 52, 44, 22, 166,
488 66, 102, 204, 86, 152, 6, 170, 148,
489 228, 76, 132, 42, 202, 4, 130, 2,
492 static const uint8_t fwdv_map[16] = {
493 1, 2, 14, 9, 4, 11, 16, 13,
494 12, 5, 6, 15, 10, 7, 8, 3,
497 void SetupClocking460(struct PlatformData *pd)
499 uint32_t reg;
501 /* PLL divisors */
502 wrdcr(CPR0_CFGADDR, CPR0_PLLD);
503 reg = rddcr(CPR0_CFGDATA);
505 uint32_t fbdv = fbdv_map[(reg >> 24) & 0xff];
506 uint32_t fwdva = fwdv_map[((reg >> 16) & 0xf)];
507 uint32_t fwdvb = fwdv_map[(reg >> 8) & 0xf];
508 (void)fwdvb; // Unused
510 /* Early PLL divisor */
511 wrdcr(CPR0_CFGADDR, CPR0_PLBED);
512 reg = rddcr(CPR0_CFGDATA);
513 uint32_t plbed = (reg >> 24) & 0x7;
514 if (plbed == 0)
515 plbed = 8;
517 /* OPB clock divisor */
518 wrdcr(CPR0_CFGADDR, CPR0_OPBD);
519 reg = rddcr(CPR0_CFGDATA);
520 uint32_t opbd = (reg >> 24) & 3;
521 if (opbd == 0)
522 opbd = 4;
524 /* Peripheral clock divisor */
525 wrdcr(CPR0_CFGADDR, CPR0_PERD);
526 reg = rddcr(CPR0_CFGDATA);
527 uint32_t perd = (reg >> 24) & 3;
528 if (perd == 0)
529 perd = 4;
531 /* AHB clock divisor */
532 wrdcr(CPR0_CFGADDR, CPR0_AHBD);
533 reg = rddcr(CPR0_CFGDATA);
534 uint32_t ahbd = (reg >> 24) & 1;
535 if (ahbd == 0)
536 ahbd = 2;
538 /* All divisors there.
539 * Read PLL control register and calculate the m value
541 wrdcr(CPR0_CFGADDR, CPR0_PLLC);
542 reg = rddcr(CPR0_CFGDATA);
544 uint32_t m;
545 if (((reg >> 24) & 3) == 0) {
546 /* PLL internal feedback */
547 m = fbdv;
548 } else {
549 /* PLL Per-Clock feedback */
550 m = fwdva * plbed * opbd * ahbd;
553 D(bug("fbdv %d, fwdva = %d, fwdvb = %d\n", fbdv, fwdva, fwdvb));
554 D(bug("plbed %d, opbd = %d, perd = %d, ahbd = %d\n",
555 plbed, opbd, perd, ahbd));
557 uint64_t vco = m * 55000000;
558 pd->pd_CPUFreq = vco / fwdva;
559 pd->pd_PLBFreq = vco / fwdva / plbed;
560 pd->pd_OPBFreq = pd->pd_PLBFreq / opbd;
561 pd->pd_EPBFreq = pd->pd_OPBFreq / perd;
562 pd->pd_PCIFreq = pd->pd_PLBFreq / ahbd;
565 * Slow down the decrement interrupt a bit. Rough guess is that UBoot has left us with
566 * 1kHz DEC counter. Enable decrementer timer and automatic reload of decrementer value.
568 wrspr(DECAR, pd->pd_OPBFreq / 5);
569 wrspr(TCR, rdspr(TCR) | TCR_DIE | TCR_ARE);
570 wrspr(CCR1, rdspr(CCR1) & ~(0x80000000 >> 24));
573 static int Kernel_Init(LIBBASETYPEPTR LIBBASE)
575 int i;
576 struct PlatformData *pd;
578 uintptr_t krn_lowest = krnGetTagData(KRN_KernelLowest, 0, BootMsg);
579 uintptr_t krn_highest = krnGetTagData(KRN_KernelHighest, 0, BootMsg);
581 D(bug("[KRN] Entered Kernel_Init()\n"));
582 /* Get the PLB and CPU speed */
584 pd = AllocMem(sizeof(struct PlatformData), MEMF_PUBLIC|MEMF_CLEAR);
585 if (!pd)
586 return FALSE;
588 LIBBASE->kb_PlatformData = pd;
590 /* Stash the PVR value */
591 pd->pd_PVR = rdspr(PVR);
592 D(bug("[KRN] PVR: 0x%08x\n", pd->pd_PVR));
594 if (krnIsPPC440(pd->pd_PVR)) {
595 SetupClocking440(pd);
596 } else if (krnIsPPC460(pd->pd_PVR)) {
597 SetupClocking460(pd);
598 } else {
599 bug("kernel.resource: Unknown PVR model 0x%08x\n", pd->pd_PVR);
600 for (;;);
603 D(bug("[KRN] CPU Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_CPUFreq / 1000000));
604 D(bug("[KRN] PLB Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_PLBFreq / 1000000));
605 D(bug("[KRN] OPB Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_OPBFreq / 1000000));
606 D(bug("[KRN] EPB Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_EPBFreq / 1000000));
607 D(bug("[KRN] PCI Speed: %dMz\n", LIBBASE->kb_PlatformData->pd_PCIFreq / 1000000));
609 /* 4K granularity for data sections */
610 krn_lowest &= 0xfffff000;
611 /* 64K granularity for code sections */
612 krn_highest = (krn_highest + 0xffff) & 0xffff0000;
614 D(bug("[KRN] Allowing userspace to flush caches\n"));
615 wrspr(MMUCR, rdspr(MMUCR) & ~0x000c0000);
617 for (i=0; i < 16; i++)
618 NEWLIST(&LIBBASE->kb_Exceptions[i]);
620 for (i=0; i < 64; i++)
621 NEWLIST(&LIBBASE->kb_Interrupts[i]);
623 LIBBASE->kb_ContextSize = sizeof(context_t);
625 D(bug("[KRN] Setting DebugInfo to %p\n", modlist));
626 LIBBASE->kb_PlatformData->pd_DebugInfo = (APTR)modlist;
628 D(bug("[KRN] Preparing kernel private memory\n"));
631 * Add MemHeader about kernel memory to public MemList to avoid invalid
632 * pointer debug messages for pointer that reference correctly into these
633 * mem regions.
635 krnCreateMemHeader("Kernel Memory", -10, (APTR)memlo, krn_lowest - ((uintptr_t)memlo & 0x00ffffff), MEMF_FAST | MEMF_KICK | MEMF_LOCAL | MEMF_24BITDMA);
636 krnCreateROMHeader("Kernel Reserved",
637 (APTR)0xff000000, (APTR)(memlo - 1));
638 krnCreateROMHeader("Kernel Code + Data Sections",
639 (APTR) ((uintptr_t) 0xff000000 + krn_lowest - 1),
640 (APTR) ((uintptr_t) 0xff000000 + krn_highest - 1));
643 * kernel.resource is ready to run, leave supervisor mode. External interrupts
644 * will be enabled during late exec init.
647 wrmsr(rdmsr() | MSR_PR);
648 D(bug("[KRN] Entered user mode \n"));
650 return TRUE;
653 ADD2INITLIB(Kernel_Init, 0)