167 lines
5.7 KiB
C
167 lines
5.7 KiB
C
//---
|
|
// fxcg50:initialize - Kernel initialization and C runtime
|
|
//---
|
|
|
|
#include "vhex/hardware.h"
|
|
#include "vhex/kmalloc.h"
|
|
#include "vhex/kernel.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <setjmp.h>
|
|
|
|
|
|
|
|
/* Constructor and destructor arrays */
|
|
extern void (*bctors)(void), (*ectors)(void);
|
|
extern void (*bdtors)(void), (*edtors)(void);
|
|
|
|
/* User-provided main() function */
|
|
extern int main(void);
|
|
|
|
/* Jumping there will properly unwind and leave the kernel */
|
|
jmp_buf vhex_exitbuf;
|
|
/* Return value of main() */
|
|
int vhex_exitcode;
|
|
|
|
/* kmalloc_arena */
|
|
kmalloc_arena_t static_ram = { 0 };
|
|
kmalloc_arena_t vxboot_ram = { 0 };
|
|
|
|
|
|
/* callarray(): Call an array of functions (constructors or destructors) */
|
|
static void callarray(void (**f)(void), void (**l)(void))
|
|
{
|
|
while(f < l) (*(*f++))();
|
|
}
|
|
|
|
/* kmalloc_init() : initialize kmalloc module */
|
|
static void kmalloc_init(void)
|
|
{
|
|
extern uint32_t __sram_start;
|
|
size_t size;
|
|
|
|
static_ram.name = "_sram";
|
|
static_ram.is_default = true;
|
|
static_ram.start = &__sram_start;
|
|
static_ram.end = (void*)(vhex[HWRAM_PHY_END] | 0x80000000);
|
|
|
|
vxboot_ram.name = "_bram";
|
|
vxboot_ram.is_default = false;
|
|
vxboot_ram.start = (void*)vhex[HWRAM_PHY_USER_START];
|
|
size = (vhex[HWRAM_PHY_USER_END] - vhex[HWRAM_PHY_USER_START]) / 2;
|
|
vxboot_ram.end = (void*)(vhex[HWRAM_PHY_USER_START] + size);
|
|
vxboot_ram.start = (void*)((uintptr_t)vxboot_ram.start | 0x80000000);
|
|
vxboot_ram.end = (void*)((uintptr_t)vxboot_ram.end | 0x80000000);
|
|
|
|
kmalloc_init_arena(&static_ram, true);
|
|
kmalloc_init_arena(&vxboot_ram, true);
|
|
kmalloc_add_arena(&static_ram);
|
|
kmalloc_add_arena(&vxboot_ram);
|
|
}
|
|
|
|
|
|
/* initialize() : Where it all starts
|
|
|
|
We are currently in a RAM location at a non-constant address due to the
|
|
relocalization performed by the bootloader (vxBoot). Moreover, we are in
|
|
privileged mode with one golden rule:
|
|
|
|
Do not disturb the operating system
|
|
|
|
Why we should keep this rule in mind? Because, on this particular device,
|
|
none of all hardware and software information are documented. Vhex will
|
|
therefore involve Casio's syscall to perform some interaction, especially
|
|
concerning file manipulation.
|
|
|
|
Note that we don't need to change the stack, the kernel will use the one
|
|
given by Casio because it's big enough to store the user-application
|
|
(mainly the vxOS) and the kernel code. However, we need to keep in mind
|
|
that for this device, a lot of hardware supposition will be performed here,
|
|
chiefly concerning the memory discovery.
|
|
|
|
+---------------+
|
|
| |
|
|
| |
|
|
| Reserved Area |
|
|
| |
|
|
| |
|
|
+ - - - - - - - + <-- virtually mapped at 0x0810000
|
|
| |
|
|
| vxBoot | <-- This part will be re-used by kmalloc
|
|
| |
|
|
+---------------+ <-- variable
|
|
| |
|
|
| Stack |
|
|
| |
|
|
+ - - - - - - - + <-- end of the TLB information (variable)
|
|
| vxKernel |
|
|
| + |
|
|
| VxOS |
|
|
+---------------+ <-- Provided by the vxKernel (variable)
|
|
| |
|
|
| |
|
|
| |
|
|
| kmalloc() |
|
|
| |
|
|
| |
|
|
| |
|
|
+---------------+ <-- variable
|
|
|
|
For the memory discovery. This an "early" exotic step for the vxkernel
|
|
because we need to detect the RAM geometry to configure the "kmalloc" module
|
|
(which provide memory management API like kmalloc(), kfree(), ...). For more
|
|
information about this part is in <board/fxcg50/hardware.c>
|
|
|
|
The function initialize is the "real" first code executed by the kernel. Its
|
|
role is to perform some hardware detection, create and initialize the
|
|
hypervisor, bootstrap the vxkernel world (see <include/hypervisor.h> for
|
|
details) which will initialize the device, then involve the "user" main()
|
|
routine. */
|
|
void initialize(void)
|
|
{
|
|
/* Detect hardware information : This part is important because it will
|
|
tell us if we are running in an emulator or on a real device. */
|
|
hw_detect();
|
|
|
|
/* initialize kmalloc module */
|
|
kmalloc_init();
|
|
|
|
/* Install Vhex, switch VBR and initialize drivers */
|
|
kinit();
|
|
|
|
/* We are now running on our own in kernel mode. Since we have taken
|
|
control of interrupts, pretty much any interaction with the system
|
|
will break it. We'll limit our use of syscalls and do device driving
|
|
ourselves. (Hopefully we can add cool features in the process!) */
|
|
|
|
/* Now that we have initialized the kernel, we are ready to start the
|
|
hosted user application, which has its own constructors and
|
|
destructors to work with. */
|
|
|
|
/* Here, we use exit() to allow the standard library to do
|
|
what it wants in exit() after main() finishes executing */
|
|
if(!setjmp(vhex_exitbuf)) {
|
|
callarray(&bctors, &ectors);
|
|
exit(main());
|
|
}
|
|
else {
|
|
callarray(&bdtors, &edtors);
|
|
}
|
|
|
|
/* Before leaving the kernel (which simply wait a manual reset),
|
|
we need to clean everything we changed to hardware settings and
|
|
peripheral modules. The OS is bound to be confused (and hang, or
|
|
crash, or any other kind of giving up) if we don't restore them. */
|
|
|
|
/* Unload vhex and give back control to the system. Driver settings
|
|
will be restored while interrupts are disabled */
|
|
kquit();
|
|
|
|
/* deep sleep */
|
|
//TODO: configure SLEEP
|
|
while (1) {
|
|
__asm__ volatile ("sleep":::);
|
|
}
|
|
}
|