Compare commits

...

4 Commits

Author SHA1 Message Date
Yatis c923ad24b1 @add
* special fxcg50 dupdate_noint() which display the content of the VRM without using the DMA (usefull for debugging)

@update
* update the drivers interface to get some information about the current running drivers' context
* remove the old cpu_setVBR() function

@fix
* fix cpu_setVBR() returned value
* fix kquit() drivers restore atomic error
2021-03-13 17:59:03 +01:00
Yatis 6961a0feec Add dynamique world context management
* Update all drivers to add context's size information.
* Isolate the driver module from the kernel module.
* Isolate the CPU "driver" from the kernel module.
* Isolate the Gint "world switch" from the kernel module.
* Generate two worlds: Gint and Casio (see <src/kernel/kernel.c>).
* Add atomic (SR.IMASK=15) functions.
* Allow to overwrite the Gint "world switch" (gint_switch()).
2021-02-01 12:00:25 +01:00
Yatis 48709c72e4 Fix Makefile installation + add some common std functions + add size_t type 2021-02-01 11:52:06 +01:00
Yatis 01f5f883e7 Update BFile information + add some common std functions 2021-02-01 11:49:31 +01:00
29 changed files with 786 additions and 351 deletions

35
include/gint/atomic.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _SRC_KERNEL_ATOMIC_H__
# define _SRC_KERNEL_ATOMIC_H__
#include <stddef.h>
#include <stdint.h>
/* atomic_begin(): Start atomic operation
This function will block interruptions and exception until
"thread_atomic_stop()" is called. This is really useful when you need to
secure some tricky part of code (like driver kernel-level implementation).
But be carefull: your code executed after this function SHOULD be
EXCEPTION-SAFE ! Otherwise, a crash will occur and Gint can do nothing to
avoid it because is hardware specific. If you need to secure shared data,
use mutex instead.
This implementation is recursive-safe and will return:
* SR value when you enter in "atomic" operation (first call)
* 0 if you are already in a "atomic" operation (x call)
To return to the "normal" operation, you should call "thread_atomic_stop()"
as many time as you have involved with "thread_atomic_start()". */
extern void *atomic_begin(void);
/* atomic_end(): Stop atomic opration
This function will try to return to the "normal" mode and will return:
* negative value If error occur
* 0 If you are alwayrs in "atomic" mode
* the restored SR value If you are returned to the "clasic" mode */
extern void *atomic_end(void);
#endif /*_SRC_KERNEL_ATOMIC_H__*/

View File

@ -105,6 +105,21 @@ struct BFile_FileInfo
/* Address of first fragment (do not use directly) */
void *address;
};
enum BFile_FileType
{
BFile_Type_Directory = 0x0000,
BFile_Type_File = 0x0001,
BFile_Type_Addin = 0x0002,
BFile_Type_Eact = 0x0003,
BFile_Type_Language = 0x0004,
BFile_Type_Bitmap = 0x0005,
BFile_Type_MainMem = 0x0006,
BFile_Type_Temp = 0x0007,
BFile_Type_Dot = 0x0008,
BFile_Type_DotDot = 0x0009,
BFile_Type_Volume = 0x000a,
BFile_Type_Archived = 0x0041,
};
int BFile_FindFirst(uint16_t const *search, int *shandle, uint16_t *foundfile,
struct BFile_FileInfo *fileinfo);

View File

@ -7,6 +7,7 @@
#include <gint/defs/types.h>
#if 0
/* cpu_setVBR(): Change VBR address
Blocks interrupts then changes the VBR address and calls the provided INTC
@ -23,6 +24,7 @@
Returns the previous VBR address. */
extern uint32_t (*cpu_setVBR)(uint32_t vbr, void (*conf_intc)(int arg),
int arg);
#endif
/* cpu_setCPUOPM(): Change the CPU Operation Mode register
@ -60,7 +62,11 @@ typedef lword_union(sr_t,
);
/* Get and set sr through the sr_t type */
sr_t cpu_getSR(void);
void cpu_setSR(sr_t sr);
extern sr_t cpu_getSR(void);
extern void cpu_setSR(sr_t sr);
/* Get and set vbr register */
extern void *cpu_setVBR(void *vbr);
extern void *cpu_getVBR();
#endif /* GINT_CORE_CPU */

View File

@ -16,7 +16,8 @@
typedef unsigned int uint;
/* Signed size_t */
typedef signed int ssize_t;
/* Offset */
typedef unsigned int off_t;
//---
// Structure elements
//----

View File

@ -122,6 +122,8 @@ void dsetvram(uint16_t *main, uint16_t *secondary);
Returns the VRAM buffer addresses used to render on fx-CG 50. */
void dgetvram(uint16_t **main, uint16_t **secondary);
/* vdupdate_noint(): Push the VRAM to the display driver without DMA */
extern void dupdate_noint(void);
#endif /* FXCG50 */
#endif /* GINT_DISPLAY_CG */

View File

@ -70,14 +70,17 @@ typedef struct
is used for instance to wait for DMA transfers. May be NULL. */
void (*wait)(void);
/* Return the context size */
size_t (*ctx_size)(void);
/* System's context and gint's context. These should point to enough
memory to store a full driver state each. Used when switching from
the system to gint and back to the main menu. If they don't need to
be initialized, put them in gint's uninitialized BSS section using
the GBSS macro of <gint/defs/attributes.h>. May be NULL only if both
ctx_save() and ctx_restore() are NULL. */
void *sys_ctx;
void *gint_ctx;
//void *sys_ctx;
//void *gint_ctx;
/* Must save the state of as much driver-controlled hardware as
possible (memory-mapped MPU registers, port state, etc). This
@ -113,4 +116,22 @@ typedef struct
#define GINT_DRIVER_SH3(name) name
#endif
//---
// Driver interface
//---
extern void *drivers_context_create(void);
extern void drivers_context_destroy(void **buffctx);
extern void drivers_wait(void);
extern void *drivers_switch(void *buffctx);
extern void *drivers_restore(void *buffctx);
extern int drivers_save_and_init(void *buffctx);
extern int drivers_save(void *buffctx);
extern int drivers_context_duplicate(void **dst, void *src);
extern void *drivers_init(void *buffctx);
extern void *drivers_get_current(void);
// default world
extern void *kernel_env_casio;
extern void *kernel_env_gint;
#endif /* GINT_DRIVERS */

View File

@ -129,4 +129,14 @@ void *gint_inthandler(int event_code, void const *handler, size_t size);
Returns the return value of the callback. */
extern int (*gint_inth_callback)(int (*function)(void *arg), void *arg);
//---
// Yatis, custom
//---
extern void gint_switch_to_casio(void);
extern void gint_switch_to_gint(void);
#endif /* GINT_GINT */

View File

@ -27,4 +27,7 @@ void srand(unsigned int seed);
/* rand(): Generate a pseudo-random number between 0 and RAND_MAX */
int rand(void);
/* atoi(): Convert string into decimal */
extern int atoi(const char *restrict s);
#endif /* GINT_STD_STDLIB */

View File

@ -31,4 +31,13 @@ char *strcat(char *dest, const char *src);
/* strcmp(): Compare NUL-terminated strings */
int strcmp(char const *s1, char const *s2);
/* strchr(): returns a pointer to the first occurrence of the character c */
extern char *strchr(const char *s1, int c);
/* strchrnull(): returns a pointer to the first occurrence of the character c*/
extern char *strchrnull(const char *s1, int c);
/* strchr(): returns a pointer to the first occurrence of the character c */
extern char *strrchr(const char *s1, int c);
#endif /* GINT_STD_STRING */

View File

@ -157,8 +157,7 @@ install: $(target)
install $(target) $(m644) $(PREFIX)
install ../$(CONFIG.TARGET.LONG).ld $(m644) $(PREFIX)
install -d $(PREFIX)/include/gint
cp ../include/gint/*.h $(PREFIX)/include/gint/
cp include/gint/*.h $(PREFIX)/include/gint/
cp -r ../include/gint/* $(PREFIX)/include/gint/
uninstall:
rm -f $(PREFIX)/$(target)

View File

@ -118,11 +118,11 @@ static void sh7305_probe(void)
// Initialization, contexts and driver metadata
//---
/* init: Initialize thre driver */
static void init(void)
{
/* Disable spread spectrum in SSGSCR */
if(isSH4())
{
if(isSH4()) {
SH7305_CPG.SSCGCR.SSEN = 0;
}
@ -134,31 +134,41 @@ static void init(void)
sh7305_probe();
}
/* CPG context */
typedef struct {
uint32_t SSCGCR;
} ctx_t;
static ctx_t sys_ctx, gint_ctx;
/* ctx_save(): save the driver's context */
static void ctx_save(void *ctx)
{
ctx_t *c = ctx;
if(isSH4()) c->SSCGCR = SH7305_CPG.SSCGCR.lword;
if(isSH4())
c->SSCGCR = SH7305_CPG.SSCGCR.lword;
}
/* ctx_restore(): restore the driver's context */
static void ctx_restore(void *ctx)
{
ctx_t *c = ctx;
if(isSH4()) SH7305_CPG.SSCGCR.lword = c->SSCGCR;
if(isSH4())
SH7305_CPG.SSCGCR.lword = c->SSCGCR;
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
/* create the driver object */
gint_driver_t drv_cpg = {
.name = "CPG",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(1, drv_cpg);

179
src/cpu/cpu.c Normal file
View File

@ -0,0 +1,179 @@
//---
// gint:kernel:cpu - CPU "driver"
//---
#include <gint/hardware.h>
#include <gint/drivers.h>
#include <gint/mmu.h>
#include <gint/std/string.h>
#include <gint/cpu.h>
/* The kernel's interrupt and exception handlers' entry points */
extern void gint_exch(void);
extern void gint_tlbh(void);
extern void gint_inth_7705(void);
extern void gint_inth_7305(void);
/* Size of exception and TLB handlers */
extern char gint_exch_size;
extern char gint_tlbh_size;
/* VBR information (generated by the kernel module) */
extern void *gint_vbr;
//---
// Context management
//---
/* CPU context */
typedef struct
{
sr_t SR;
uint32_t VBR;
uint32_t CPUOPM;
} ctx_t;
/* ctx_save(): save the CPU context */
static void ctx_save(ctx_t *ctx)
{
ctx->VBR = (uint32_t)(uintptr_t)cpu_getVBR();
if(isSH4()) {
ctx->CPUOPM = cpu_getCPUOPM();
ctx->SR = cpu_getSR();
}
}
/* ctx_restore(): Restore the CPU context */
static void ctx_restore(ctx_t *ctx)
{
cpu_setVBR((void*)(uintptr_t)ctx->VBR);
if(isSH4()) {
cpu_setCPUOPM(ctx->CPUOPM);
cpu_setSR(ctx->SR);
}
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver manipulation
//---
/* init(): Initialize the CPU */
static void init(void)
{
/* Event handler entry points */
uint32_t exch_size = (uintptr_t)&gint_exch_size;
uint32_t tlbh_size = (uintptr_t)&gint_tlbh_size;
void *inth_entry = gint_inth_7305;
if (isSH3())
inth_entry = gint_inth_7705;
/* Load the event handler entry points into memory */
memcpy(gint_vbr + 0x100, gint_exch, exch_size);
memcpy(gint_vbr + 0x400, gint_tlbh, tlbh_size);
memcpy(gint_vbr + 0x600, inth_entry, 64);
/* enable some feature on SH4 */
if(isSH4()) {
cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
/* Enable DSP mode on the CPU */
sr_t SR = cpu_getSR();
SR.DSP = 1;
cpu_setSR(SR);
}
/* switch the VBR */
cpu_setVBR(gint_vbr);
}
/* Due to dire space restrictions on SH3, event codes that are translated to
SH4 are further remapped into the VBR space to eliminate gaps and save
space. Each entry in this table represents a 32-byte block after the
interrupt handler's entry gate. It shows the SH4 event code whose gate is
placed on that block (some of gint's SH4 event codes are invented to host
helper blocks).
For instance, the 5th block after the entry gate hosts the interrupt handler
for SH4 event 0x9e0, which is ETMU0 underflow.
The _inth_remap table in src/core/inth.S combines the SH3-SH4 translation
with the compact translation, hence its entry for 0xf00 (the SH3 event code
for ETMU0 underflow) is the offset in this table where 0x9e0 is stored,
which is 4. */
static const uint16_t sh3_vbr_map[] = {
0x400, /* TMU0 underflow */
0x420, /* TMU1 underflow */
0x440, /* TMU2 underflow */
0x460, /* (gint custom: TMU helper) */
0x9e0, /* ETMU0 underflow */
0xd00, /* ETMU4 underflow (used as helper on SH3) */
0xd20, /* (gint custom: ETMU helper) */
0xd40, /* (gint custom: ETMU helper) */
0xaa0, /* RTC Periodic Interrupt */
1, /* (Filler to maintain the gap between 0xaa0 and 0xae0) */
0xae0, /* (gint custom: RTC helper) */
0
};
/* gint_inthandler(): Install interrupt handlers */
/* Yatis note:
** Due to the hypervisor hack, we assume that the VBR is already mapped.
** FIXME
*/
void *gint_inthandler(int event_code, const void *handler, size_t size)
{
void *dest;
/* Normalize the event code */
if(event_code < 0x400)
return NULL;
event_code &= ~0x1f;
/* On SH3, make VBR compact. Use this offset specified in the VBR map
above to avoid gaps */
if(isSH3())
{
int index = 0;
while(sh3_vbr_map[index])
{
if((int)sh3_vbr_map[index] == event_code) break;
index++;
}
/* This happens if the event has not beed added to the table,
ie. the compact VBR scheme does not support this code */
if(!sh3_vbr_map[index]) return NULL;
/* Gates are placed starting at VBR + 0x200 to save space */
dest = (void *)(gint_vbr + 0x200 + index * 0x20);
}
/* On SH4, just use the code as offset */
else
{
/* 0x40 is the size of the entry gate */
dest = (void *)(gint_vbr + 0x640 + (event_code - 0x400));
}
return memcpy(dest, handler, size);
}
//---
// Driver definition
//---
/* create the driver object */
gint_driver_t drv_cpu = {
.name = "CPU",
.init = init,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(0, drv_cpu);

View File

@ -2,55 +2,14 @@
** gint:core:vbr - Assembler-level VBR management
*/
.global _cpu_setVBR
.text
.global _cpu_setCPUOPM
.global _cpu_getCPUOPM
.global _cpu_getSR
.global _cpu_setSR
.global _cpu_setVBR
.global _cpu_getVBR
/* cpu_setVBR(): Change VBR address */
.section .gint.mapped, "ax"
_cpu_setVBR_reloc:
mov.l r8, @-r15
mov.l r9, @-r15
sts.l pr, @-r15
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r9
shll2 r9
shll2 r9
stc sr, r0
or r9, r0
ldc r0, sr
/* Set the new VBR address */
stc vbr, r8
ldc r4, vbr
/* Call the configuration function */
jsr @r5
mov r6, r4
/* Enable interrupts again */
stc sr, r0
not r9, r9
and r9, r0
ldc r0, sr
/* Return the previous VBR address */
mov r8, r0
lds.l @r15+, pr
mov.l @r15+, r9
rts
mov.l @r15+, r8
.section .gint.mappedrel, "aw"
_cpu_setVBR:
.long _cpu_setVBR_reloc
.text
/* cpu_setCPUOPM(): Change the CPU Operation Mode register */
_cpu_setCPUOPM:
@ -90,3 +49,28 @@ _cpu_setSR:
ldc r4, sr
rts
nop
/* cpu_setVBR(): Set the VBR */
_cpu_setVBR:
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r1
shll2 r1
shll2 r1
stc sr, r2
or r2, r1
ldc r1, sr
/* switch VBR */
stc vbr, r0
ldc r4, vbr
/* resotre old SR */
ldc r2, sr
rts
nop
/* cpu_getVBR: Get the VBR */
_cpu_getVBR:
stc vbr, r0
rts
nop

View File

@ -29,7 +29,7 @@ static channel_t *dma_channel(int channel)
/* dma_translate(): Translate virtual address to DMA-suitable form */
static uint32_t dma_translate(void const *address)
{
uint32_t a = (uint32_t)address;
uint32_t a = (uintptr_t)address;
/* Preserve RS addresses (as of SH7724 Reference, 11.2.2) */
if(a >= 0xfd800000 && a < 0xfd800800)
@ -173,7 +173,7 @@ void dma_transfer_noint(int channel, dma_size_t size, uint blocks,
//---
// Initialization
//---
/* init: Initialize the hardware */
static void init(void)
{
/* This driver is not implemented on SH3 */
@ -215,16 +215,20 @@ static void init(void)
DMA.OR.DME = 1;
}
/* wait(): Wait all transfers' end */
static void wait(void)
{
/* Make sure any DMA transfer is finished before leaving the app */
dma_transfer_wait(-1);
}
//---
// Context system for this driver
//---
/* define the driver context */
typedef struct
{
channel_t ch[6];
@ -233,9 +237,7 @@ typedef struct
} GPACKED(4) ctx_t;
/* One buffer for the system state will go in gint's .bss section */
GBSS static ctx_t sys_ctx, gint_ctx;
/* ctx_save(): save the current driver's context */
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -255,6 +257,7 @@ static void ctx_save(void *buf)
ctx->clock = POWER.MSTPCR0.DMAC0;
}
/* ctx_restore(): restore the driver's context */
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
@ -279,18 +282,24 @@ static void ctx_restore(void *buf)
DMA.OR.word = ctx->OR;
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
/* define the driver object */
gint_driver_t drv_dma0 = {
.name = "DMA0",
.init = init,
.wait = wait,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(2, drv_dma0);

View File

@ -113,15 +113,14 @@ static void init(void)
//---
// Driver context
//---
/* define the driver's context */
typedef struct
{
uint16_t IPR[12];
uint8_t MSK[13];
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
/* ctx_save(): save the current driver's context */
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -130,9 +129,7 @@ static void ctx_save(void *buf)
{
for(int i = 0; i < 8; i++)
ctx->IPR[i] = *(SH7705_INTC.IPR[i]);
}
else
{
} else {
for(int i = 0; i < 12; i++)
ctx->IPR[i] = SH7305_INTC.IPR[2 * i];
@ -142,42 +139,44 @@ static void ctx_save(void *buf)
}
}
/* ctx_restore(): restore the driver's context */
static void ctx_restore(void *buf)
{
ctx_t *ctx = buf;
if(isSH3())
{
if(isSH3()) {
for(int i = 0; i < 8; i++)
*(SH7705_INTC.IPR[i]) = ctx->IPR[i];
}
else
{
} else {
for(int i = 0; i < 12; i++)
SH7305_INTC.IPR[2 * i] = ctx->IPR[i];
/* Setting masks it a bit more involved than reading them */
uint8_t *IMCR = (void *)SH7305_INTC.MSKCLR;
uint8_t *IMR = (void *)SH7305_INTC.MSK;
for(int i = 0; i < 13; i++, IMR += 4, IMCR += 4)
{
for(int i = 0; i < 13; i++, IMR += 4, IMCR += 4) {
*IMCR = 0xff;
*IMR = ctx->MSK[i];
}
}
}
/* ctx_size(): return the context size */
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
/* create the driver object */
gint_driver_t drv_intc = {
.name = "INTC",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)ctx_save,
.ctx_restore = (void*)ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(0, drv_intc);

87
src/kernel/atomic.S Normal file
View File

@ -0,0 +1,87 @@
/*
** gint:thread:atomic - Thread atomic helper
*/
.text
.align 2
.global _atomic_begin
.type _atomic_begin, @function
/* thread_atomic_begin(): Mask interrupts and exceptions */
_atomic_begin:
/* Check if the user is currently into an atomic state and update
atomic counter. */
mov.l atomic_counter, r1
mov.l @r1, r2
tst r2, r2
add #1, r2
mov.l r2, @r1
bf/s atomic_begin_exit
mov #-1, r0
/* Block all interrupts by setting IMASK=15 */
mov #0xf, r1
shll2 r1
shll2 r1
stc sr, r0
or r0, r1
ldc r1, sr
/* Save "old" SR register. */
mov.l atomic_sr_save, r1
mov.l r0, @r1
atomic_begin_exit:
rts
nop
.global _atomic_end
.type _atomic_end, @function
/* atomic_end(): Unmask (if possible) interrupts / exceptions signals */
_atomic_end:
/* Check if the device is currently into an atomic operation, then
update the counter and, if needed, restore the SR register. */
mov.l atomic_counter, r1
mov.l @r1, r0
tst r0, r0
bt atomic_end_error
cmp/eq #1, r0
add #-1, r0
mov.l r0, @r1
bf/s atomic_end_exit
mov #0, r0
/* Restore saved SR register data. */
mov.l atomic_sr_save, r1
mov.l @r1, r0
ldc r0, sr
bra atomic_end_exit
nop
atomic_end_error:
mov #-1, r0
atomic_end_exit:
rts
nop
.align 4
atomic_counter: .long _atomic_counter
atomic_sr_save: .long _atomic_sr_save
/*
** Global symbols
*/
.global _atomic_sr_save
.type _atomic_sr_save, @object
.global _atomic_counter
.type _atomic_counter, @object
.align 4
_atomic_sr_save: .long 0x00000000
_atomic_counter: .long 0x00000000

166
src/kernel/drivers.c Normal file
View File

@ -0,0 +1,166 @@
//---
// gint:core:drivers - Drivers manager
//---
#include <gint/drivers.h>
#include <gint/hardware.h>
#include <gint/atomic.h>
#include <gint/std/string.h>
#include <gint/std/stdlib.h>
#include "drivers.h"
/* external driver information */
extern gint_driver_t bdrv;
extern gint_driver_t edrv;
//---
// Context interface
//---
/* drivers_context_get_size(): Return the buffctx size */
size_t drivers_context_get_size(void)
{
size_t size = 0;
for driver_asc(drv) {
if (drv->ctx_size != NULL)
size += (drv->ctx_size() + 3) & ~3;
}
return (size);
}
/* drivers_create_cotext(): Generate buffer with can content all driver ctx */
void *drivers_context_create(void)
{
return (malloc(drivers_context_get_size()));
}
/* drivers_context_duplicate(): Duplicate an environment */
int drivers_context_duplicate(void **dst, void *src)
{
if (src == NULL)
return (-1);
size_t ctxsz = drivers_context_get_size();
*dst = realloc(*dst, ctxsz);
if (*dst == NULL)
return (-2);
atomic_begin();
memcpy(*dst, src, ctxsz);
atomic_end();
return (0);
}
/* drivers_context_destroy(): Destroy generated context */
void drivers_context_destroy(void **buffctx)
{
if (buffctx != NULL && *buffctx != NULL)
free(*buffctx);
*buffctx = NULL;
}
//---
// Drivers interface
//---
/* current env drivers information */
void *kernel_env_current = NULL;
/* driver_wait(): Wait until all driver have finished */
void drivers_wait(void)
{
for driver_asc(drv) {
if (drv->wait != NULL)
drv->wait();
}
}
/* drivers_save(): save the current drivers' context */
int drivers_save(void *buffctx)
{
if (buffctx == NULL)
return (-1);
/* we need to wait until all transction has been done */
drivers_wait();
/* save the current drivers state into the given env */
atomic_begin();
buffctx += drivers_context_get_size();
for driver_dsc(drv) {
if (drv->ctx_size != NULL)
buffctx -= (drv->ctx_size() + 3) & ~3;
if (drv->ctx_save != NULL)
drv->ctx_save(buffctx);
}
atomic_end();
return (0);
}
/* drivers_restore(): restore entier drivers' context */
void *drivers_restore(void *buffctx)
{
void *tmp;
if (buffctx == NULL)
return (NULL);
/* we need to wait until all transction has been done */
drivers_wait();
/* switch current env then restore the saved drivers' env */
atomic_begin();
tmp = kernel_env_current;
kernel_env_current = buffctx;
for driver_asc(drv) {
if (drv->ctx_restore != NULL)
drv->ctx_restore(buffctx);
if (drv->ctx_size != NULL)
buffctx += (drv->ctx_size() + 3) & ~3;
}
atomic_end();
/* return the previous env */
return (tmp);
}
/* drivers_save_and_exit(): save the current context and init the next */
void *drivers_init(void *buffctx)
{
void *tmp;
if (buffctx == NULL)
return (NULL);
/* switch the current env then initialize it */
atomic_begin();
tmp = kernel_env_current;
kernel_env_current = buffctx;
for driver_asc(drv) {
if (isSH3() && drv->driver_sh3 != NULL)
drv->driver_sh3();
if (drv->init != NULL)
drv->init();
}
atomic_end();
/* return the previous env */
return (tmp);
}
//---
// abstraction
//---
/* drivers_switch(): Switch between two world */
void *drivers_switch(void *buffctx)
{
drivers_save(kernel_env_current);
return (drivers_restore(buffctx));
}
/* drivers_get_current(): return the current context information */
void *drivers_get_current(void)
{
return (kernel_env_current);
}

32
src/kernel/hypervisor.c Normal file
View File

@ -0,0 +1,32 @@
//---
// gint:kernel:hypervisor - small hypervisor that perform world switch
//---
#include <gint/gint.h>
#include <gint/atomic.h>
#include <gint/defs/attributes.h>
#include <gint/drivers.h>
/* external symbols */
extern void *kernel_env_casio;
extern void *kernel_env_gint;
#if 0
/* gint_switch(): Temporarily switch out of gint */
GWEAK void gint_switch(void (*function)(void))
{
void *buffctx;
/* check useless switch */
if(function == NULL)
return;
/* Switch from gint to the OS after a short wait */
buffctx = drivers_switch(kernel_env_casio);
/* involve function */
function();
/* Then switch back to gint once the OS finishes working */
drivers_switch(buffctx);
}
#endif

View File

@ -2,242 +2,46 @@
// gint:core:kernel - Installing and unloading the library
//---
#include <gint/gint.h>
#include <gint/drivers.h>
#include <gint/std/string.h>
#include <gint/hardware.h>
#include <gint/mmu.h>
#include <gint/mpu/intc.h>
#include <gint/drivers.h>
#include <gint/atomic.h>
#include "cpu.h"
#include "vbr.h"
#include "drivers.h"
#include "kernel.h"
/* internal global witch content Casio and Gint environment */
void *kernel_env_casio;
void *kernel_env_gint;
static void kinit_cpu(void);
/* Forcefully pull in the INTC driver which gint cannot run without */
extern gint_driver_t drv_intc;
GUNUSED gint_driver_t *gint_required_intc = &drv_intc;
//---
// Context for the CPU and registers not directly managed by a driver
//---
typedef struct
{
sr_t SR;
uint32_t VBR;
uint32_t CPUOPM;
} ctx_t;
/* System context and gint context for the CPU and VBR */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(ctx_t *ctx)
{
if(isSH4())
{
ctx->CPUOPM = cpu_getCPUOPM();
ctx->SR = cpu_getSR();
}
}
static void ctx_restore(ctx_t *ctx)
{
if(isSH4())
{
cpu_setCPUOPM(ctx->CPUOPM);
cpu_setSR(ctx->SR);
}
}
//---
// Driver control
//---
static void drivers_wait(void)
{
for driver_asc(d)
{
if(d->wait) d->wait();
}
}
static void drivers_save_and_init(GUNUSED int zero)
{
/* Initialize the CPU, which is done here instead of in a driver */
ctx_save(&sys_ctx);
kinit_cpu();
for driver_asc(d)
{
if(isSH3() && d->driver_sh3) d->driver_sh3();
if(d->ctx_save) d->ctx_save(d->sys_ctx);
if(d->init) d->init();
}
}
static void drivers_restore(int who)
{
for driver_dsc(d)
{
if(d->ctx_restore) d->ctx_restore(who?d->gint_ctx:d->sys_ctx);
}
ctx_restore(who ? &gint_ctx : &sys_ctx);
}
static void drivers_switch(int who)
{
/* Save all drivers in reverse order */
for driver_dsc(d)
{
if(!d->ctx_save || !d->ctx_restore) continue;
d->ctx_save(who ? d->gint_ctx : d->sys_ctx);
}
ctx_save(who ? &gint_ctx : &sys_ctx);
/* Restore the other context */
ctx_restore(who ? &sys_ctx : &gint_ctx);
for driver_asc(d)
{
if(!d->ctx_save || !d->ctx_restore) continue;
d->ctx_restore(who ? d->sys_ctx : d->gint_ctx);
}
}
//---
// Initialization and unloading
//---
static void kinit_cpu(void)
{
if(isSH4())
{
cpu_setCPUOPM(cpu_getCPUOPM() | 0x00000008);
/* Enable DSP mode on the CPU */
sr_t SR = cpu_getSR();
SR.DSP = 1;
cpu_setSR(SR);
}
}
/* global information ( workaround >_< ) */
void *gint_vbr = NULL;
/* kinit(): Install and start gint */
void kinit(void)
{
/* generate the VBR address */
#ifdef FX9860G
/* VBR is loaded 0x600 bytes before end of the user RAM (0x100 bytes at
the start of the VBR space are unused) */
gint_ctx.VBR = (uint32_t)mmu_uram() + 0x1a00 - 0x100;
gint_vbr = (void*)(uintptr_t)mmu_uram() + 0x1a00 - 0x100;
#endif
#ifdef FXCG50
/* VBR is loaded at the start of the user RAM */
gint_ctx.VBR = (uint32_t)mmu_uram();
gint_vbr = (void*)(uintptr_t)mmu_uram();
#endif
/* Event handler entry points */
void *inth_entry = isSH3() ? gint_inth_7705 : gint_inth_7305;
uint32_t exch_size = (uint32_t)&gint_exch_size;
uint32_t tlbh_size = (uint32_t)&gint_tlbh_size;
/* Load the event handler entry points into memory */
void *vbr = (void *)gint_ctx.VBR;
memcpy(vbr + 0x100, gint_exch, exch_size);
memcpy(vbr + 0x400, gint_tlbh, tlbh_size);
memcpy(vbr + 0x600, inth_entry, 64);
/* Take control of the VBR and roll! */
drivers_wait();
sys_ctx.VBR = (*cpu_setVBR)(gint_ctx.VBR, drivers_save_and_init, 0);
}
/* Due to dire space restrictions on SH3, event codes that are translated to
SH4 are further remapped into the VBR space to eliminate gaps and save
space. Each entry in this table represents a 32-byte block after the
interrupt handler's entry gate. It shows the SH4 event code whose gate is
placed on that block (some of gint's SH4 event codes are invented to host
helper blocks).
For instance, the 5th block after the entry gate hosts the interrupt handler
for SH4 event 0x9e0, which is ETMU0 underflow.
The _inth_remap table in src/core/inth.S combines the SH3-SH4 translation
with the compact translation, hence its entry for 0xf00 (the SH3 event code
for ETMU0 underflow) is the offset in this table where 0x9e0 is stored,
which is 4. */
static const uint16_t sh3_vbr_map[] = {
0x400, /* TMU0 underflow */
0x420, /* TMU1 underflow */
0x440, /* TMU2 underflow */
0x460, /* (gint custom: TMU helper) */
0x9e0, /* ETMU0 underflow */
0xd00, /* ETMU4 underflow (used as helper on SH3) */
0xd20, /* (gint custom: ETMU helper) */
0xd40, /* (gint custom: ETMU helper) */
0xaa0, /* RTC Periodic Interrupt */
1, /* (Filler to maintain the gap between 0xaa0 and 0xae0) */
0xae0, /* (gint custom: RTC helper) */
0
};
/* gint_inthandler(): Install interrupt handlers */
void *gint_inthandler(int event_code, const void *handler, size_t size)
{
void *dest;
/* Normalize the event code */
if(event_code < 0x400) return NULL;
event_code &= ~0x1f;
/* On SH3, make VBR compact. Use this offset specified in the VBR map
above to avoid gaps */
if(isSH3())
{
int index = 0;
while(sh3_vbr_map[index])
{
if((int)sh3_vbr_map[index] == event_code) break;
index++;
}
/* This happens if the event has not beed added to the table,
ie. the compact VBR scheme does not support this code */
if(!sh3_vbr_map[index]) return NULL;
/* Gates are placed starting at VBR + 0x200 to save space */
dest = (void *)gint_ctx.VBR + 0x200 + index * 0x20;
}
/* On SH4, just use the code as offset */
else
{
/* 0x40 is the size of the entry gate */
dest = (void *)gint_ctx.VBR + 0x640 + (event_code - 0x400);
}
return memcpy(dest, handler, size);
}
/* gint_switch(): Temporarily switch out of gint */
void gint_switch(void (*function)(void))
{
/* Switch from gint to the OS after a short wait */
drivers_wait();
(*cpu_setVBR)(sys_ctx.VBR, drivers_switch, 1);
if(function) function();
/* Then switch back to gint once the OS finishes working */
drivers_wait();
(*cpu_setVBR)(gint_ctx.VBR, drivers_switch, 0);
/* create Casio's context, switch to Gint and save Gint context */
kernel_env_gint = drivers_context_create();
kernel_env_casio = drivers_context_create();
drivers_save(kernel_env_casio);
drivers_init(kernel_env_gint);
drivers_save(kernel_env_gint);
}
/* kquit(): Quit gint and give back control to the system */
void kquit(void)
{
/* Wait for hardware tasks then restore all of the drivers' state and
return the VBR space to the OS */
drivers_wait();
(*cpu_setVBR)(sys_ctx.VBR, drivers_restore, 0);
drivers_restore(kernel_env_casio);
atomic_begin();
drivers_context_destroy(&kernel_env_casio);
drivers_context_destroy(&kernel_env_gint);
atomic_end();
}

View File

@ -6,9 +6,9 @@
#define GINT_CORE_KERNEL
/* kinit(): Install and start gint */
void kinit(void);
extern void kinit(void);
/* kquit(): Quit gint and give back control to the system */
void kquit(void);
extern void kquit(void);
#endif /* GINT_CORE_KERNEL */

View File

@ -170,8 +170,6 @@ typedef struct {
uint32_t IRMCR;
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
if(isSH3()) return;
@ -190,13 +188,17 @@ static void ctx_restore(void *buf)
SH7305_MMU.IRMCR.lword = ctx->IRMCR;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
gint_driver_t drv_mmu = {
.name = "MMU",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(1, drv_mmu);

View File

@ -253,9 +253,6 @@ typedef struct
} GPACKED(2) ctx_t;
/* Allocate one buffer in gint's storage section */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -268,10 +265,15 @@ static void ctx_restore(void *buf)
r61524_win_set(ctx->HSA, ctx->HEA, ctx->VSA, ctx->VEA);
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver initialization
//---
/* init(): Initialize the hardware */
static void init(void)
{
select(device_code_read);
@ -284,14 +286,14 @@ static void init(void)
//---
// Driver structure definition
//---
/* define the driver object */
gint_driver_t drv_r61524 = {
.name = "R61524",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
/* register the driver */
GINT_DECLARE_DRIVER(5, drv_r61524);

View File

@ -11,3 +11,9 @@ void dupdate(void)
overwriting the data which is about to be sent. */
dvram_switch();
}
/* dupdate_noint(): Push the video RAM to the display driver without DMA */
void dupdate_noint(void)
{
r61524_display(gint_vram, 0, 224, R61524_CPU);
}

View File

@ -180,8 +180,6 @@ typedef struct
uint8_t RCR2;
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -197,6 +195,11 @@ static void ctx_restore(void *buf)
RTC->RCR2.byte = ctx->RCR2 & 0x7f;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
@ -205,10 +208,9 @@ gint_driver_t drv_rtc = {
.name = "RTC",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(2, drv_rtc);

View File

@ -62,8 +62,6 @@ typedef struct
uint32_t XBANKC0, XBANKC1;
} ctx_t;
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -82,6 +80,11 @@ static void ctx_restore(void *buf)
SPU.XBANKC1 = ctx->XBANKC1;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
@ -89,10 +92,9 @@ static void ctx_restore(void *buf)
gint_driver_t drv_spu = {
.name = "SPU",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(3, drv_spu);

16
src/std/stdlib.c Normal file
View File

@ -0,0 +1,16 @@
#include <gint/defs/types.h>
#include <gint/defs/attributes.h>
GWEAK int atoi(const char *restrict s)
{
if (s == NULL)
return (0);
int nb = 0;
for (int i = 0; s[i] != '\0'; ++i) {
if (s[i] < '0' || s[i] > '9')
return (nb);
nb = (nb * 10) + (s[i] - '0');
}
return (nb);
}

View File

@ -33,3 +33,35 @@ GWEAK int strcmp(char const *s1, char const *s2)
while(*s1 && *s1 == *s2) s1++, s2++;
return *s1 - *s2;
}
GWEAK char *strchr(const char *s1, int c)
{
void *ret;
int i;
i = -1;
while (s1[++i] != '\0' && s1[i] != c);
ret = NULL;
if (s1[i] != '\0')
ret = (void *)&s1[i];
return (ret);
}
GWEAK char *strchrnul(const char *s1, int c)
{
int i = -1;
while (s1[++i] != '\0' && s1[i] != c) ;
return ((void *)&s1[i]);
}
GWEAK char *strrchr(const char *s1, int c)
{
void *saved;
saved = NULL;
for (int i = 0; s1[i] != '\0'; i++) {
if (s1[i] == c)
saved = (void *)&s1[i];
}
return (saved);
}

View File

@ -195,9 +195,6 @@ typedef struct
} GPACKED(1) ctx_t;
/* Pre-allocate a context in gint's uninitialized section */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
if(gint[HWCALC] == HWCALC_G35PE2) return;
@ -221,6 +218,11 @@ static void ctx_restore(void *buf)
command(reg_counter, cnt);
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver initialization
//---
@ -239,10 +241,9 @@ static void init(void)
gint_driver_t drv_t6k11 = {
.name = "T6K11",
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(5, drv_t6k11);

View File

@ -436,9 +436,6 @@ typedef struct
uint8_t TSTR;
} ctx_t;
/* Allocate a system buffer in gint's BSS area */
GBSS static ctx_t sys_ctx, gint_ctx;
static void ctx_save(void *buf)
{
ctx_t *ctx = buf;
@ -498,6 +495,11 @@ static void ctx_restore(void *buf)
*TSTR = ctx->TSTR;
}
static size_t ctx_size(void)
{
return (sizeof(ctx_t));
}
//---
// Driver structure definition
//---
@ -506,10 +508,9 @@ gint_driver_t drv_tmu = {
.name = "TMU",
.driver_sh3 = GINT_DRIVER_SH3(driver_sh3),
.init = init,
.sys_ctx = &sys_ctx,
.gint_ctx = &gint_ctx,
.ctx_save = ctx_save,
.ctx_restore = ctx_restore,
.ctx_size = &ctx_size,
.ctx_save = (void*)&ctx_save,
.ctx_restore = (void*)&ctx_restore,
};
GINT_DECLARE_DRIVER(2, drv_tmu);