forked from Lephenixnoir/gint
Lephe
e5abe03b89
This commit introduces a large architectural change. Unlike previous models of the fx-9860G series, the G-III models have a new user RAM address different from 8801c000. The purpose of this change is to dynamically load GMAPPED functions to this address by querying the TLB, and call them through a function pointer whose address is determined when loading. Because of the overhead of using a function pointer in both assembly and C code, changes have been made to avoid GMAPPED functions altogether. Current, only cpu_setVBR() and gint_inth_callback() are left, the second being used specifically to enable TLB misses when needed. * Add a .gint.mappedrel section for the function pointers holding addresses to GMAPPED functions; add function pointers for cpu_setVBR() and gint_inth_callback() * Move rram to address 0 instead of the hardcoded 0x8801c000 * Load GMAPPED functions at their linked address + the physical address user RAM is mapped, to and compute their function pointers * Remove the GMAPPED macro since no user function needs it anymore * Add section flags "ax" (code) or "aw" (data) to every custom .section in assembler code, as they default to unpredictable values that can cause the section to be marked NOLOAD by the linker * Update the main kernel, TMU, ETMU and RTC interrupt handlers to use the new indirect calling method This is made possible by new MMU functions giving direct access to the physical area behind any virtualized page. * Add an mmu_translate() function to query the TLB * Add an mmu_uram() function to access user RAM from P1 The exception catching mechanism has been modified to avoid the use of GMAPPED functions altogether. * Set SR.BL=0 and SR.IMASK=15 before calling exception catchers * Move gint_exc_skip() to normal text ROM * Also fix registers not being popped off the stack before a panic The timer drivers have also been modified to avoid GMAPPED functions. * Invoke timer_stop() through gint_inth_callback() and move it to ROM * Move and expand the ETMU driver to span 3 blocks at 0xd00 (ETMU4) * Remove the timer_clear() function by inlining it into the ETMU handler (TCR is provided within the storage block of each timer) * Also split src/timer/inth.s into src/timer/inth-{tmu,etmu}.s Additionally, VBR addresses are now determined at runtime to further reduce hardcoded memory layout addresses in the linker script. * Determine fx-9860G VBR addresses dynamically from mmu_uram() * Determine fx-CG 50 VBR addresses dynamically from mmu_uram() * Remove linker symbols for VBR addresses Comments and documentation have been updated throughout the code to reflect the changes.
171 lines
5.1 KiB
C
171 lines
5.1 KiB
C
//---
|
|
// gint:core:start - Kernel initialization and C runtime
|
|
//--
|
|
|
|
#include <gint/defs/attributes.h>
|
|
#include <gint/defs/types.h>
|
|
#include <gint/mmu.h>
|
|
#include <gint/drivers.h>
|
|
#include <gint/gint.h>
|
|
#include <gint/hardware.h>
|
|
#include <gint/exc.h>
|
|
|
|
#include "kernel.h"
|
|
|
|
/* 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 */
|
|
ldata, sdata, rdata, /* User's data section */
|
|
lilram, silram, rilram, /* IL memory section */
|
|
lxram, sxram, rxram, /* X memory section */
|
|
lyram, syram, ryram, /* Y memory section */
|
|
sbss, rbss; /* User's BSS section */
|
|
#ifdef FX9860G
|
|
extern uint32_t
|
|
lgmapped, sgmapped, /* Permanently mapped functions */
|
|
lreloc, sreloc; /* Relocatable references */
|
|
#endif
|
|
|
|
/* Constructor and destructor arrays */
|
|
extern void (*bctors)(void), (*ectors)(void);
|
|
extern void (*bdtors)(void), (*edtors)(void);
|
|
|
|
/* User-provided main() function */
|
|
int main(int isappli, int optnum);
|
|
|
|
/* Whether to restart main through the OS menu rather than returning */
|
|
int gint_restart = 0;
|
|
|
|
/* gint_setrestart(): Set whether to restart the add-in after exiting */
|
|
void gint_setrestart(int restart)
|
|
{
|
|
gint_restart = restart;
|
|
}
|
|
|
|
/* 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) */
|
|
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) */
|
|
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)
|
|
|
|
/* callarray(): Call an array of functions (constructors or destructors)
|
|
@f First element of array
|
|
@l First element outside of the array */
|
|
static void callarray(void (**f)(void), void (**l)(void))
|
|
{
|
|
while(f < l) (*(*f++))();
|
|
}
|
|
|
|
/* start(): Where it all starts
|
|
Returns a status code. Invoking main menu is better than returning, see
|
|
gint_setrestart() for that. */
|
|
GSECTION(".text.entry")
|
|
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 loads its important code and data at the start of the user RAM
|
|
area. The kernel redirects interrupts and uses its own drivers, so
|
|
we can't rely too much on syscalls. Ladies and gentlemen, let's have
|
|
fun! ;D */
|
|
|
|
/* For now, we use the system's memory mapper for ROM. We'll still do
|
|
it later in our TLB miss handler once we're installed. RAM is always
|
|
fully mapped, but we need to initialize it. We also need to perform
|
|
hardware detection because there are many models and emulators with
|
|
varying processor, peripherals, and configuration. */
|
|
|
|
/* Detect hardware; this will mainly tell SH3 from SH4 on fx-9860G */
|
|
hw_detect();
|
|
|
|
/* Load data sections and wipe the bss section. This has to be done
|
|
first for static and global variables to be initialized */
|
|
regcpy(&ldata, &sdata, &rdata);
|
|
regcpy(&lilram, &silram, &rilram);
|
|
regcpy(&lxram, &sxram, &rxram);
|
|
regcpy(&lyram, &syram, &ryram);
|
|
regclr(&rbss, &sbss);
|
|
|
|
#ifdef FX9860G
|
|
/* Copy permanentely-mapped code to start of user RAM (on fx-CG 50 it
|
|
is loaded along ILRAM contents) */
|
|
void *rgmapped = mmu_uram();
|
|
regcpy(&lgmapped, &sgmapped, rgmapped);
|
|
|
|
/* Relocate references to this code */
|
|
uint32_t volatile *fixups = &lreloc;
|
|
for(uint i = 0; i < (uint32_t)&sreloc / 4; i++)
|
|
{
|
|
fixups[i] += (uint32_t)rgmapped;
|
|
}
|
|
#endif
|
|
|
|
/* Install gint, 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. */
|
|
|
|
callarray(&bctors, &ectors);
|
|
|
|
int rc = 1;
|
|
while(1)
|
|
{
|
|
rc = main(isappli, optnum);
|
|
if(!gint_restart) break;
|
|
gint_osmenu();
|
|
}
|
|
|
|
callarray(&bdtors, &edtors);
|
|
/* Before leaving the application, 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 gint and give back control to the system. Driver settings
|
|
will be restored while interrupts are disabled */
|
|
kquit();
|
|
return rc;
|
|
}
|