mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
gint: reload on-chip sections after world, with option to backup (#26)
Solves the power off crash, at least for programs that don't store long-term data in on-chip memory.
This commit is contained in:
parent
235fa8a361
commit
5655699cd8
4 changed files with 109 additions and 7 deletions
|
@ -80,6 +80,48 @@ void gint_osmenu_native(void);
|
||||||
@restart 0 to exit, 1 to restart by using gint_osmenu() */
|
@restart 0 to exit, 1 to restart by using gint_osmenu() */
|
||||||
void gint_setrestart(int restart);
|
void gint_setrestart(int restart);
|
||||||
|
|
||||||
|
/* gint_set_onchip_save_mode(): Specify memory save policy for world switches
|
||||||
|
|
||||||
|
World switches can cause corruption in on-chip memory in two ways. First, if
|
||||||
|
the calculator powers off while in the OS world, on-chip memory will be
|
||||||
|
wiped because it's not powered when the calculator is off. Second, the OS
|
||||||
|
may run code that overwrites on-chip memory (we don't have any examples of
|
||||||
|
that but it's not part of the add-in interface).
|
||||||
|
|
||||||
|
As a result, the best option is to backup on-chip memory and restore it when
|
||||||
|
loading back into the add-in. The issue is that there's 20 kB of on-chip
|
||||||
|
memory (4 kB ILRAM + 16 kB XYRAM) and on some machines (fx-9860G-like) or in
|
||||||
|
some applications we don't have that much memory lying around.
|
||||||
|
|
||||||
|
This function selects between three modes for handling this save:
|
||||||
|
|
||||||
|
* [Reinitialization mode]
|
||||||
|
Don't save on-chip memory at all, instead just reinitialize the globals
|
||||||
|
and leave the rest corrupted. This is useful if on-chip memory is used
|
||||||
|
only for temporaries (e.g. frames in Azur), for which we don't care if
|
||||||
|
they're corrupted, or code (e.g gint interrupt handling code), which will
|
||||||
|
be reloaded and is otherwise a constant.
|
||||||
|
|
||||||
|
* [Backup mode]
|
||||||
|
Save on-chip memory to a user-provided buffer of size GINT_ONCHIP_BUFSIZE.
|
||||||
|
|
||||||
|
* [Nothing mode]
|
||||||
|
Don't do anything, and let the world switch function choose its preferred
|
||||||
|
saving method. This allows application-specific compromises.
|
||||||
|
|
||||||
|
This is not a problem on SH3 because on-chip memory is only used on SH4. */
|
||||||
|
enum {
|
||||||
|
GINT_ONCHIP_REINITIALIZE = 0,
|
||||||
|
GINT_ONCHIP_BACKUP = 1,
|
||||||
|
GINT_ONCHIP_NOTHING = 2,
|
||||||
|
};
|
||||||
|
#define GINT_ONCHIP_BUFSIZE (20 << 10)
|
||||||
|
|
||||||
|
void gint_set_onchip_save_mode(int mode, void *ptr);
|
||||||
|
|
||||||
|
/* gint_get_onchip_save_mode(): Get the current on-chip memory save policy */
|
||||||
|
int gint_get_onchip_save_mode(void **ptr);
|
||||||
|
|
||||||
/* This function has been moved to the INTC driver */
|
/* This function has been moved to the INTC driver */
|
||||||
__attribute__((deprecated("Use intc_handler() instead")))
|
__attribute__((deprecated("Use intc_handler() instead")))
|
||||||
static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
|
static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#ifndef GINT_CORE_KERNEL
|
#ifndef GINT_CORE_KERNEL
|
||||||
#define GINT_CORE_KERNEL
|
#define GINT_CORE_KERNEL
|
||||||
|
|
||||||
|
/* gint_load_onchip_sections(): Initialize on-chip memory sections */
|
||||||
|
void gint_load_onchip_sections(void);
|
||||||
|
|
||||||
/* kinit(): Install and start gint */
|
/* kinit(): Install and start gint */
|
||||||
void kinit(void);
|
void kinit(void);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <gint/exc.h>
|
#include <gint/exc.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
|
@ -94,6 +95,21 @@ static void callarray(void (**f)(void), void (**l)(void))
|
||||||
while(f < l) (*(*f++))();
|
while(f < l) (*(*f++))();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gint_load_onchip_sections(void)
|
||||||
|
{
|
||||||
|
/* Do not load data to ILRAM, XRAM or YRAM on SH3 - the areas don't
|
||||||
|
exist. If you use them, you're responsible! */
|
||||||
|
if(!isSH3())
|
||||||
|
{
|
||||||
|
/* Clear the areas so that we have less to save in case of a
|
||||||
|
return to menu leading to a poweroff. */
|
||||||
|
memset((void *)0xe5200000, 0, 4096);
|
||||||
|
regcpy(&lilram, &silram, &rilram);
|
||||||
|
memset((void *)0xe500e000, 0, 16384);
|
||||||
|
regcpy(&lxyram, &sxyram, &rxyram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int start2(int isappli, int optnum)
|
static int start2(int isappli, int optnum)
|
||||||
{
|
{
|
||||||
/* We are currently in a dynamic userspace mapping of an add-in run
|
/* We are currently in a dynamic userspace mapping of an add-in run
|
||||||
|
@ -141,13 +157,7 @@ static int start2(int isappli, int optnum)
|
||||||
regcpy(&ldata, &sdata, &rdata);
|
regcpy(&ldata, &sdata, &rdata);
|
||||||
regclr(&rbss, &sbss);
|
regclr(&rbss, &sbss);
|
||||||
|
|
||||||
/* Do not load data to ILRAM, XRAM or YRAM on SH3 - the areas don't
|
gint_load_onchip_sections();
|
||||||
exist. If you use them, you're responsible! */
|
|
||||||
if(!isSH3())
|
|
||||||
{
|
|
||||||
regcpy(&lilram, &silram, &rilram);
|
|
||||||
regcpy(&lxyram, &sxyram, &rxyram);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef FX9860G
|
#ifdef FX9860G
|
||||||
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
|
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
#include <gint/gint.h>
|
#include <gint/gint.h>
|
||||||
#include <gint/exc.h>
|
#include <gint/exc.h>
|
||||||
#include <gint/defs/call.h>
|
#include <gint/defs/call.h>
|
||||||
|
#include <gint/hardware.h>
|
||||||
|
#include "kernel.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// World buffer
|
// World buffer
|
||||||
|
@ -56,6 +59,9 @@ void gint_world_sync(void)
|
||||||
// World switch with driver state saves
|
// World switch with driver state saves
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
static int onchip_save_mode = GINT_ONCHIP_REINITIALIZE;
|
||||||
|
static void *onchip_save_buffer = NULL;
|
||||||
|
|
||||||
void gint_world_switch_in(gint_world_t world_os, gint_world_t world_addin)
|
void gint_world_switch_in(gint_world_t world_os, gint_world_t world_addin)
|
||||||
{
|
{
|
||||||
/* Unbind from the OS driver and complete foreign asynchronous tasks */
|
/* Unbind from the OS driver and complete foreign asynchronous tasks */
|
||||||
|
@ -144,13 +150,41 @@ int gint_world_switch(gint_call_t call)
|
||||||
extern void *gint_stack_top;
|
extern void *gint_stack_top;
|
||||||
gint_world_switch_out(gint_world_addin, gint_world_os);
|
gint_world_switch_out(gint_world_addin, gint_world_os);
|
||||||
|
|
||||||
|
void *ILRAM = (void *)0xe5200000;
|
||||||
|
void *XRAM = (void *)0xe500e000;
|
||||||
|
void *YRAM = (void *)0xe5010000;
|
||||||
|
|
||||||
/* Watch out for stack overflows */
|
/* Watch out for stack overflows */
|
||||||
uint32_t *canary = gint_stack_top;
|
uint32_t *canary = gint_stack_top;
|
||||||
if(canary)
|
if(canary)
|
||||||
*canary = 0xb7c0ffee;
|
*canary = 0xb7c0ffee;
|
||||||
|
|
||||||
|
/* Save on-chip memory if requested */
|
||||||
|
if(!isSH3() && onchip_save_mode == GINT_ONCHIP_BACKUP) {
|
||||||
|
void *ptr = onchip_save_buffer;
|
||||||
|
memcpy(ptr, ILRAM, 4096);
|
||||||
|
ptr += 4096;
|
||||||
|
memcpy(ptr, XRAM, 8192);
|
||||||
|
ptr += 8192;
|
||||||
|
memcpy(ptr, YRAM, 8192);
|
||||||
|
ptr += 8192;
|
||||||
|
}
|
||||||
|
|
||||||
int rc = gint_call(call);
|
int rc = gint_call(call);
|
||||||
|
|
||||||
|
/* Restore or reinitialize on-chip memory */
|
||||||
|
if(!isSH3() && onchip_save_mode == GINT_ONCHIP_BACKUP) {
|
||||||
|
void *ptr = onchip_save_buffer;
|
||||||
|
memcpy(ILRAM, ptr, 4096);
|
||||||
|
ptr += 4096;
|
||||||
|
memcpy(XRAM, ptr, 8192);
|
||||||
|
ptr += 8192;
|
||||||
|
memcpy(YRAM, ptr, 8192);
|
||||||
|
ptr += 8192;
|
||||||
|
}
|
||||||
|
else if(!isSH3() && onchip_save_mode == GINT_ONCHIP_REINITIALIZE)
|
||||||
|
gint_load_onchip_sections();
|
||||||
|
|
||||||
/* The canary check needs to occur before switching in the gint world;
|
/* The canary check needs to occur before switching in the gint world;
|
||||||
otherwise we just crash due to the overflow. gint_panic() isn't
|
otherwise we just crash due to the overflow. gint_panic() isn't
|
||||||
really designed to work from the OS world, but it does fine on the
|
really designed to work from the OS world, but it does fine on the
|
||||||
|
@ -167,3 +201,16 @@ void gint_switch(void (*function)(void))
|
||||||
{
|
{
|
||||||
gint_world_switch(GINT_CALL(function));
|
gint_world_switch(GINT_CALL(function));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gint_set_onchip_save_mode(int mode, void *ptr)
|
||||||
|
{
|
||||||
|
onchip_save_mode = mode;
|
||||||
|
onchip_save_buffer = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gint_get_onchip_save_mode(void **ptr)
|
||||||
|
{
|
||||||
|
if(ptr)
|
||||||
|
*ptr = onchip_save_buffer;
|
||||||
|
return onchip_save_mode;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue