2018-04-19 13:24:26 +02:00
|
|
|
//---
|
2019-07-04 18:11:43 +02:00
|
|
|
// gint:core:start - Kernel initialization and C runtime
|
2018-04-19 13:24:26 +02:00
|
|
|
//--
|
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
#include <gint/defs/attributes.h>
|
|
|
|
#include <gint/defs/types.h>
|
2018-04-19 13:24:26 +02:00
|
|
|
#include <core/bootlog.h>
|
|
|
|
#include <core/mmu.h>
|
|
|
|
#include <gint/drivers.h>
|
|
|
|
#include <gint/gint.h>
|
2019-07-04 18:11:43 +02:00
|
|
|
#include <gint/hardware.h>
|
2019-09-03 22:15:00 +02:00
|
|
|
#include <gint/exc.h>
|
2018-04-19 13:24:26 +02:00
|
|
|
|
|
|
|
/* Symbols provided by the linker script. For sections:
|
|
|
|
- l* represents the load address (source address in ROM)
|
|
|
|
- s* represents the size of the section
|
|
|
|
- r* represents the relocation address (destination address in RAM)
|
|
|
|
gint's BSS section is not mentioned here because it's never initialized */
|
|
|
|
extern uint32_t
|
|
|
|
brom, srom, /* Limits of ROM mappings */
|
|
|
|
lgdata, sgdata, rgdata, /* gint's data section */
|
|
|
|
ldata, sdata, rdata, /* User's data section */
|
|
|
|
sbss, rbss, /* User's BSS section */
|
|
|
|
btors, mtors, etors; /* Constructor/destructor arrays */
|
|
|
|
extern gint_driver_t
|
|
|
|
bdrv, edrv; /* Driver table */
|
|
|
|
|
|
|
|
/* User-provided main() function */
|
|
|
|
int main(int isappli, int optnum);
|
|
|
|
|
|
|
|
/* regcpy() - copy a memory region using symbol information
|
|
|
|
@l Source pointer (load address)
|
|
|
|
@s Size of area (should be a multiple of 16)
|
|
|
|
@r Destination pointer (relocation address) */
|
2019-02-21 20:58:38 +01:00
|
|
|
GSECTION(".pretext")
|
2018-04-19 13:24:26 +02:00
|
|
|
static void regcpy(uint32_t * restrict l, int32_t s, uint32_t * restrict r)
|
|
|
|
{
|
|
|
|
while(s > 0)
|
|
|
|
{
|
|
|
|
*r++ = *l++;
|
|
|
|
*r++ = *l++;
|
|
|
|
*r++ = *l++;
|
|
|
|
*r++ = *l++;
|
|
|
|
s -= 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#define regcpy(l, s, r) regcpy(&l, (int32_t)&s, &r)
|
|
|
|
|
|
|
|
/* regclr() - clear a memory region using symbol information
|
|
|
|
@r Source pointer (base address)
|
|
|
|
@s Size of area (should be a multiple of 16) */
|
2019-02-21 20:58:38 +01:00
|
|
|
GSECTION(".pretext")
|
2018-04-19 13:24:26 +02:00
|
|
|
static void regclr(uint32_t *r, int32_t s)
|
|
|
|
{
|
|
|
|
while(s > 0)
|
|
|
|
{
|
|
|
|
*r++ = 0;
|
|
|
|
*r++ = 0;
|
|
|
|
*r++ = 0;
|
|
|
|
*r++ = 0;
|
|
|
|
s -= 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#define regclr(r, s) regclr(&r, (int32_t)&s)
|
|
|
|
|
|
|
|
/* explore() - read data from a memory region to get it mapped by the system
|
|
|
|
This function accesses all the 1k-blocks between b and b + s. This
|
|
|
|
corresponds to region [b; b+s) when b and s are 1k-aligned.
|
|
|
|
@b Base pointer: first address checked
|
|
|
|
@s Size of region */
|
2019-02-21 20:58:38 +01:00
|
|
|
GSECTION(".pretext")
|
2018-04-19 13:24:26 +02:00
|
|
|
static void explore(volatile void *b, int32_t s)
|
|
|
|
{
|
2019-02-21 20:58:38 +01:00
|
|
|
GUNUSED uint8_t x;
|
2018-04-19 13:24:26 +02:00
|
|
|
|
|
|
|
while(s > 0)
|
|
|
|
{
|
|
|
|
x = *(volatile uint8_t *)b;
|
|
|
|
b += 1024;
|
|
|
|
s -= 1024;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#define explore(b, s) explore(&b, (int32_t)&s)
|
|
|
|
|
|
|
|
/* acall() - call an array of functions (constructors or destructors)
|
|
|
|
@f First element of array
|
|
|
|
@l First element outside of the array */
|
2019-02-21 20:58:38 +01:00
|
|
|
GSECTION(".pretext")
|
2018-04-19 13:24:26 +02:00
|
|
|
static void acall(void (**f)(void), void (**l)(void))
|
|
|
|
{
|
|
|
|
while(f < l) (*(*f++))();
|
|
|
|
}
|
|
|
|
#define acall(f, l) acall((void (**)(void))&f, (void (**)(void))&l)
|
|
|
|
|
|
|
|
|
|
|
|
/* start() - this is where it all starts
|
|
|
|
Returns a status code. Invoking main menu is better than returning! */
|
2019-02-21 20:58:38 +01:00
|
|
|
GSECTION(".pretext.entry")
|
2018-04-19 13:24:26 +02:00
|
|
|
int start(int isappli, int optnum)
|
|
|
|
{
|
|
|
|
/* We are currently in a dynamic userspace mapping of an add-in run
|
|
|
|
from the storage memory. We are running in privileged mode with one
|
|
|
|
golden rule:
|
|
|
|
|
|
|
|
Do not disturb the operating system.
|
|
|
|
|
|
|
|
gint will silently run in an isolated part of the memory (fx9860g)
|
|
|
|
or at the start of the RAM (fxcg50). It acts as a kernel,
|
|
|
|
redirecting interrupts and reimplementing drivers, so we can't rely
|
|
|
|
too much on the system. Ladies and gentlemen, let's have fun! ;D */
|
|
|
|
|
2019-03-06 14:32:51 +01:00
|
|
|
/* For now, we use the system's memory mapper for ROM. RAM is always
|
2018-04-19 13:24:26 +02:00
|
|
|
fully mapped, but we need to initialize it. We also need to do some
|
2019-03-06 14:32:51 +01:00
|
|
|
hardware detection because old fx9860g models have a different
|
2018-04-19 13:24:26 +02:00
|
|
|
processor with some incompatible features */
|
|
|
|
|
|
|
|
/* Detect architecture - this will tell SH3 from SH4 on fx9860g */
|
2019-07-04 18:11:43 +02:00
|
|
|
hw_detect();
|
2018-04-19 13:24:26 +02:00
|
|
|
|
|
|
|
/* Load data sections and wipe the bss section. This has to be done
|
|
|
|
first for static and global variables to be initialized */
|
|
|
|
regcpy(lgdata, sgdata, rgdata);
|
|
|
|
regcpy(ldata, sdata, rdata);
|
|
|
|
regclr(rbss, sbss);
|
|
|
|
bootlog_loaded();
|
|
|
|
|
|
|
|
/* Traverse all ROM pages */
|
|
|
|
explore(brom, srom);
|
2018-08-01 20:41:36 +02:00
|
|
|
|
2018-04-19 13:24:26 +02:00
|
|
|
/* Count how much memory got mapped from this process */
|
|
|
|
uint32_t rom, ram;
|
2018-08-19 17:11:37 +02:00
|
|
|
isSH3() ? tlb_mapped_memory(&rom, &ram)
|
|
|
|
: utlb_mapped_memory(&rom, &ram);
|
2018-08-01 20:41:36 +02:00
|
|
|
bootlog_mapped(rom, ram);
|
2018-04-19 13:24:26 +02:00
|
|
|
|
2019-03-06 14:32:51 +01:00
|
|
|
/* Cancel add-in execution if not all pages are mapped */
|
2019-09-13 08:10:30 +02:00
|
|
|
if(rom < (uint32_t)&srom) gint_panic(0x1040);
|
2018-04-19 13:24:26 +02:00
|
|
|
|
|
|
|
/* Install gint and switch VBR */
|
|
|
|
gint_install();
|
|
|
|
bootlog_kernel();
|
|
|
|
|
2019-02-21 20:58:38 +01:00
|
|
|
/* We are now running on our own in kernel mode. Since we have taken
|
2019-03-06 14:32:51 +01:00
|
|
|
control of interrupts, pretty much any interaction with the system
|
2019-02-21 20:58:38 +01:00
|
|
|
will break it. We'll limit our use of syscalls and do device driving
|
|
|
|
ourselves. (Hopefully we can add cool features in the process.) */
|
2018-04-19 13:24:26 +02:00
|
|
|
|
|
|
|
gint_driver_t *drv;
|
|
|
|
|
|
|
|
/* Initialize all drivers by saving the system settings */
|
|
|
|
for(drv = &bdrv; drv < &edrv; drv++)
|
|
|
|
{
|
2019-02-21 20:58:38 +01:00
|
|
|
/* Hook for old SH3 fx9860g machines */
|
2018-08-01 20:41:36 +02:00
|
|
|
if(isSH3() && drv->driver_sh3) drv->driver_sh3();
|
2019-02-21 20:58:38 +01:00
|
|
|
|
2018-08-19 17:11:37 +02:00
|
|
|
if(drv->ctx_save) drv->ctx_save(drv->sys_ctx);
|
2018-08-01 20:41:36 +02:00
|
|
|
if(drv->init) drv->init();
|
2019-03-06 14:32:51 +01:00
|
|
|
|
|
|
|
#ifdef GINT_BOOT_LOG
|
|
|
|
const char *status = drv->status ? drv->status() : NULL;
|
|
|
|
bootlog_driver(drv->name, status);
|
|
|
|
#endif
|
2018-04-19 13:24:26 +02:00
|
|
|
}
|
2019-03-06 14:32:51 +01:00
|
|
|
bootlog_driver_summary();
|
2018-04-19 13:24:26 +02:00
|
|
|
|
|
|
|
/* With gint fully initialized, we are ready to start the hosted user
|
|
|
|
application. We have already loaded the RAM sections earlier; all
|
|
|
|
that's left is calling the constructors and rolling main(). */
|
|
|
|
|
|
|
|
acall(btors, mtors);
|
|
|
|
int ret = main(isappli, optnum);
|
|
|
|
acall(mtors, etors);
|
|
|
|
|
|
|
|
/* Before leaving the application, we need to clean up our mess. We
|
2019-02-21 20:58:38 +01:00
|
|
|
have changed many hardware settings while accessing the peripheral
|
2018-08-19 17:11:37 +02:00
|
|
|
modules. The OS is bound to be confused (and hang, or crash, or any
|
2019-02-21 20:58:38 +01:00
|
|
|
other kind of giving up) if we don't restore them. */
|
2018-04-19 13:24:26 +02:00
|
|
|
|
2018-08-01 20:41:36 +02:00
|
|
|
/* Unload gint and give back control to the system. Driver settings
|
|
|
|
will be restored while interrupts are disabled */
|
2018-04-19 13:24:26 +02:00
|
|
|
gint_unload();
|
|
|
|
|
|
|
|
/* TODO: Invoke main menu instead of returning? */
|
|
|
|
return ret;
|
|
|
|
}
|