gint/src/kernel/kernel.c

127 lines
3.5 KiB
C

//---
// gint:core:kernel - Installing and unloading the library
//---
#include <gint/gint.h>
#include <gint/drivers.h>
#include <gint/hardware.h>
#include <gint/mmu.h>
#include <gint/mpu/intc.h>
#include <gint/kmalloc.h>
#include <gint/cpu.h>
#include <string.h>
#include <stdlib.h>
#include "vbr.h"
#include "kernel.h"
/* Reference the CPU and INTC drivers which are required for gint to work */
extern gint_driver_t drv_intc, drv_cpu;
GUNUSED gint_driver_t *gint_required_cpu = &drv_cpu;
GUNUSED gint_driver_t *gint_required_intc = &drv_intc;
/* World buffers for the OS and gint */
gint_world_t gint_world_os = NULL;
gint_world_t gint_world_addin = NULL;
/* Dynamic flags for all drivers */
uint8_t *gint_driver_flags = NULL;
//---
// Initialization and unloading
//---
/* kinit(): Install and start gint */
void kinit(void)
{
uint32_t VBR = 0;
#ifdef FX9860G
/* On fx-9860G, VBR is loaded at the end of the user RAM. On SH4, the
end of the user RAM hosts the stack, for which we leave 8 kB
(0x2000 bytes). The VBR space takes about 0x600 bytes on SH3 due to
the compact scheme, while it uses about 0x1100 bytes for the whole
expanded region. */
uint32_t uram_end = (uint32_t)mmu_uram() + mmu_uram_size();
if(isSH4()) uram_end -= 0x2000;
uram_end -= (isSH3() ? 0x600 : 0x1100);
/* VBR is advanced 0x100 bytes because of an unused gap */
VBR = uram_end - 0x100;
#endif /* FX9860G */
#ifdef FXCG50
/* On fx-CG 50, VBR is loaded at the start of the user RAM; the linker
script leaves 5 kB (0x1400 bytes) before the start of the data
segment. The stack is again placed at the end of the region, and we
leave 16 kB. */
VBR = (uint32_t)mmu_uram();
uint32_t uram_end = (uint32_t)mmu_uram() + mmu_uram_size() - 0x4000;
#endif
/* Event handler entry points */
void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305;
uint32_t exch_size = (uint32_t)&gint_exch_size;
uint32_t tlbh_size = (uint32_t)&gint_tlbh_size;
/* Load the event handler entry points into memory */
memcpy((void *)VBR + 0x100, gint_exch, exch_size);
memcpy((void *)VBR + 0x400, gint_tlbh, tlbh_size);
memcpy((void *)VBR + 0x600, inth_entry, 64);
/* Initialize memory allocators */
kmalloc_init();
/* Create an allocation arena with unused static RAM */
static kmalloc_arena_t static_ram = { 0 };
extern uint32_t euram;
static_ram.name = "_uram";
static_ram.is_default = isSH4();
static_ram.start = mmu_uram() + ((uint32_t)&euram - 0x08100000);
static_ram.end = (void *)uram_end;
kmalloc_init_arena(&static_ram, true);
kmalloc_add_arena(&static_ram);
/* Allocate world buffers for the OS and for gint */
gint_world_os = gint_world_alloc();
gint_world_addin = gint_world_alloc();
gint_driver_flags = malloc(gint_driver_count());
if(!gint_world_os || !gint_world_addin || !gint_driver_flags)
{
extern void gint_panic(uint32_t code);
gint_panic(0x1060);
}
/* Initialize drivers */
for(int i = 0; i < gint_driver_count(); i++)
{
gint_driver_t *d = &gint_drivers[i];
if(d->constructor) d->constructor();
uint8_t *f = &gint_driver_flags[i];
*f = (d->flags & GINT_DRV_INIT_) | GINT_DRV_CLEAN;
}
/* Select the VBR address for this world before configuring */
cpu_configure_VBR(VBR);
gint_world_switch_in(gint_world_os, gint_world_addin);
}
/* kquit(): Quit gint and give back control to the system */
void kquit(void)
{
gint_world_switch_out(gint_world_addin, gint_world_os);
gint_world_free(gint_world_os);
gint_world_free(gint_world_addin);
free(gint_driver_flags);
gint_world_os = NULL;
gint_world_addin = NULL;
gint_driver_flags = NULL;
}