forked from Lephenixnoir/gint
168 lines
3.6 KiB
C
168 lines
3.6 KiB
C
//---
|
|
// gint:core:kernel - Installing and unloading the library
|
|
//---
|
|
|
|
#include <gint/gint.h>
|
|
#include <gint/drivers.h>
|
|
#include <gint/std/string.h>
|
|
#include <gint/hardware.h>
|
|
#include <gint/mpu/intc.h>
|
|
|
|
#include "cpu.h"
|
|
#include "vbr.h"
|
|
#include "drivers.h"
|
|
#include "kernel.h"
|
|
|
|
static void kinit_cpu(void);
|
|
|
|
//---
|
|
// Context for the CPU and registers not directly managed by a driver
|
|
//---
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t VBR;
|
|
uint32_t CPUOPM;
|
|
} ctx_t;
|
|
|
|
/* System context and gint context for the CPU and VBR */
|
|
GBSS static ctx_t sys_ctx, gint_ctx;
|
|
|
|
static void ctx_save(ctx_t *ctx)
|
|
{
|
|
if(isSH4()) ctx->CPUOPM = cpu_getCPUOPM();
|
|
}
|
|
static void ctx_restore(ctx_t *ctx)
|
|
{
|
|
if(isSH4()) cpu_setCPUOPM(ctx->CPUOPM);
|
|
}
|
|
|
|
//---
|
|
// Driver control
|
|
//---
|
|
|
|
static void drivers_wait(void)
|
|
{
|
|
for driver_asc(d)
|
|
{
|
|
if(d->wait) d->wait();
|
|
}
|
|
}
|
|
|
|
static void drivers_save_and_init(GUNUSED int zero)
|
|
{
|
|
/* Initialize the CPU, which is done here instead of in a driver */
|
|
ctx_save(&sys_ctx);
|
|
kinit_cpu();
|
|
|
|
for driver_asc(d)
|
|
{
|
|
if(d->ctx_save) d->ctx_save(d->sys_ctx);
|
|
|
|
if(isSH3() && d->driver_sh3) d->driver_sh3();
|
|
if(d->init) d->init();
|
|
}
|
|
}
|
|
|
|
static void drivers_restore(int who)
|
|
{
|
|
for driver_dsc(d)
|
|
{
|
|
if(d->ctx_restore) d->ctx_restore(who?d->gint_ctx:d->sys_ctx);
|
|
}
|
|
|
|
ctx_restore(who ? &gint_ctx : &sys_ctx);
|
|
}
|
|
|
|
static void drivers_switch(int who)
|
|
{
|
|
/* Save all drivers in reverse order */
|
|
for driver_dsc(d)
|
|
{
|
|
if(!d->ctx_save || !d->ctx_restore) continue;
|
|
d->ctx_save(who ? d->gint_ctx : d->sys_ctx);
|
|
}
|
|
ctx_save(who ? &gint_ctx : &sys_ctx);
|
|
|
|
/* Restore the other context */
|
|
ctx_restore(who ? &sys_ctx : &gint_ctx);
|
|
for driver_asc(d)
|
|
{
|
|
if(!d->ctx_save || !d->ctx_restore) continue;
|
|
d->ctx_restore(who ? d->sys_ctx : d->gint_ctx);
|
|
}
|
|
}
|
|
|
|
//---
|
|
// Initialization and unloading
|
|
//---
|
|
|
|
static void kinit_cpu(void)
|
|
{
|
|
cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
|
|
}
|
|
|
|
/* kinit(): Install and start gint */
|
|
void kinit(void)
|
|
{
|
|
/* VBR address, provided by the linker script */
|
|
#ifdef FX9860G
|
|
gint_ctx.VBR = (uint32_t)&gint_vbr_fx9860g;
|
|
#endif
|
|
#ifdef FXCG50
|
|
gint_ctx.VBR = (gint[HWCALC] == HWCALC_FXCG50)
|
|
? (uint32_t)&gint_vbr_fxcg50
|
|
: (uint32_t)&gint_vbr_fxcg20;
|
|
#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 */
|
|
void *vbr = (void *)gint_ctx.VBR;
|
|
memcpy(vbr + 0x100, gint_exch, exch_size);
|
|
memcpy(vbr + 0x400, gint_tlbh, tlbh_size);
|
|
memcpy(vbr + 0x600, inth_entry, 64);
|
|
|
|
/* Take control of the VBR and roll! */
|
|
drivers_wait();
|
|
sys_ctx.VBR = cpu_setVBR(gint_ctx.VBR, drivers_save_and_init, 0);
|
|
}
|
|
|
|
/* gint_inthandler(): Install interrupt handlers */
|
|
void *gint_inthandler(int event_code, const void *handler, size_t size)
|
|
{
|
|
/* Normalize the event code */
|
|
if(event_code < 0x400) return NULL;
|
|
event_code -= 0x400;
|
|
event_code &= ~0x1f;
|
|
|
|
void *dest = (void *)gint_ctx.VBR + event_code + 0x640;
|
|
return memcpy(dest, handler, size);
|
|
}
|
|
|
|
/* gint_switch(): Temporarily switch out of gint */
|
|
void gint_switch(void (*function)(void))
|
|
{
|
|
/* Switch from gint to the OS after a short wait */
|
|
drivers_wait();
|
|
cpu_setVBR(sys_ctx.VBR, drivers_switch, 1);
|
|
|
|
if(function) function();
|
|
|
|
/* Then switch back to gint once the OS finishes working */
|
|
drivers_wait();
|
|
cpu_setVBR(gint_ctx.VBR, drivers_switch, 0);
|
|
}
|
|
|
|
/* kquit(): Quit gint and give back control to the system */
|
|
void kquit(void)
|
|
{
|
|
/* Wait for hardware tasks then restore all of the drivers' state and
|
|
return the VBR space to the OS */
|
|
drivers_wait();
|
|
cpu_setVBR(sys_ctx.VBR, drivers_restore, 0);
|
|
}
|