vxKernel/board/fxcg50/initialize.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":::);
}
}