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() */
|
||||
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 */
|
||||
__attribute__((deprecated("Use intc_handler() instead")))
|
||||
static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#ifndef 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 */
|
||||
void kinit(void);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <gint/exc.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
|
@ -94,6 +95,21 @@ static void callarray(void (**f)(void), void (**l)(void))
|
|||
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)
|
||||
{
|
||||
/* 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);
|
||||
regclr(&rbss, &sbss);
|
||||
|
||||
/* 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())
|
||||
{
|
||||
regcpy(&lilram, &silram, &rilram);
|
||||
regcpy(&lxyram, &sxyram, &rxyram);
|
||||
}
|
||||
gint_load_onchip_sections();
|
||||
|
||||
#ifdef FX9860G
|
||||
/* Copy permanently-mapped code to start of user RAM (on fx-CG 50 it
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
#include <gint/gint.h>
|
||||
#include <gint/exc.h>
|
||||
#include <gint/defs/call.h>
|
||||
#include <gint/hardware.h>
|
||||
#include "kernel.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
//---
|
||||
// World buffer
|
||||
|
@ -56,6 +59,9 @@ void gint_world_sync(void)
|
|||
// 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)
|
||||
{
|
||||
/* 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;
|
||||
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 */
|
||||
uint32_t *canary = gint_stack_top;
|
||||
if(canary)
|
||||
*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);
|
||||
|
||||
/* 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;
|
||||
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
|
||||
|
@ -167,3 +201,16 @@ void gint_switch(void (*function)(void))
|
|||
{
|
||||
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