//--- // gint:core:kernel - Installing and unloading the library //--- #include #include #include #include #include #include #include #include #include #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; }