From 4442d27b620570c1f788d867ccbdc79d686f34ce Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Tue, 1 Apr 2025 15:03:23 +0200 Subject: [PATCH] world: new gint_world_enter() and gint_world_leave() primitives --- include/gint/gint.h | 9 ++++++++ src/kernel/exch.c | 2 ++ src/kernel/world.c | 53 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/include/gint/gint.h b/include/gint/gint.h index 2c4ed09..3cbddb8 100644 --- a/include/gint/gint.h +++ b/include/gint/gint.h @@ -41,6 +41,15 @@ int gint_world_switch(gint_call_t function); __attribute__((deprecated("Use gint_world_switch() instead"))) void gint_switch(void (*function)(void)); +#define GINT_WORLD_ADDIN 1 +#define GINT_WORLD_OS 0 + +/* gint_world_enter(): Enter in a new world */ +void gint_world_enter(int world); + +/* gint_world_leave(): Leave a world set by gint_world_enter() */ +void gint_world_leave(void); + /* gint_world_sync(): Synchronize asynchronous drivers This function waits for asynchronous tasks to complete by unbinding all diff --git a/src/kernel/exch.c b/src/kernel/exch.c index 5f79567..86458aa 100644 --- a/src/kernel/exch.c +++ b/src/kernel/exch.c @@ -81,6 +81,7 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code) if(code == 0x1080) name = "Stack overflow"; if(code == 0x10a0) name = "UBC in bank 1 code"; // if(code == 0x10c0) name = "Missing syscall"; // not on FX + if(code == 0x1100) name = "World-switch error"; if(name[0]) dtext(1, 9, name); else dprint(1, 9, "%03x", code); @@ -124,6 +125,7 @@ GNORETURN static void gint_default_panic(GUNUSED uint32_t code) if(code == 0x10a0) name = "UBC break in register bank 1 code"; if(code == 0x10c0) name = "Missing syscall for this OS version"; if(code == 0x10e0) name = "I2C (touch-screen) error"; + if(code == 0x1100) name = "World-switch error"; dprint(6, 25, "%03x %s", code, name); diff --git a/src/kernel/world.c b/src/kernel/world.c index 6a39d27..a984768 100644 --- a/src/kernel/world.c +++ b/src/kernel/world.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "kernel.h" @@ -146,10 +147,58 @@ void gint_world_switch_out(gint_world_t world_addin, gint_world_t world_os) cpu_atomic_end(); } +#ifndef WORLD_SWITCH_STACK_SIZE +# define WORLD_SWITCH_STACK_SIZE 8 +#endif + +static struct { + u8 stack[WORLD_SWITCH_STACK_SIZE]; + int idx; +} world_switch_stack = { + .stack = { GINT_WORLD_ADDIN }, + .idx = 0, +}; + +// FIXME: support CPU atomic operation +void gint_world_enter(int world) +{ + GAUTOTYPE wss = &world_switch_stack; + + if (world != GINT_WORLD_OS && world != GINT_WORLD_ADDIN) + gint_panic(0x1100); + if (wss->idx >= WORLD_SWITCH_STACK_SIZE) + gint_panic(0x1100); + if (world != wss->stack[wss->idx]) + { + if (world == GINT_WORLD_OS) + gint_world_switch_out(gint_world_addin, gint_world_os); + if (world == GINT_WORLD_ADDIN) + gint_world_switch_in(gint_world_os, gint_world_addin); + } + wss->stack[++(wss->idx)] = world; +} + +// FIXME: support CPU atomic operation +void gint_world_leave(void) +{ + GAUTOTYPE wss = &world_switch_stack; + + if (wss->idx == 0) + gint_panic(0x1100); + if (wss->stack[wss->idx - 0] != wss->stack[wss->idx - 1]) + { + if (wss->stack[wss->idx] == GINT_WORLD_OS) + gint_world_switch_in(gint_world_os, gint_world_addin); + if (wss->stack[wss->idx] == GINT_WORLD_ADDIN) + gint_world_switch_out(gint_world_addin, gint_world_os); + } + wss->idx -= 1; +} + int gint_world_switch(gint_call_t call) { extern void *gint_stack_top; - gint_world_switch_out(gint_world_addin, gint_world_os); + gint_world_enter(GINT_WORLD_OS); void *ILRAM = (void *)0xe5200000; void *XRAM = (void *)0xe500e000; @@ -194,7 +243,7 @@ int gint_world_switch(gint_call_t call) if(canary && *canary != 0xb7c0ffee) gint_panic(0x1080); - gint_world_switch_in(gint_world_os, gint_world_addin); + gint_world_leave(); return rc; }