2 Copyright © 2008-2014, The AROS Development Team. All rights reserved.
8 #include <aros/kernel.h>
9 #include <aros/symbolsets.h>
10 #include <exec/memory.h>
11 #include <exec/tasks.h>
12 #include <exec/alerts.h>
13 #include <exec/execbase.h>
15 #include <asm/mpc5200b.h>
16 #include <proto/kernel.h>
19 #include <proto/exec.h>
21 #include "exec_intern.h"
24 #include "kernel_intern.h"
25 #include LC_LIBDEFS_FILE
29 static void __attribute__((used
)) kernel_cstart(struct TagItem
*msg
);
30 struct OFWNode
*krnCopyOFWTree(struct OFWNode
*orig
);
31 int exec_main(struct TagItem
*msg
, void *entry
);
33 asm(".section .aros.init,\"ax\"\n\t"
35 ".type start,@function\n"
38 "mr %r29,%r3\n\t" /* Keep it for later */
41 "mtmsr %r0\n\t" /* Disable address translation */
44 /* Set up BAT registers with a very simple map. */
45 /* IBAT0 virtual 0xff800000 into physical 0x07800000, size 8MB, read only, super only, cached */
47 "ori %r0, %r0, 0x2 | 0xfc; "
48 "mtspr 528,%r0; " /* Clear all BAT entries */
50 "ori %r0,%r0,0x01 | 0x10; "
53 /* IBAT1 virtual 0x07800000 into physical 0x07800000, size 8MB, read only, super only, cached */
55 "ori %r0, %r0, 0x2 | 0xfc; "
56 "mtspr 530,%r0; " /* Clear all BAT entries */
58 "ori %r0,%r0,0x01 | 0x10; "
61 /* Clear IBAT1 - IBAT7 */
77 /* DBAT0 virtual 0xff000000, physical 0x07000000, size 8MB, read write, super only, cached */
79 "ori %r0, %r0, 0x2 | 0xfc; "
80 "mtspr 536,%r0; " /* Clear all BAT entries */
82 "ori %r0,%r0,0x02 | 0x10; "
84 /* DBAT1 virtual 0xff800000, physical 0x07800000, size 8MB, read only, super only, cached */
86 "ori %r0, %r0, 0x2 | 0xfc; "
87 "mtspr 538,%r0; " /* Clear all BAT entries */
89 "ori %r0,%r0,0x01 | 0x10; "
91 /* DBAT2 virtual 0x00000000, physical 0x00000000, 128MB, read write, super only, cached */
93 "ori %r0, %r0, 0x2 | 0x1ffc; "
94 "mtspr 540,%r0; " /* Clear all BAT entries */
96 "ori %r0,%r0,0x02 | 0x10; "
98 /* DBAT3 virtual 0xf0000000, physical 0xf0000000, 128KB, read write, super only, not cached */
100 "ori %r0, %r0, 0x3; "
103 "ori %r0,%r0,0x0a | 0x20; "
106 /* Clear DBAT3 - DBAT7 */
118 "mttbl %r0; mttbu %r0; mttbl %r0;"
120 /* Enable address translation again. All accesses will be done through BAT registers */
122 "mtmsr %r0;sync;isync;"
124 "lis %r9,tmp_stack_end@ha\n\t" /* Use temporary stack while clearing BSS */
125 "lwz %r1,tmp_stack_end@l(%r9)\n\t"
127 "bl __clear_bss\n\t" /* Clear BSS */
129 "lis %r11,target_address@ha\n\t" /* Load the address of init code in C */
130 "mr %r3,%r29\n\t" /* restore the message */
131 "lwz %r11,target_address@l(%r11)\n\t"
132 "lis %r9,stack_end@ha\n\t" /* Use brand new stack to do evil things */
134 "lwz %r1,stack_end@l(%r9)\n\t"
136 "bctr\n\t" /* And start the game... */
138 ".string \"Native/CORE v3 (" __DATE__
")\""
142 static void __attribute__((used
)) __clear_bss(struct TagItem
*msg
)
144 struct KernelBSS
*bss
;
146 bss
=(struct KernelBSS
*)krnGetTagData(KRN_KernelBss
, 0, msg
);
150 while (bss
->addr
&& bss
->len
)
152 memset(bss
->addr
, 0, bss
->len
);
158 static __attribute__((used
,section(".data"),aligned(16))) union {
159 struct TagItem bootup_tags
[64];
160 uint32_t tmp_stack
[128];
162 static const uint32_t *tmp_stack_end
__attribute__((used
, section(".text"))) = &tmp_struct
.tmp_stack
[124];
163 static uint32_t stack
[STACK_SIZE
] __attribute__((used
,aligned(16)));
164 static uint32_t stack_super
[STACK_SIZE
] __attribute__((used
,aligned(16)));
165 static const uint32_t *stack_end
__attribute__((used
, section(".text"))) = &stack
[STACK_SIZE
-4];
166 static const void *target_address
__attribute__((used
, section(".text"))) = (void*)kernel_cstart
;
167 static uint8_t *mmu_dir
;
168 static uint32_t *MBAR
;
170 /* Variables which should go to the .data section */
171 static struct OFWNode
*ofw_root_node
__attribute__((used
,section(".data"))) = NULL
;
172 struct TagItem
*BootMsg
__attribute__((used
,section(".data"))) = NULL
;
173 static uint8_t *memlo
__attribute__((used
,section(".data"))) = NULL
;
178 static void __attribute__((used
)) kernel_cstart(struct TagItem
*msg
)
180 D(bug("[KRN] EFika5200B Kernel build on %s\n", __DATE__
));
181 struct TagItem
*tmp
= tmp_struct
.bootup_tags
;
182 struct TagItem
*src
= msg
;
183 struct OFWNode
*node
;
185 wrspr(SPRG0
, (uint32_t)&stack_super
[STACK_SIZE
-4]);
188 wrmsr(rdmsr() | MSR_FP
);
190 /* MMU directory - 1MB is recommended size for systems with 128MB ram
191 * USE PHYSICAL ADDRESS HERE! */
192 mmu_dir
= (uint8_t *)0x07000000;
194 D(bug("[KRN] BootMsg @ %p\n", msg
));
198 D(bug("[KRN] Reboot detected\n"));
202 /* Set the memlo pointer right after MMU dir */
205 D(bug("[KRN] Copying TagList and data\n"));
207 while(msg
->ti_Tag
!= TAG_DONE
)
211 if (tmp
->ti_Tag
== KRN_CmdLine
)
213 tmp
->ti_Data
= (intptr_t)memlo
;
214 memlo
+= (strlen(msg
->ti_Data
) + 4) & ~3;
215 memcpy(tmp
->ti_Data
, msg
->ti_Data
, strlen(msg
->ti_Data
)+1);
216 D(bug("[KRN] CmdLine: '%s'\n", tmp
->ti_Data
));
218 else if (tmp
->ti_Tag
== KRN_KernelBss
)
220 struct KernelBSS
*bss_in
, *bss_out
;
222 bss_out
= (struct KernelBSS
*)memlo
;
223 bss_in
= msg
->ti_Data
;
225 tmp
->ti_Data
= (intptr_t)bss_out
;
227 while(bss_in
->addr
&& bss_in
->len
)
229 *bss_out
++ = *bss_in
++;
231 *bss_out
++ = *bss_in
++;
233 memlo
= (uint8_t *)bss_out
;
235 else if (tmp
->ti_Tag
== KRN_OpenFirmwareTree
)
237 ofw_root_node
= krnCopyOFWTree((struct OFWNode
*)msg
->ti_Data
);
238 tmp
->ti_Data
= (intptr_t)ofw_root_node
;
240 else if (tmp
->ti_Tag
== KRN_DebugInfo
)
243 struct MinList
*mlist
= tmp
->ti_Data
;
245 D(bug("[KRN] DebugInfo at %08x\n", modlist
));
247 module_t
*mod
= (module_t
*)memlo
;
249 ListLength(mlist
, modlength
);
252 memlo
= &mod
[modlength
];
254 D(bug("[KRN] Bootstrap loaded debug info for %d modules\n", modlength
));
256 /* Copy the module entries */
257 for (i
=0; i
< modlength
; i
++)
259 module_t
*m
= REMHEAD(mlist
);
262 mod
[i
].m_lowest
= m
->m_lowest
;
263 mod
[i
].m_highest
= m
->m_highest
;
265 NEWLIST(&mod
[i
].m_symbols
);
266 mod
[i
].m_name
= (char *)memlo
;
267 memlo
+= (strlen(m
->m_name
) + 4) & ~3;
268 strcpy(mod
[i
].m_name
, m
->m_name
);
270 ForeachNode(&m
->m_symbols
, sym
)
272 symbol_t
*newsym
= memlo
;
273 memlo
+= sizeof(symbol_t
);
275 newsym
->s_name
= memlo
;
276 memlo
+= (strlen(sym
->s_name
)+4)&~3;
277 strcpy(newsym
->s_name
, sym
->s_name
);
279 newsym
->s_lowest
= sym
->s_lowest
;
280 newsym
->s_highest
= sym
->s_highest
;
282 ADDTAIL(&mod
[i
].m_symbols
, newsym
);
286 D(bug("[KRN] Debug info uses %d KB of memory\n", ((intptr_t)memlo
- (intptr_t)mod
) >> 10));
294 memlo
= (char *)(((intptr_t)memlo
+ 4095) & ~4095);
296 BootMsg
= tmp_struct
.bootup_tags
;
300 mmu_init(mmu_dir
, 0x100000);
303 * Find the "/builtin" node in ofw tree and read it's reg property. It is
304 * the only way to obtain the value of MBAR register (that is, location of
305 * the CPU in-chip peripherials
307 ForeachNode(&ofw_root_node
->on_children
, node
)
309 if (!strcmp(node
->on_name
, "builtin"))
315 struct OFWProperty
*prop
= NULL
;
317 ForeachNode(&node
->on_properties
, prop
)
319 if (!strcmp(prop
->op_name
,"reg"))
325 MBAR
= *(uint32_t**)prop
->op_value
;
327 D(bug("[KRN] MBAR at %08x\n", MBAR
));
331 /* Enable dynamic power management */
332 wrspr(1008, 0x0010c000);
333 D(bug("[KRN] HID0=%08x HID1=%08x\n", rdspr(1008), rdspr(1009)));
337 D(bug("[KRN] Mapping 00003000-06ffffff range for public use\n"));
338 mmu_map_area(0x00003000, 0x00003000, 0x06ffd000, (2 << 3) | 2); // PP = 10, WIMG = 0010
340 D(bug("[KRN] Mapping %08x-%08x range for MBAR\n", MBAR
, MBAR
+ 0xc000 - 1));
341 mmu_map_area((uint64_t)MBAR
& 0xffffffff, (uint64_t)MBAR
& 0xffffffff, 0x0000c000, (5 << 3) | 2); // PP = 10, WIMG = 0101
343 D(bug("[KRN] Mapping %08x-%08x range for public read-only access\n", 0xff100000, memlo
- 1));
344 mmu_map_area(0xff100000, 0x07100000, (intptr_t)memlo
- 0xff100000, (2 << 3) | 1); // PP = 01, WIMG = 0010
346 uintptr_t krn_base
= krnGetTagData(KRN_KernelBase
, 0, BootMsg
);
347 uintptr_t krn_lowest
= krnGetTagData(KRN_KernelLowest
, 0, BootMsg
) & ~4095;
348 uintptr_t krn_highest
= (krnGetTagData(KRN_KernelHighest
, 0, BootMsg
) + 4095) & ~4095;
350 D(bug("[KRN] Mapping %08x-%08x range for supervisor\n", memlo
, (krn_lowest
^ 0xf8000000)-1));
351 mmu_map_area((uint32_t)memlo
, (uint32_t)memlo
^ 0xf8000000, (krn_lowest
^ 0xf8000000) - (intptr_t)memlo
, (2 << 3) | 0); // PP = 00, WIMG = 0010
353 D(bug("[KRN] Mapping %08x-%08x range for read-write\n", krn_lowest
^0xf8000000, (krn_base
^ 0xf8000000)-1));
354 mmu_map_area((uint32_t)krn_lowest
^0xf8000000, (uint32_t)krn_lowest
, (krn_base
- krn_lowest
), (2 << 3) | 2); // PP = 10, WIMG = 0010
356 D(bug("[KRN] Mapping %08x-%08x range for read-only\n", krn_base
^0xf8000000, (krn_highest
^ 0xf8000000)-1));
357 mmu_map_area((uint32_t)krn_base
^0xf8000000, (uint32_t)krn_base
, (krn_highest
- krn_base
), (2 << 3) | 3); // PP = 11, WIMG = 0010
359 D(bug("[KRN] Mapping %08x-%08x range for supervisor\n", krn_highest
^ 0xf8000000, 0xffffffff));
360 mmu_map_area((uint32_t)krn_highest
^0xf8000000, (uint32_t)krn_highest
, -(krn_highest
^0xf8000000), (2 << 3) | 0); // PP = 00, WIMG = 0010
362 /* Prepare the MemHeader structure for this region */
363 struct MemHeader
*mh
= (struct MemHeader
*)memlo
;
364 mh
->mh_First
= (struct MemChunk
*)((uint8_t *)mh
+ MEMHEADER_TOTAL
);
365 mh
->mh_Free
= ((krn_lowest
^0xf8000000) - MEMHEADER_TOTAL
- (intptr_t)memlo
) & ~(MEMCHUNK_TOTAL
-1);
366 mh
->mh_First
->mc_Next
= NULL
;
367 mh
->mh_First
->mc_Bytes
= mh
->mh_Free
;
369 D(bug("[KRN] Supervisor mem: %dKB free\n", mh
->mh_Free
>> 10));
371 exec_main(BootMsg
, NULL
);
374 D(bug("[KRN] Uhm? Nothing to do?\n[KRN] STOPPED\n"));
377 wrmsr(rdmsr() | MSR_EE
);
378 wrmsr(rdmsr() | MSR_POW
);
383 AROS_LH0I(struct TagItem
*, KrnGetBootInfo
,
384 struct KernelBase
*, KernelBase
, 11, Kernel
)
393 AROS_LH0(void *, KrnCreateContext
,
394 struct KernelBase
*, KernelBase
, 18, Kernel
)
400 uint32_t oldmsr
= goSuper();
402 ctx
= Allocate(KernelBase
->kb_SupervisorMem
, sizeof(context_t
));
403 memset(ctx
, 0, sizeof(context_t
));
408 ctx
= AllocMem(sizeof(context_t
), MEMF_PUBLIC
|MEMF_CLEAR
);
415 AROS_LH1(void, KrnDeleteContext
,
416 AROS_LHA(void *, context
, A0
),
417 struct KernelBase
*, KernelBase
, 19, Kernel
)
421 /* Was context in supervisor space? Deallocate it there :) */
422 if ((intptr_t)context
& 0xf0000000)
424 uint32_t oldmsr
= goSuper();
426 Deallocate(KernelBase
->kb_SupervisorMem
, context
, sizeof(context_t
));
431 FreeMem(context
, sizeof(context_t
));
433 /* Was this context owning a FPU? Make FPU totally free then */
434 if (KernelBase
->kb_FPUOwner
== context
)
435 KernelBase
->kb_FPUOwner
= NULL
;
441 struct OFWNode
*krnCopyOFWTree(struct OFWNode
*orig
)
443 uint32_t node_length
= sizeof(struct OFWNode
) + strlen(orig
->on_name
) + 1;
444 struct OFWNode
*new_node
= (struct OFWNode
*)memlo
;
445 struct OFWNode
*child
;
446 struct OFWProperty
*prop
, *new_prop
;
447 memlo
+= (node_length
+ 3) & ~3;
449 new_node
->on_name
= new_node
->on_storage
;
450 memcpy(new_node
->on_name
, orig
->on_name
, strlen(orig
->on_name
) + 1);
451 NEWLIST(&new_node
->on_children
);
452 NEWLIST(&new_node
->on_properties
);
454 ForeachNode(&orig
->on_properties
, prop
)
456 uint32_t prop_name_length
= strlen(prop
->op_name
) + 1;
457 uint32_t prop_length
= sizeof(struct OFWProperty
) + prop_name_length
+ prop
->op_length
;
459 new_prop
= (struct OFWProperty
*)memlo
;
460 memlo
+= (prop_length
+ 3) & ~3;
462 new_prop
->op_name
= new_prop
->op_storage
;
463 new_prop
->op_value
= &new_prop
->op_storage
[prop_name_length
];
464 new_prop
->op_length
= prop
->op_length
;
466 memcpy(new_prop
->op_name
, prop
->op_name
, strlen(prop
->op_name
)+1);
467 memcpy(new_prop
->op_value
, prop
->op_value
, prop
->op_length
);
469 ADDTAIL(&new_node
->on_properties
, new_prop
);
472 ForeachNode(&orig
->on_children
, child
)
473 ADDTAIL(&new_node
->on_children
, krnCopyOFWTree(child
));
483 struct Task
*idle_task
;
485 /* As soon as IdleTask gets CPU again, it records the current cycle count */
486 AROS_UFH1(void, idleCount
,
487 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
492 SysBase
->IdleCount
++;
498 * When CPU time gets lost, the cycle count spent in idle task is summed
499 * with the total idle time
501 AROS_UFH1(void, idleOff
,
502 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
507 idle_time
+= tbu2
- tbu1
;
513 * Idle task on Efika does not do much. It enters supervisor mode, enables
514 * interrupts (so that it survived even in Disable()'d state) and then enters
515 * power save mode. Once woken up, a Reschedule is forced.
517 void idleTask(struct ExecBase
*SysBase
, struct KernelBase
*KernelBase
)
519 D(bug("[KRN] IdleTask entered\n"));
525 /* Superstate() done quickly */
527 uint32_t msr
= goSuper();
528 uint32_t msr_sup
= rdmsr() | MSR_EE
| MSR_POW
;
529 /* Enable external/decrementer interrupts */
530 asm volatile("sync");
533 /* Changing the POW bit needs a context synchronization now. */
534 asm volatile("isync");
536 /* CPU needs few cycles to enter sleep state */
537 for (i
=0; i
< 10; i
++)
542 /* And reschedule! */
548 struct MemHeader KernelMemory
;
550 void *(*__AllocMem
)();
552 #define ExecAllocMem(bytesize, requirements) \
553 AROS_CALL2(void *, __AllocMem, \
554 AROS_LCA(ULONG, byteSize, D0), \
555 AROS_LCA(ULONG, requirements, D1), \
556 struct ExecBase *, SysBase)
558 AROS_LH2(APTR
, AllocMem
,
559 AROS_LHA(ULONG
, byteSize
, D0
),
560 AROS_LHA(ULONG
, requirements
, D1
),
561 struct ExecBase
*, SysBase
, 33, Kernel
)
565 return ExecAllocMem(bytesize
, requirements
& ~MEMF_CHIP
);
571 static int Kernel_Init(LIBBASETYPEPTR LIBBASE
)
574 struct ExecBase
*SysBase
= getSysBase();
577 uintptr_t krn_lowest
= (krnGetTagData(KRN_KernelLowest
, 0, BootMsg
) & ~4095) ^ 0xf8000000;
578 uintptr_t krn_highest
= ((krnGetTagData(KRN_KernelHighest
, 0, BootMsg
) + 4095) & ~4095) ^ 0xf8000000;
579 char *cmd
= krnGetTagData(KRN_CmdLine
, 0, BootMsg
);
581 KernelMemory
.mh_Node
.ln_Name
= "Kernel";
582 KernelMemory
.mh_Node
.ln_Type
= NT_MEMORY
;
583 KernelMemory
.mh_Node
.ln_Pri
= -128;
584 KernelMemory
.mh_Attributes
= MEMF_KICK
;
585 KernelMemory
.mh_First
= NULL
;
586 KernelMemory
.mh_Free
= 0;
587 KernelMemory
.mh_Lower
= krn_lowest
;
588 KernelMemory
.mh_Upper
= krn_highest
;
591 Enqueue(&SysBase
->MemList
, &KernelMemory
.mh_Node
);
594 NEWLIST(&LIBBASE
->kb_Modules
);
595 NEWLIST(&LIBBASE
->kb_DeadTasks
);
597 /* Check whether the user passed realchip parameter. */
602 uint32_t temp
= strcspn(cmd
, " ");
604 if (strncmp(cmd
, "realchip", 8) == 0)
609 cmd
= stpblk(cmd
+temp
);
614 * If no realchip parameter was given, the AllocMem function will be patched with a stub
615 * which *always* clears the MEMF_CHIP flag.
619 __AllocMem
= SetFunction(SysBase
, -33*LIB_VECTSIZE
, AROS_SLIB_ENTRY(AllocMem
, Kernel
, 33));
623 * Set the KernelBase into SPRG4. At this stage the SPRG5 should be already set by
624 * exec.library itself.
626 wrspr(SPRG4
, LIBBASE
);
628 LIBBASE
->kb_FPUOwner
= NULL
;
630 D(bug("[KRN] Kernel resource post-exec init.\n"));
632 for (i
=0; i
< 21; i
++)
633 NEWLIST(&LIBBASE
->kb_Exceptions
[i
]);
635 for (i
=0; i
< 64; i
++)
636 NEWLIST(&LIBBASE
->kb_Interrupts
[i
]);
638 /* Prepare private memory block */
639 LIBBASE
->kb_SupervisorMem
= (struct MemHeader
*)memlo
;
642 * kernel.resource is ready to run. Enable external interrupts and leave
645 wrmsr(rdmsr() | (MSR_EE
|MSR_FP
));
646 D(bug("[KRN] Interrupts enabled\n"));
648 asm volatile("mtdec %0"::"r"(33000000/1000));
650 wrmsr(rdmsr() | (MSR_PR
));
651 D(bug("[KRN] Entered user mode\n"));
654 /* Add idle task now. */
658 struct TagItem tags
[] = {
659 { TASKTAG_ARG1
, (IPTR
)SysBase
},
660 { TASKTAG_ARG2
, (IPTR
)LIBBASE
},
663 /* Allocate MemEntry for this task and stack */
664 ml
= (struct MemList
*)AllocMem(sizeof(struct MemList
)+sizeof(struct MemEntry
),
665 MEMF_PUBLIC
|MEMF_CLEAR
);
666 t
= (struct Task
*) AllocMem(sizeof(struct Task
), MEMF_CLEAR
|MEMF_PUBLIC
);
667 s
= (uint8_t *) AllocMem(4096, MEMF_CLEAR
|MEMF_PUBLIC
);
669 if( !ml
|| !t
|| !s
)
671 bug("ERROR: Cannot create Idle Task!\n");
672 Alert( AT_DeadEnd
| AG_NoMemory
| AN_ExecLib
);
675 ml
->ml_NumEntries
= 2;
676 ml
->ml_ME
[0].me_Addr
= t
;
677 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
678 ml
->ml_ME
[1].me_Addr
= s
;
679 ml
->ml_ME
[1].me_Length
= 4096;
681 NEWLIST(&t
->tc_MemEntry
);
682 AddHead(&t
->tc_MemEntry
, &ml
->ml_Node
);
684 t
->tc_SPUpper
= s
+ 4096 - SP_OFFSET
;
685 #if AROS_STACK_GROWS_DOWNWARDS
686 t
->tc_SPReg
= (char *)t
->tc_SPUpper
- SP_OFFSET
;
688 t
->tc_SPReg
= (char *)t
->tc_SPLower
+ SP_OFFSET
;
691 t
->tc_Node
.ln_Name
= "Idle Task";
692 t
->tc_Node
.ln_Pri
= -128;
693 t
->tc_Launch
= &idleCount
;
694 t
->tc_Switch
= &idleOff
;
695 t
->tc_Flags
= TF_LAUNCH
| TF_SWITCH
;
696 NewAddTask(t
, &idleTask
, NULL
, &tags
);
703 ADD2INITLIB(Kernel_Init
, 0)