mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
intc: allow user-space handlers to access the interrupted context
This workaround using a gint_call_t with an odd address is not realy the cleanest idea but it helps keep the existing intc_generic_handler in the 32 bytes size limit of the VBR space.
This commit is contained in:
parent
eca05ec64c
commit
76c82beec6
4 changed files with 58 additions and 7 deletions
|
@ -144,6 +144,19 @@ typedef struct {
|
||||||
/* GINT_CALL_NULL: Empty function call */
|
/* GINT_CALL_NULL: Empty function call */
|
||||||
#define GINT_CALL_NULL ((gint_call_t){ .function = NULL, .args = {} })
|
#define GINT_CALL_NULL ((gint_call_t){ .function = NULL, .args = {} })
|
||||||
|
|
||||||
|
/* GINT_CALL_FLAG(): Build an indirect call to an odd address
|
||||||
|
|
||||||
|
This is used as a workaround to have an extra flag in gint_call_t structures
|
||||||
|
without altering their size and exploits the fact that SuperH code has to be
|
||||||
|
aligned on even addresses.
|
||||||
|
It is up to the caller to notice the presence of the flag and realign the
|
||||||
|
address properly.
|
||||||
|
|
||||||
|
This flag is currently only checked by gint_inth_callback to specify that the
|
||||||
|
called function will take the interrupt context as its first argument. */
|
||||||
|
#define GINT_CALL_FLAG(func, ...) \
|
||||||
|
GINT_CALL((void*)((uint32_t)(func) | 1), __VA_ARGS__)
|
||||||
|
|
||||||
/* gint_call(): Perform an indirect call */
|
/* gint_call(): Perform an indirect call */
|
||||||
static GINLINE int gint_call(gint_call_t cb)
|
static GINLINE int gint_call(gint_call_t cb)
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,10 +105,29 @@ static GINLINE void *gint_inthandler(int code, void const *h, size_t size) {
|
||||||
.callback:
|
.callback:
|
||||||
.long _gint_inth_callback
|
.long _gint_inth_callback
|
||||||
|
|
||||||
|
The gint_call_t object can be built with GINT_CALL_FLAG to specify that the
|
||||||
|
called function should get a pointer to a gint_inth_callback_context_t
|
||||||
|
strcture as its first argument.
|
||||||
|
|
||||||
@call Address of a gint_call_t object
|
@call Address of a gint_call_t object
|
||||||
Returns the return value of the callback. */
|
Returns the return value of the callback. */
|
||||||
extern int (*gint_inth_callback)(gint_call_t const *call);
|
extern int (*gint_inth_callback)(gint_call_t const *call);
|
||||||
|
|
||||||
|
/* gint_inth_callback_context_t: Context of the interrupted function when an
|
||||||
|
interrupt is handled by gint_inth_callback. */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t ssr;
|
||||||
|
uint32_t spc;
|
||||||
|
uint32_t r7;
|
||||||
|
uint32_t r6;
|
||||||
|
uint32_t r5;
|
||||||
|
uint32_t r4;
|
||||||
|
uint32_t r3;
|
||||||
|
uint32_t r2;
|
||||||
|
uint32_t r1;
|
||||||
|
uint32_t r0;
|
||||||
|
} gint_inth_callback_context_t;
|
||||||
|
|
||||||
/* gint_set_quit_handler(): Setup a call to be invoked when leaving the add-in
|
/* gint_set_quit_handler(): Setup a call to be invoked when leaving the add-in
|
||||||
|
|
||||||
This function sets up the provided GINT_CALL() to be invoked when the
|
This function sets up the provided GINT_CALL() to be invoked when the
|
||||||
|
|
|
@ -130,6 +130,11 @@ void *intc_handler(int event_code, void const *handler, size_t size);
|
||||||
the numerous constraints of intc_handler(), at the cost of always going back
|
the numerous constraints of intc_handler(), at the cost of always going back
|
||||||
to userspace and a small time overhead.
|
to userspace and a small time overhead.
|
||||||
|
|
||||||
|
Since gint_inth_callback is used to do the heavy lifting of setting up a sane
|
||||||
|
context for C code, the gint_call_t object can be built with GINT_CALL_FLAG
|
||||||
|
if the called function expects a gint_inth_callback_context_t structure as its
|
||||||
|
first argument.
|
||||||
|
|
||||||
@event_code Identifier of the interrupt block
|
@event_code Identifier of the interrupt block
|
||||||
@function Function to use as a handler
|
@function Function to use as a handler
|
||||||
Returns true on success, false if the event code is invalid. */
|
Returns true on success, false if the event code is invalid. */
|
||||||
|
|
|
@ -209,11 +209,15 @@ _gint_inth_callback_reloc:
|
||||||
stc.l r7_bank, @-r15
|
stc.l r7_bank, @-r15
|
||||||
stc.l spc, @-r15
|
stc.l spc, @-r15
|
||||||
stc.l ssr, @-r15
|
stc.l ssr, @-r15
|
||||||
|
/* We backup the address of the gint_inth_callback_context_t built on
|
||||||
|
the stack to the user bank. */
|
||||||
|
ldc r15, r4_bank
|
||||||
|
|
||||||
stc.l sr, @-r15
|
stc.l sr, @-r15
|
||||||
|
|
||||||
/* Save some values to user bank; once we enable interrupts, the kernel
|
/* Save some values to user bank; once we enable interrupts, the kernel
|
||||||
bank might be overwritten at any moment. */
|
bank might be overwritten at any moment. */
|
||||||
ldc r4, r0_bank
|
ldc r4, r3_bank
|
||||||
|
|
||||||
/* Enable interrupts and go back to user bank. On SH4, SR.IMASK is set
|
/* Enable interrupts and go back to user bank. On SH4, SR.IMASK is set
|
||||||
to the level of the current interrupt, which makes sure we can only
|
to the level of the current interrupt, which makes sure we can only
|
||||||
|
@ -243,15 +247,25 @@ _gint_inth_callback_reloc:
|
||||||
.load_sr:
|
.load_sr:
|
||||||
ldc r1, sr
|
ldc r1, sr
|
||||||
|
|
||||||
/* We are now in the user bank with r0 set. Perform the call. We want
|
/* We are now in the user bank with r3 set. Perform the call. We want
|
||||||
to forward the return value to kernel bank, but this bank can be
|
to forward the return value to kernel bank, but this bank can be
|
||||||
changed at any moment since interrupts are enabled. */
|
changed at any moment since interrupts are enabled. */
|
||||||
sts.l pr, @-r15
|
sts.l pr, @-r15
|
||||||
mov.l @(4, r0), r4
|
|
||||||
mov.l @(8, r0), r5
|
/* We only set r4 to the value of the first argument in the gint_call_t
|
||||||
mov.l @(12, r0), r6
|
if the address is even (i.e. GINT_CALL_FLAG() was not used). */
|
||||||
mov.l @(16, r0), r7
|
mov.l @r3, r0
|
||||||
mov.l @r0, r0
|
tst #1, r0
|
||||||
|
bf .do_not_set_r4
|
||||||
|
mov.l @(4, r3), r4
|
||||||
|
.do_not_set_r4:
|
||||||
|
/* And we make sure to realign the address in case it was odd. */
|
||||||
|
mov #0xfe, r2
|
||||||
|
and r2, r0
|
||||||
|
|
||||||
|
mov.l @(8, r3), r5
|
||||||
|
mov.l @(12, r3), r6
|
||||||
|
mov.l @(16, r3), r7
|
||||||
jsr @r0
|
jsr @r0
|
||||||
nop
|
nop
|
||||||
lds.l @r15+, pr
|
lds.l @r15+, pr
|
||||||
|
|
Loading…
Reference in a new issue