4 * Created on: Aug 19, 2008
10 #include <aros/kernel.h>
11 #include <aros/symbolsets.h>
12 #include <exec/memory.h>
13 #include <exec/tasks.h>
14 #include <exec/alerts.h>
15 #include <exec/execbase.h>
17 #include <asm/mpc5200b.h>
18 #include <proto/kernel.h>
21 #include <proto/exec.h>
23 #include "exec_intern.h"
26 #include "kernel_intern.h"
27 #include LC_LIBDEFS_FILE
31 static void __attribute__((used
)) kernel_cstart(struct TagItem
*msg
);
32 struct OFWNode
*krnCopyOFWTree(struct OFWNode
*orig
);
33 int exec_main(struct TagItem
*msg
, void *entry
);
35 asm(".section .aros.init,\"ax\"\n\t"
37 ".type start,@function\n"
40 "mr %r29,%r3\n\t" /* Keep it for later */
43 "mtmsr %r0\n\t" /* Disable address translation */
46 /* Set up BAT registers with a very simple map. */
47 /* IBAT0 virtual 0xff800000 into physical 0x07800000, size 8MB, read only, super only, cached */
49 "ori %r0, %r0, 0x2 | 0xfc; "
50 "mtspr 528,%r0; " /* Clear all BAT entries */
52 "ori %r0,%r0,0x01 | 0x10; "
55 /* IBAT1 virtual 0x07800000 into physical 0x07800000, size 8MB, read only, super only, cached */
57 "ori %r0, %r0, 0x2 | 0xfc; "
58 "mtspr 530,%r0; " /* Clear all BAT entries */
60 "ori %r0,%r0,0x01 | 0x10; "
63 /* Clear IBAT1 - IBAT7 */
79 /* DBAT0 virtual 0xff000000, physical 0x07000000, size 8MB, read write, super only, cached */
81 "ori %r0, %r0, 0x2 | 0xfc; "
82 "mtspr 536,%r0; " /* Clear all BAT entries */
84 "ori %r0,%r0,0x02 | 0x10; "
86 /* DBAT1 virtual 0xff800000, physical 0x07800000, size 8MB, read only, super only, cached */
88 "ori %r0, %r0, 0x2 | 0xfc; "
89 "mtspr 538,%r0; " /* Clear all BAT entries */
91 "ori %r0,%r0,0x01 | 0x10; "
93 /* DBAT2 virtual 0x00000000, physical 0x00000000, 128MB, read write, super only, cached */
95 "ori %r0, %r0, 0x2 | 0x1ffc; "
96 "mtspr 540,%r0; " /* Clear all BAT entries */
98 "ori %r0,%r0,0x02 | 0x10; "
100 /* DBAT3 virtual 0xf0000000, physical 0xf0000000, 128KB, read write, super only, not cached */
102 "ori %r0, %r0, 0x3; "
105 "ori %r0,%r0,0x0a | 0x20; "
108 /* Clear DBAT3 - DBAT7 */
120 "mttbl %r0; mttbu %r0; mttbl %r0;"
122 /* Enable address translation again. All accesses will be done through BAT registers */
124 "mtmsr %r0;sync;isync;"
126 "lis %r9,tmp_stack_end@ha\n\t" /* Use temporary stack while clearing BSS */
127 "lwz %r1,tmp_stack_end@l(%r9)\n\t"
129 "bl __clear_bss\n\t" /* Clear BSS */
131 "lis %r11,target_address@ha\n\t" /* Load the address of init code in C */
132 "mr %r3,%r29\n\t" /* restore the message */
133 "lwz %r11,target_address@l(%r11)\n\t"
134 "lis %r9,stack_end@ha\n\t" /* Use brand new stack to do evil things */
136 "lwz %r1,stack_end@l(%r9)\n\t"
138 "bctr\n\t" /* And start the game... */
140 ".string \"Native/CORE v3 (" __DATE__
")\""
144 static void __attribute__((used
)) __clear_bss(struct TagItem
*msg
)
146 struct KernelBSS
*bss
;
148 bss
=(struct KernelBSS
*)krnGetTagData(KRN_KernelBss
, 0, msg
);
152 while (bss
->addr
&& bss
->len
)
154 bzero(bss
->addr
, bss
->len
);
160 static __attribute__((used
,section(".data"),aligned(16))) union {
161 struct TagItem bootup_tags
[64];
162 uint32_t tmp_stack
[128];
164 static const uint32_t *tmp_stack_end
__attribute__((used
, section(".text"))) = &tmp_struct
.tmp_stack
[124];
165 static uint32_t stack
[STACK_SIZE
] __attribute__((used
,aligned(16)));
166 static uint32_t stack_super
[STACK_SIZE
] __attribute__((used
,aligned(16)));
167 static const uint32_t *stack_end
__attribute__((used
, section(".text"))) = &stack
[STACK_SIZE
-4];
168 static const void *target_address
__attribute__((used
, section(".text"))) = (void*)kernel_cstart
;
169 static uint8_t *mmu_dir
;
170 static uint32_t *MBAR
;
172 /* Variables which should go to the .data section */
173 static struct OFWNode
*ofw_root_node
__attribute__((used
,section(".data"))) = NULL
;
174 struct TagItem
*BootMsg
__attribute__((used
,section(".data"))) = NULL
;
175 static uint8_t *memlo
__attribute__((used
,section(".data"))) = NULL
;
180 static void __attribute__((used
)) kernel_cstart(struct TagItem
*msg
)
182 D(bug("[KRN] EFika5200B Kernel build on %s\n", __DATE__
));
183 struct TagItem
*tmp
= tmp_struct
.bootup_tags
;
184 struct TagItem
*src
= msg
;
185 struct OFWNode
*node
;
187 wrspr(SPRG0
, (uint32_t)&stack_super
[STACK_SIZE
-4]);
190 wrmsr(rdmsr() | MSR_FP
);
192 /* MMU directory - 1MB is recommended size for systems with 128MB ram
193 * USE PHYSICAL ADDRESS HERE! */
194 mmu_dir
= (uint8_t *)0x07000000;
196 D(bug("[KRN] BootMsg @ %p\n", msg
));
200 D(bug("[KRN] Reboot detected\n"));
204 /* Set the memlo pointer right after MMU dir */
207 D(bug("[KRN] Copying TagList and data\n"));
209 while(msg
->ti_Tag
!= TAG_DONE
)
213 if (tmp
->ti_Tag
== KRN_CmdLine
)
215 tmp
->ti_Data
= (intptr_t)memlo
;
216 memlo
+= (strlen(msg
->ti_Data
) + 4) & ~3;
217 memcpy(tmp
->ti_Data
, msg
->ti_Data
, strlen(msg
->ti_Data
)+1);
218 D(bug("[KRN] CmdLine: '%s'\n", tmp
->ti_Data
));
220 else if (tmp
->ti_Tag
== KRN_KernelBss
)
222 struct KernelBSS
*bss_in
, *bss_out
;
224 bss_out
= (struct KernelBSS
*)memlo
;
225 bss_in
= msg
->ti_Data
;
227 tmp
->ti_Data
= (intptr_t)bss_out
;
229 while(bss_in
->addr
&& bss_in
->len
)
231 *bss_out
++ = *bss_in
++;
233 *bss_out
++ = *bss_in
++;
235 memlo
= (uint8_t *)bss_out
;
237 else if (tmp
->ti_Tag
== KRN_OpenFirmwareTree
)
239 ofw_root_node
= krnCopyOFWTree((struct OFWNode
*)msg
->ti_Data
);
240 tmp
->ti_Data
= (intptr_t)ofw_root_node
;
242 else if (tmp
->ti_Tag
== KRN_DebugInfo
)
245 struct MinList
*mlist
= tmp
->ti_Data
;
247 D(bug("[KRN] DebugInfo at %08x\n", modlist
));
249 module_t
*mod
= (module_t
*)memlo
;
251 ListLength(mlist
, modlength
);
254 memlo
= &mod
[modlength
];
256 D(bug("[KRN] Bootstrap loaded debug info for %d modules\n", modlength
));
258 /* Copy the module entries */
259 for (i
=0; i
< modlength
; i
++)
261 module_t
*m
= REMHEAD(mlist
);
264 mod
[i
].m_lowest
= m
->m_lowest
;
265 mod
[i
].m_highest
= m
->m_highest
;
267 NEWLIST(&mod
[i
].m_symbols
);
268 mod
[i
].m_name
= (char *)memlo
;
269 memlo
+= (strlen(m
->m_name
) + 4) & ~3;
270 strcpy(mod
[i
].m_name
, m
->m_name
);
272 ForeachNode(&m
->m_symbols
, sym
)
274 symbol_t
*newsym
= memlo
;
275 memlo
+= sizeof(symbol_t
);
277 newsym
->s_name
= memlo
;
278 memlo
+= (strlen(sym
->s_name
)+4)&~3;
279 strcpy(newsym
->s_name
, sym
->s_name
);
281 newsym
->s_lowest
= sym
->s_lowest
;
282 newsym
->s_highest
= sym
->s_highest
;
284 ADDTAIL(&mod
[i
].m_symbols
, newsym
);
288 D(bug("[KRN] Debug info uses %d KB of memory\n", ((intptr_t)memlo
- (intptr_t)mod
) >> 10));
296 memlo
= (char *)(((intptr_t)memlo
+ 4095) & ~4095);
298 BootMsg
= tmp_struct
.bootup_tags
;
302 mmu_init(mmu_dir
, 0x100000);
305 * Find the "/builtin" node in ofw tree and read it's reg property. It is
306 * the only way to obtain the value of MBAR register (that is, location of
307 * the CPU in-chip peripherials
309 ForeachNode(&ofw_root_node
->on_children
, node
)
311 if (!strcmp(node
->on_name
, "builtin"))
317 struct OFWProperty
*prop
= NULL
;
319 ForeachNode(&node
->on_properties
, prop
)
321 if (!strcmp(prop
->op_name
,"reg"))
327 MBAR
= *(uint32_t**)prop
->op_value
;
329 D(bug("[KRN] MBAR at %08x\n", MBAR
));
333 /* Enable dynamic power management */
334 wrspr(1008, 0x0010c000);
335 D(bug("[KRN] HID0=%08x HID1=%08x\n", rdspr(1008), rdspr(1009)));
339 D(bug("[KRN] Mapping 00003000-06ffffff range for public use\n"));
340 mmu_map_area(0x00003000, 0x00003000, 0x06ffd000, (2 << 3) | 2); // PP = 10, WIMG = 0010
342 D(bug("[KRN] Mapping %08x-%08x range for MBAR\n", MBAR
, MBAR
+ 0xc000 - 1));
343 mmu_map_area((uint64_t)MBAR
& 0xffffffff, (uint64_t)MBAR
& 0xffffffff, 0x0000c000, (5 << 3) | 2); // PP = 10, WIMG = 0101
345 D(bug("[KRN] Mapping %08x-%08x range for public read-only access\n", 0xff100000, memlo
- 1));
346 mmu_map_area(0xff100000, 0x07100000, (intptr_t)memlo
- 0xff100000, (2 << 3) | 1); // PP = 01, WIMG = 0010
348 uintptr_t krn_base
= krnGetTagData(KRN_KernelBase
, 0, BootMsg
);
349 uintptr_t krn_lowest
= krnGetTagData(KRN_KernelLowest
, 0, BootMsg
) & ~4095;
350 uintptr_t krn_highest
= (krnGetTagData(KRN_KernelHighest
, 0, BootMsg
) + 4095) & ~4095;
352 D(bug("[KRN] Mapping %08x-%08x range for supervisor\n", memlo
, (krn_lowest
^ 0xf8000000)-1));
353 mmu_map_area((uint32_t)memlo
, (uint32_t)memlo
^ 0xf8000000, (krn_lowest
^ 0xf8000000) - (intptr_t)memlo
, (2 << 3) | 0); // PP = 00, WIMG = 0010
355 D(bug("[KRN] Mapping %08x-%08x range for read-write\n", krn_lowest
^0xf8000000, (krn_base
^ 0xf8000000)-1));
356 mmu_map_area((uint32_t)krn_lowest
^0xf8000000, (uint32_t)krn_lowest
, (krn_base
- krn_lowest
), (2 << 3) | 2); // PP = 10, WIMG = 0010
358 D(bug("[KRN] Mapping %08x-%08x range for read-only\n", krn_base
^0xf8000000, (krn_highest
^ 0xf8000000)-1));
359 mmu_map_area((uint32_t)krn_base
^0xf8000000, (uint32_t)krn_base
, (krn_highest
- krn_base
), (2 << 3) | 3); // PP = 11, WIMG = 0010
361 D(bug("[KRN] Mapping %08x-%08x range for supervisor\n", krn_highest
^ 0xf8000000, 0xffffffff));
362 mmu_map_area((uint32_t)krn_highest
^0xf8000000, (uint32_t)krn_highest
, -(krn_highest
^0xf8000000), (2 << 3) | 0); // PP = 00, WIMG = 0010
364 /* Prepare the MemHeader structure for this region */
365 struct MemHeader
*mh
= (struct MemHeader
*)memlo
;
366 mh
->mh_First
= (struct MemChunk
*)((uint8_t *)mh
+ MEMHEADER_TOTAL
);
367 mh
->mh_Free
= ((krn_lowest
^0xf8000000) - MEMHEADER_TOTAL
- (intptr_t)memlo
) & ~(MEMCHUNK_TOTAL
-1);
368 mh
->mh_First
->mc_Next
= NULL
;
369 mh
->mh_First
->mc_Bytes
= mh
->mh_Free
;
371 D(bug("[KRN] Supervisor mem: %dKB free\n", mh
->mh_Free
>> 10));
373 exec_main(BootMsg
, NULL
);
376 D(bug("[KRN] Uhm? Nothing to do?\n[KRN] STOPPED\n"));
379 wrmsr(rdmsr() | MSR_EE
);
380 wrmsr(rdmsr() | MSR_POW
);
385 AROS_LH0I(struct TagItem
*, KrnGetBootInfo
,
386 struct KernelBase
*, KernelBase
, 10, Kernel
)
395 AROS_LH0(void *, KrnCreateContext
,
396 struct KernelBase
*, KernelBase
, 10, Kernel
)
402 uint32_t oldmsr
= goSuper();
404 ctx
= Allocate(KernelBase
->kb_SupervisorMem
, sizeof(context_t
));
405 bzero(ctx
, sizeof(context_t
));
410 ctx
= AllocMem(sizeof(context_t
), MEMF_PUBLIC
|MEMF_CLEAR
);
417 AROS_LH1(void, KrnDeleteContext
,
418 AROS_LHA(void *, context
, A0
),
419 struct KernelBase
*, KernelBase
, 10, Kernel
)
423 /* Was context in supervisor space? Deallocate it there :) */
424 if ((intptr_t)context
& 0xf0000000)
426 uint32_t oldmsr
= goSuper();
428 Deallocate(KernelBase
->kb_SupervisorMem
, context
, sizeof(context_t
));
433 FreeMem(context
, sizeof(context_t
));
435 /* Was this context owning a FPU? Make FPU totally free then */
436 if (KernelBase
->kb_FPUOwner
== context
)
437 KernelBase
->kb_FPUOwner
= NULL
;
443 struct OFWNode
*krnCopyOFWTree(struct OFWNode
*orig
)
445 uint32_t node_length
= sizeof(struct OFWNode
) + strlen(orig
->on_name
) + 1;
446 struct OFWNode
*new_node
= (struct OFWNode
*)memlo
;
447 struct OFWNode
*child
;
448 struct OFWProperty
*prop
, *new_prop
;
449 memlo
+= (node_length
+ 3) & ~3;
451 new_node
->on_name
= new_node
->on_storage
;
452 memcpy(new_node
->on_name
, orig
->on_name
, strlen(orig
->on_name
) + 1);
453 NEWLIST(&new_node
->on_children
);
454 NEWLIST(&new_node
->on_properties
);
456 ForeachNode(&orig
->on_properties
, prop
)
458 uint32_t prop_name_length
= strlen(prop
->op_name
) + 1;
459 uint32_t prop_length
= sizeof(struct OFWProperty
) + prop_name_length
+ prop
->op_length
;
461 new_prop
= (struct OFWProperty
*)memlo
;
462 memlo
+= (prop_length
+ 3) & ~3;
464 new_prop
->op_name
= new_prop
->op_storage
;
465 new_prop
->op_value
= &new_prop
->op_storage
[prop_name_length
];
466 new_prop
->op_length
= prop
->op_length
;
468 memcpy(new_prop
->op_name
, prop
->op_name
, strlen(prop
->op_name
)+1);
469 memcpy(new_prop
->op_value
, prop
->op_value
, prop
->op_length
);
471 ADDTAIL(&new_node
->on_properties
, new_prop
);
474 ForeachNode(&orig
->on_children
, child
)
475 ADDTAIL(&new_node
->on_children
, krnCopyOFWTree(child
));
485 struct Task
*idle_task
;
487 /* As soon as IdleTask gets CPU again, it records the current cycle count */
488 AROS_UFH1(void, idleCount
,
489 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
494 SysBase
->IdleCount
++;
500 * When CPU time gets lost, the cycle count spent in idle task is summed
501 * with the total idle time
503 AROS_UFH1(void, idleOff
,
504 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
509 idle_time
+= tbu2
- tbu1
;
515 * Idle task on Efika does not do much. It enters supervisor mode, enables
516 * interrupts (so that it survived even in Disable()'d state) and then enters
517 * power save mode. Once woken up, a Reschedule is forced.
519 void idleTask(struct ExecBase
*SysBase
, struct KernelBase
*KernelBase
)
521 D(bug("[KRN] IdleTask entered\n"));
527 /* Superstate() done quickly */
529 uint32_t msr
= goSuper();
530 uint32_t msr_sup
= rdmsr() | MSR_EE
| MSR_POW
;
531 /* Enable external/decrementer interrupts */
532 asm volatile("sync");
535 /* Changing the POW bit needs a context synchronization now. */
536 asm volatile("isync");
538 /* CPU needs few cycles to enter sleep state */
539 for (i
=0; i
< 10; i
++)
544 /* And reschedule! */
550 extern void *priv_KernelBase
;
551 struct MemHeader KernelMemory
;
553 void *(*__AllocMem
)();
555 #define ExecAllocMem(bytesize, requirements) \
556 AROS_CALL2(void *, __AllocMem, \
557 AROS_LCA(ULONG, byteSize, D0), \
558 AROS_LCA(ULONG, requirements, D1), \
559 struct ExecBase *, SysBase)
561 AROS_LH2(APTR
, AllocMem
,
562 AROS_LHA(ULONG
, byteSize
, D0
),
563 AROS_LHA(ULONG
, requirements
, D1
),
564 struct ExecBase
*, SysBase
, 33, Kernel
)
568 return ExecAllocMem(bytesize
, requirements
& ~MEMF_CHIP
);
574 static int Kernel_Init(LIBBASETYPEPTR LIBBASE
)
577 struct ExecBase
*SysBase
= getSysBase();
580 uintptr_t krn_lowest
= (krnGetTagData(KRN_KernelLowest
, 0, BootMsg
) & ~4095) ^ 0xf8000000;
581 uintptr_t krn_highest
= ((krnGetTagData(KRN_KernelHighest
, 0, BootMsg
) + 4095) & ~4095) ^ 0xf8000000;
582 char *cmd
= krnGetTagData(KRN_CmdLine
, 0, BootMsg
);
584 KernelMemory
.mh_Node
.ln_Name
= "Kernel";
585 KernelMemory
.mh_Node
.ln_Type
= NT_MEMORY
;
586 KernelMemory
.mh_Node
.ln_Pri
= -128;
587 KernelMemory
.mh_Attributes
= MEMF_KICK
;
588 KernelMemory
.mh_First
= NULL
;
589 KernelMemory
.mh_Free
= 0;
590 KernelMemory
.mh_Lower
= krn_lowest
;
591 KernelMemory
.mh_Upper
= krn_highest
;
594 Enqueue(&SysBase
->MemList
, &KernelMemory
.mh_Node
);
597 NEWLIST(&LIBBASE
->kb_Modules
);
598 NEWLIST(&LIBBASE
->kb_DeadTasks
);
600 /* Check whether the user passed realchip parameter. */
605 uint32_t temp
= strcspn(cmd
, " ");
607 if (strncmp(cmd
, "realchip", 8) == 0)
612 cmd
= stpblk(cmd
+temp
);
617 * If no realchip parameter was given, the AllocMem function will be patched with a stub
618 * which *always* clears the MEMF_CHIP flag.
622 __AllocMem
= SetFunction(SysBase
, -33*LIB_VECTSIZE
, AROS_SLIB_ENTRY(AllocMem
, Kernel
));
626 * Set the KernelBase into SPRG4. At this stage the SPRG5 should be already set by
627 * exec.library itself.
629 wrspr(SPRG4
, LIBBASE
);
631 LIBBASE
->kb_FPUOwner
= NULL
;
633 D(bug("[KRN] Kernel resource post-exec init.\n"));
635 for (i
=0; i
< 21; i
++)
636 NEWLIST(&LIBBASE
->kb_Exceptions
[i
]);
638 for (i
=0; i
< 64; i
++)
639 NEWLIST(&LIBBASE
->kb_Interrupts
[i
]);
641 /* Prepare private memory block */
642 LIBBASE
->kb_SupervisorMem
= (struct MemHeader
*)memlo
;
645 * kernel.resource is ready to run. Enable external interrupts and leave
648 wrmsr(rdmsr() | (MSR_EE
|MSR_FP
));
649 D(bug("[KRN] Interrupts enabled\n"));
651 asm volatile("mtdec %0"::"r"(33000000/1000));
653 wrmsr(rdmsr() | (MSR_PR
));
654 D(bug("[KRN] Entered user mode\n"));
656 priv_KernelBase
= LIBBASE
;
659 /* Add idle task now. */
663 struct TagItem tags
[] = {
664 { TASKTAG_ARG1
, (IPTR
)SysBase
},
665 { TASKTAG_ARG2
, (IPTR
)LIBBASE
},
668 /* Allocate MemEntry for this task and stack */
669 ml
= (struct MemList
*)AllocMem(sizeof(struct MemList
)+sizeof(struct MemEntry
),
670 MEMF_PUBLIC
|MEMF_CLEAR
);
671 t
= (struct Task
*) AllocMem(sizeof(struct Task
), MEMF_CLEAR
|MEMF_PUBLIC
);
672 s
= (uint8_t *) AllocMem(4096, MEMF_CLEAR
|MEMF_PUBLIC
);
674 if( !ml
|| !t
|| !s
)
676 bug("ERROR: Cannot create Idle Task!\n");
677 Alert( AT_DeadEnd
| AG_NoMemory
| AN_ExecLib
);
680 ml
->ml_NumEntries
= 2;
681 ml
->ml_ME
[0].me_Addr
= t
;
682 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
683 ml
->ml_ME
[1].me_Addr
= s
;
684 ml
->ml_ME
[1].me_Length
= 4096;
686 NEWLIST(&t
->tc_MemEntry
);
687 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
689 t
->tc_SPUpper
= s
+ 4096 - SP_OFFSET
;
690 #if AROS_STACK_GROWS_DOWNWARDS
691 t
->tc_SPReg
= (char *)t
->tc_SPUpper
- SP_OFFSET
;
693 t
->tc_SPReg
= (char *)t
->tc_SPLower
+ SP_OFFSET
;
696 t
->tc_Node
.ln_Name
= "Idle Task";
697 t
->tc_Node
.ln_Pri
= -128;
698 t
->tc_Launch
= &idleCount
;
699 t
->tc_Switch
= &idleOff
;
700 t
->tc_Flags
= TF_LAUNCH
| TF_SWITCH
;
701 NewAddTask(t
, &idleTask
, NULL
, &tags
);
708 ADD2INITLIB(Kernel_Init
, 0)