This patchset is aimed at unifying the code used to preserve CPU context when switching from client programs into Forth, via either the CIF or interrupt handlers.
It is part of a longer process to enable access to saved CPU context state from within Forth which will eventually enable proper implementation of the init-program and go words.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
Mark Cave-Ayland (8): SPARC64: create proper stack frame when entering client interface SPARC64: introduce new Forth context stack (fcstack) for CPU contexts SPARC64: switch client interface over to use new Forth context stack SPARC64: switch IMMU/DMMU miss handlers over to use new Forth context stack SPARC64: move client interface stack inline to the new Forth context stack SPARC64: move IMMU/DMMU miss handler stacks inline to the new Forth context stack SPARC64: reorganise IMMU/DMMU trap context structure SPARC64: rearrange saved state window order
openbios-devel/arch/sparc64/call-client.S | 218 +++++---------------- openbios-devel/arch/sparc64/context.c | 4 + openbios-devel/arch/sparc64/cpustate.h | 244 +++++++++++++++++++++++ openbios-devel/arch/sparc64/ldscript | 5 + openbios-devel/arch/sparc64/vectors.S | 300 ++++++----------------------- openbios-devel/include/arch/sparc64/io.h | 2 +- 6 files changed, 367 insertions(+), 406 deletions(-) create mode 100644 openbios-devel/arch/sparc64/cpustate.h
The original motivation behind reducing the stack frame size was in order to keep the stack usage low enough to boot OpenBSD/NetBSD.
Since the final solution now is to save and restore the entire CPU state around CIF calls then this no longer matters.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/call-client.S | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/openbios-devel/arch/sparc64/call-client.S b/openbios-devel/arch/sparc64/call-client.S index f365e3c..0223168 100644 --- a/openbios-devel/arch/sparc64/call-client.S +++ b/openbios-devel/arch/sparc64/call-client.S @@ -176,15 +176,15 @@ client_window: sparc64_of_client_interface:
/* Save globals on callers stack */ - add %sp, -56, %sp + add %sp, -248, %sp
- stx %g1, [%sp + 2047 + 0] - stx %g2, [%sp + 2047 + 8] - stx %g3, [%sp + 2047 + 16] - stx %g4, [%sp + 2047 + 24] - stx %g5, [%sp + 2047 + 32] - stx %g6, [%sp + 2047 + 40] - stx %g7, [%sp + 2047 + 48] + stx %g1, [%sp + 2047 + 192] + stx %g2, [%sp + 2047 + 200] + stx %g3, [%sp + 2047 + 208] + stx %g4, [%sp + 2047 + 216] + stx %g5, [%sp + 2047 + 224] + stx %g6, [%sp + 2047 + 232] + stx %g7, [%sp + 2047 + 240]
/* Save client trap table */ setx client_tba, %g6, %g7 @@ -222,15 +222,15 @@ sparc64_of_client_interface: wrpr %g6, %tba
/* Restore globals */ - ldx [%sp + 2047 + 0], %g1 - ldx [%sp + 2047 + 8], %g2 - ldx [%sp + 2047 + 16], %g3 - ldx [%sp + 2047 + 24], %g4 - ldx [%sp + 2047 + 32], %g5 - ldx [%sp + 2047 + 40], %g6 - ldx [%sp + 2047 + 48], %g7 - - add %sp, 56, %sp + ldx [%sp + 2047 + 192], %g1 + ldx [%sp + 2047 + 200], %g2 + ldx [%sp + 2047 + 208], %g3 + ldx [%sp + 2047 + 216], %g4 + ldx [%sp + 2047 + 224], %g5 + ldx [%sp + 2047 + 232], %g6 + ldx [%sp + 2047 + 240], %g7 + + add %sp, 248, %sp
jmp %o7+8 nop
The fcstack holds a stack of complete CPU states which can be used to enable re-entrant calls into Forth (e.g. when processing interrupts).
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/context.c | 4 ++++ openbios-devel/arch/sparc64/ldscript | 5 +++++ openbios-devel/include/arch/sparc64/io.h | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/arch/sparc64/context.c b/openbios-devel/arch/sparc64/context.c index 2e76689..98932ee 100644 --- a/openbios-devel/arch/sparc64/context.c +++ b/openbios-devel/arch/sparc64/context.c @@ -40,6 +40,10 @@ static uint8_t image_stack[IMAGE_STACK_SIZE]; /* Pointer to startup context (physical address) */ unsigned long __boot_ctx;
+/* Pointer to Forth context stack */ +void *_fcstack_ptr = &_efcstack; + + /* * Main starter * This is the C function that runs first. diff --git a/openbios-devel/arch/sparc64/ldscript b/openbios-devel/arch/sparc64/ldscript index 54288e8..c5cc6a5 100644 --- a/openbios-devel/arch/sparc64/ldscript +++ b/openbios-devel/arch/sparc64/ldscript @@ -50,6 +50,11 @@ SECTIONS *(.bss.*) *(COMMON)
+ _fcstack = .; + . += 32768; + . = ALIGN(16); + _efcstack = .; + _stack = .; . += STACK_SIZE; . = ALIGN(16); diff --git a/openbios-devel/include/arch/sparc64/io.h b/openbios-devel/include/arch/sparc64/io.h index 2e4dfa3..0f1a732 100644 --- a/openbios-devel/include/arch/sparc64/io.h +++ b/openbios-devel/include/arch/sparc64/io.h @@ -9,7 +9,7 @@
extern unsigned long va_shift; // Set in entry.S // Defined in ldscript -extern char _start, _data, _stack, _estack, _end, _iomem; +extern char _start, _data, _stack, _estack, _fcstack, _efcstack, _end, _iomem;
// XXX check use and merge #define phys_to_virt(phys) ((void *) ((unsigned long) (phys)))
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/call-client.S | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/openbios-devel/arch/sparc64/call-client.S b/openbios-devel/arch/sparc64/call-client.S index 0223168..bad8aa0 100644 --- a/openbios-devel/arch/sparc64/call-client.S +++ b/openbios-devel/arch/sparc64/call-client.S @@ -10,7 +10,6 @@ */
#define SAVE_WINDOW_STATE(type) \ - setx client_window, %g6, %g1; \ rdpr %cwp, %g7; \ stx %g7, [%g1]; \ rdpr %cansave, %g7; \ @@ -85,8 +84,6 @@ save_cpu_window_##type: \
#define RESTORE_WINDOW_STATE(type) \ - setx client_window, %g6, %g1; \ - \ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ @@ -196,6 +193,11 @@ sparc64_of_client_interface: stx %sp, [%g7]
/* Save windows */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, -0x510, %g1 + stx %g1, [%g7] + SAVE_WINDOW_STATE(cif)
/* Move to OpenBIOS stack */ @@ -206,12 +208,19 @@ sparc64_of_client_interface: call of_client_interface ldx [%g1 + 0x30], %o0
- setx client_window, %g6, %g1 - stx %o0, [%g1 + 0x30] - /* Restore windows */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + + /* Return value */ + stx %o0, [%g1 + 0x30] + RESTORE_WINDOW_STATE(cif) - + + add %g1, 0x510, %g1 + setx _fcstack_ptr, %g6, %g7 + stx %g1, [%g7] + /* Restore stack */ setx client_stack, %g6, %g7 ldx [%g7], %sp
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/vectors.S | 64 ++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 25 deletions(-)
diff --git a/openbios-devel/arch/sparc64/vectors.S b/openbios-devel/arch/sparc64/vectors.S index 927c1cd..0a95f2e 100644 --- a/openbios-devel/arch/sparc64/vectors.S +++ b/openbios-devel/arch/sparc64/vectors.S @@ -355,11 +355,6 @@ fill_32bit: */
#define SAVE_CPU_STATE(type) \ - /* Set up our exception stack pointer in %g1 */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - ldx [%g6], %g1; \ - add %g1, -0x510, %g1; \ - \ /* First save the various state registers */ \ rdpr %cwp, %g7; \ stx %g7, [%g1]; \ @@ -456,18 +451,10 @@ save_cpu_window_##type: \ \ wrpr %g0, %cleanwin; \ wrpr %g0, %canrestore; \ - wrpr %g0, %otherwin; \ - \ - /* Update our exception stack pointer */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - stx %g1, [%g6]; + wrpr %g0, %otherwin
#define RESTORE_CPU_STATE(type) \ - /* Set up our exception stack pointer in %g1 */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - ldx [%g6], %g1; \ - \ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ @@ -547,22 +534,24 @@ restore_trap_state_##type: \ ldx [%g1 + 0x40], %g7; \ wr %g7, 0, %fprs; \ ldx [%g1 + 0x48], %g7; \ - wrpr %g7, %tl; \ - \ - /* Restore exception stack pointer to previous value */ \ - setx tlb_handler_stack_pointer, %g7, %g6; \ - add %g1, 0x510, %g1; \ - stx %g1, [%g6]; + wrpr %g7, %tl
.globl reload_DMMU_tlb, reload_IMMU_tlb, bug
reload_DMMU_tlb: - + + /* Save CPU state to stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, -0x510, %g1 + stx %g1, [%g7] + SAVE_CPU_STATE(dtlb)
/* Switch to TLB locked stack space (note we add an additional 192 bytes required for gcc to save its arguments when building with -O0) */ + setx tlb_handler_stack_top, %g6, %g1 add %g1, -STACK_BIAS - 192, %sp
/* Enable interrupts for window spill/fill traps */ @@ -577,17 +566,33 @@ reload_DMMU_tlb: rdpr %pstate, %g7 andn %g7, PSTATE_IE, %g7 wrpr %g7, %pstate - + + /* Restore CPU state from stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + RESTORE_CPU_STATE(dtlb) - + + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, 0x510, %g1 + stx %g1, [%g7] + retry
reload_IMMU_tlb: - + + /* Save CPU state to stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, -0x510, %g1 + stx %g1, [%g7] + SAVE_CPU_STATE(itlb)
/* Switch to TLB locked stack space (note we add an additional 192 bytes required for gcc to save its arguments when building with -O0) */ + setx tlb_handler_stack_top, %g6, %g1 add %g1, -STACK_BIAS - 192, %sp
/* Enable interrupts for window spill/fill traps */ @@ -602,8 +607,17 @@ reload_IMMU_tlb: rdpr %pstate, %g7 andn %g7, PSTATE_IE, %g7 wrpr %g7, %pstate - + + /* Restore CPU state from stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + RESTORE_CPU_STATE(itlb) + + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g1 + add %g1, 0x510, %g1 + stx %g1, [%g7]
retry
Rather than having a separate OpenBIOS stack for client interface calls, reuse the Forth stack by reserving 8K extra beneath the CPU save state area and using that instead.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/call-client.S | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/openbios-devel/arch/sparc64/call-client.S b/openbios-devel/arch/sparc64/call-client.S index bad8aa0..66e0809 100644 --- a/openbios-devel/arch/sparc64/call-client.S +++ b/openbios-devel/arch/sparc64/call-client.S @@ -148,9 +148,6 @@ restore_cpu_window_##type: \ .data .align 8
- .skip 16384 -openbios_stack: - client_stack: .xword 0 client_tba: @@ -200,8 +197,15 @@ sparc64_of_client_interface: SAVE_WINDOW_STATE(cif)
- /* Move to OpenBIOS stack */ - setx openbios_stack - 2047 - 192, %g6, %g7 + /* Move to OpenBIOS context stack */ + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g6 + setx 0x2000, %g4, %g5 + sub %g6, %g5, %g6 + stx %g6, [%g7] + + setx - 2047 - 192, %g6, %g7 + add %g1, %g7, %g7 mov %g7, %sp
/* Call client inteface */ @@ -211,6 +215,9 @@ sparc64_of_client_interface: /* Restore windows */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 + setx 0x2000, %g4, %g5 + add %g1, %g5, %g1 + stx %g1, [%g7] /* Return value */ stx %o0, [%g1 + 0x30]
Rather than having a separate OpenBIOS stack for IMMU/DMMU miss handlers, reuse the Forth context stack by reserving 8K extra beneath the CPU save state area and using that instead.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/vectors.S | 43 +++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/openbios-devel/arch/sparc64/vectors.S b/openbios-devel/arch/sparc64/vectors.S index 0a95f2e..f489f35 100644 --- a/openbios-devel/arch/sparc64/vectors.S +++ b/openbios-devel/arch/sparc64/vectors.S @@ -276,17 +276,8 @@ tl1_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8)
.section ".data" .align 8 - .globl tlb_handler_stack_top, tlb_handler_stack_pointer, obp_ticks_pointer + .globl obp_ticks_pointer
- ! Stack for the tlb MMU trap handlers -tlb_handler_stack_bottom: - .skip 8192 -tlb_handler_stack_top: - .skip 8 - - ! MMU trap handler stack pointer -tlb_handler_stack_pointer: - .xword tlb_handler_stack_top
! Pointer to current tick value obp_ticks_pointer: @@ -549,10 +540,17 @@ reload_DMMU_tlb: SAVE_CPU_STATE(dtlb)
- /* Switch to TLB locked stack space (note we add an additional 192 bytes required for + /* Switch to 8K TLB locked OpenBIOS stack (note we add an additional 192 bytes required for gcc to save its arguments when building with -O0) */ - setx tlb_handler_stack_top, %g6, %g1 - add %g1, -STACK_BIAS - 192, %sp + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g6 + setx 0x2000, %g4, %g5 + sub %g6, %g5, %g6 + stx %g6, [%g7] + + setx - 2047 - 192, %g6, %g7 + add %g1, %g7, %g7 + mov %g7, %sp
/* Enable interrupts for window spill/fill traps */ rdpr %pstate, %g7 @@ -570,6 +568,9 @@ reload_DMMU_tlb: /* Restore CPU state from stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 + setx 0x2000, %g4, %g5 + add %g1, %g5, %g1 + stx %g1, [%g7] RESTORE_CPU_STATE(dtlb) @@ -590,10 +591,17 @@ reload_IMMU_tlb: SAVE_CPU_STATE(itlb)
- /* Switch to TLB locked stack space (note we add an additional 192 bytes required for + /* Switch to 8K TLB locked OpenBIOS stack (note we add an additional 192 bytes required for gcc to save its arguments when building with -O0) */ - setx tlb_handler_stack_top, %g6, %g1 - add %g1, -STACK_BIAS - 192, %sp + setx _fcstack_ptr, %g6, %g7 + ldx [%g7], %g6 + setx 0x2000, %g4, %g5 + sub %g6, %g5, %g6 + stx %g6, [%g7] + + setx - 2047 - 192, %g6, %g7 + add %g1, %g7, %g7 + mov %g7, %sp
/* Enable interrupts for window spill/fill traps */ rdpr %pstate, %g7 @@ -611,6 +619,9 @@ reload_IMMU_tlb: /* Restore CPU state from stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 + setx 0x2000, %g4, %g5 + add %g1, %g5, %g1 + stx %g1, [%g7] RESTORE_CPU_STATE(itlb)
Here the trap context is reorganised to share the same prologue as the CIF context so that they can be subsequently unified.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/call-client.S | 150 +------------------ openbios-devel/arch/sparc64/cpustate.h | 230 +++++++++++++++++++++++++++++ openbios-devel/arch/sparc64/vectors.S | 217 ++------------------------- 3 files changed, 247 insertions(+), 350 deletions(-) create mode 100644 openbios-devel/arch/sparc64/cpustate.h
diff --git a/openbios-devel/arch/sparc64/call-client.S b/openbios-devel/arch/sparc64/call-client.S index 66e0809..a8c0348 100644 --- a/openbios-devel/arch/sparc64/call-client.S +++ b/openbios-devel/arch/sparc64/call-client.S @@ -1,3 +1,5 @@ +#include "cpustate.h" + .globl sparc64_of_client_interface, client_tba
@@ -9,142 +11,6 @@ * behaviour of OBP. */
-#define SAVE_WINDOW_STATE(type) \ - rdpr %cwp, %g7; \ - stx %g7, [%g1]; \ - rdpr %cansave, %g7; \ - stx %g7, [%g1 + 0x8]; \ - rdpr %canrestore, %g7; \ - stx %g7, [%g1 + 0x10]; \ - rdpr %otherwin, %g7; \ - stx %g7, [%g1 + 0x18]; \ - rdpr %wstate, %g7; \ - stx %g7, [%g1 + 0x20]; \ - rdpr %cleanwin, %g7; \ - stx %g7, [%g1 + 0x28]; \ - \ - stx %o0, [%g1 + 0x30]; \ - stx %o1, [%g1 + 0x38]; \ - stx %o2, [%g1 + 0x40]; \ - stx %o3, [%g1 + 0x48]; \ - stx %o4, [%g1 + 0x50]; \ - stx %o5, [%g1 + 0x58]; \ - stx %o6, [%g1 + 0x60]; \ - stx %o7, [%g1 + 0x68]; \ - \ - rdpr %pstate, %g7; \ - stx %g7, [%g1 + 0x70]; \ - rd %y, %g7; \ - stx %g7, [%g1 + 0x78]; \ - rd %fprs, %g7; \ - stx %g7, [%g1 + 0x80]; \ - \ - /* Now iterate through all of the windows saving all l and i registers */ \ - add %g1, 0x90, %g5; \ - \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ -save_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - stx %l0, [%g5]; \ - stx %l1, [%g5 + 0x8]; \ - stx %l2, [%g5 + 0x10]; \ - stx %l3, [%g5 + 0x18]; \ - stx %l4, [%g5 + 0x20]; \ - stx %l5, [%g5 + 0x28]; \ - stx %l6, [%g5 + 0x30]; \ - stx %l7, [%g5 + 0x38]; \ - stx %i0, [%g5 + 0x40]; \ - stx %i1, [%g5 + 0x48]; \ - stx %i2, [%g5 + 0x50]; \ - stx %i3, [%g5 + 0x58]; \ - stx %i4, [%g5 + 0x60]; \ - stx %i5, [%g5 + 0x68]; \ - stx %i6, [%g5 + 0x70]; \ - stx %i7, [%g5 + 0x78]; \ - bne save_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* For 8 windows with 16 registers to save in the window, memory required \ - is 16*8*8 = 0x400 bytes */ \ - \ - /* Now we should be in window 0 so update the other window registers */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - dec %g6; \ - wrpr %g6, %cansave; \ - \ - wrpr %g0, %cleanwin; \ - wrpr %g0, %canrestore; \ - wrpr %g0, %otherwin; - - -#define RESTORE_WINDOW_STATE(type) \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ - /* Now iterate through all of the windows restoring all l and i registers */ \ - add %g1, 0x90, %g5; \ - \ -restore_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - ldx [%g5], %l0; \ - ldx [%g5 + 0x8], %l1; \ - ldx [%g5 + 0x10], %l2; \ - ldx [%g5 + 0x18], %l3; \ - ldx [%g5 + 0x20], %l4; \ - ldx [%g5 + 0x28], %l5; \ - ldx [%g5 + 0x30], %l6; \ - ldx [%g5 + 0x38], %l7; \ - ldx [%g5 + 0x40], %i0; \ - ldx [%g5 + 0x48], %i1; \ - ldx [%g5 + 0x50], %i2; \ - ldx [%g5 + 0x58], %i3; \ - ldx [%g5 + 0x60], %i4; \ - ldx [%g5 + 0x68], %i5; \ - ldx [%g5 + 0x70], %i6; \ - ldx [%g5 + 0x78], %i7; \ - bne restore_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* Restore the window registers to their original value */ \ - ldx [%g1], %g7; \ - wrpr %g7, %cwp; \ - ldx [%g1 + 0x8], %g7; \ - wrpr %g7, %cansave; \ - ldx [%g1 + 0x10], %g7; \ - wrpr %g7, %canrestore; \ - ldx [%g1 + 0x18], %g7; \ - wrpr %g7, %otherwin; \ - ldx [%g1 + 0x20], %g7; \ - wrpr %g7, %wstate; \ - ldx [%g1 + 0x28], %g7; \ - wrpr %g7, %cleanwin; \ - \ - ldx [%g1 + 0x30], %o0; \ - ldx [%g1 + 0x38], %o1; \ - ldx [%g1 + 0x40], %o2; \ - ldx [%g1 + 0x48], %o3; \ - ldx [%g1 + 0x50], %o4; \ - ldx [%g1 + 0x58], %o5; \ - ldx [%g1 + 0x60], %o6; \ - ldx [%g1 + 0x68], %o7; \ - \ - ldx [%g1 + 0x70], %g7; \ - wrpr %g7, %pstate; \ - ldx [%g1 + 0x78], %g7; \ - wr %g7, 0, %y; \ - ldx [%g1 + 0x80], %g7; \ - wr %g7, 0, %fprs - - .data .align 8
@@ -192,15 +58,15 @@ sparc64_of_client_interface: /* Save windows */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - add %g1, -0x510, %g1 + add %g1, -CONTEXT_STATE_SIZE, %g1 stx %g1, [%g7] - SAVE_WINDOW_STATE(cif) + SAVE_CPU_WINDOW_STATE(cif)
/* Move to OpenBIOS context stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g6 - setx 0x2000, %g4, %g5 + setx CONTEXT_STACK_SIZE, %g4, %g5 sub %g6, %g5, %g6 stx %g6, [%g7] @@ -215,16 +81,16 @@ sparc64_of_client_interface: /* Restore windows */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - setx 0x2000, %g4, %g5 + setx CONTEXT_STACK_SIZE, %g4, %g5 add %g1, %g5, %g1 stx %g1, [%g7] /* Return value */ stx %o0, [%g1 + 0x30] - RESTORE_WINDOW_STATE(cif) + RESTORE_CPU_WINDOW_STATE(cif) - add %g1, 0x510, %g1 + add %g1, CONTEXT_STATE_SIZE, %g1 setx _fcstack_ptr, %g6, %g7 stx %g1, [%g7] diff --git a/openbios-devel/arch/sparc64/cpustate.h b/openbios-devel/arch/sparc64/cpustate.h new file mode 100644 index 0000000..35ca712 --- /dev/null +++ b/openbios-devel/arch/sparc64/cpustate.h @@ -0,0 +1,230 @@ +/* + * Save/restore CPU state macros + * + * Copyright (C) 2015 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk>) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 + * + */ + +/* State size for context (see below) */ +#define CONTEXT_STATE_SIZE 0x510 + +/* Stack size for context (allocated inline of the context stack) */ +#define CONTEXT_STACK_SIZE 0x2000 + +/* + * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch + * to C to occur within the MMU I/D TLB miss handlers. + * + * Because these handlers are called on a TLB miss, we cannot use flushw to store + * processor window state on the stack, as the memory areas used by each window's + * stack pointer may not be in the TLB, causing recursive TLB miss traps. + * + * For this reason, we save window state by manually rotating the window registers + * and saving their contents (along with other vital registers) into a special + * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and + * so won't cause issues with trap recursion. + * + * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow + * window fill/spill traps if required), switch to our safe tlb_handler_stack and + * invoke the miss handler. + */ + +#define SAVE_CPU_WINDOW_STATE(type) \ + /* Save window state into context at %g1 */ \ + rdpr %cwp, %g7; \ + stx %g7, [%g1]; \ + rdpr %cansave, %g7; \ + stx %g7, [%g1 + 0x8]; \ + rdpr %canrestore, %g7; \ + stx %g7, [%g1 + 0x10]; \ + rdpr %otherwin, %g7; \ + stx %g7, [%g1 + 0x18]; \ + rdpr %wstate, %g7; \ + stx %g7, [%g1 + 0x20]; \ + rdpr %cleanwin, %g7; \ + stx %g7, [%g1 + 0x28]; \ + \ + stx %o0, [%g1 + 0x30]; \ + stx %o1, [%g1 + 0x38]; \ + stx %o2, [%g1 + 0x40]; \ + stx %o3, [%g1 + 0x48]; \ + stx %o4, [%g1 + 0x50]; \ + stx %o5, [%g1 + 0x58]; \ + stx %o6, [%g1 + 0x60]; \ + stx %o7, [%g1 + 0x68]; \ + \ + rdpr %pstate, %g7; \ + stx %g7, [%g1 + 0x70]; \ + rd %y, %g7; \ + stx %g7, [%g1 + 0x78]; \ + rd %fprs, %g7; \ + stx %g7, [%g1 + 0x80]; \ + rdpr %tl, %g7; \ + stx %g7, [%g1 + 0x88]; \ + \ + /* Now iterate through all of the windows saving all l and i registers */ \ + add %g1, 0x90, %g5; \ + \ + /* Get the number of windows in %g6 */ \ + rdpr %ver, %g6; \ + and %g6, 0xf, %g6; \ + inc %g6; \ + \ +save_cpu_window_##type: \ + deccc %g6; \ + wrpr %g6, %cwp; \ + stx %l0, [%g5]; \ + stx %l1, [%g5 + 0x8]; \ + stx %l2, [%g5 + 0x10]; \ + stx %l3, [%g5 + 0x18]; \ + stx %l4, [%g5 + 0x20]; \ + stx %l5, [%g5 + 0x28]; \ + stx %l6, [%g5 + 0x30]; \ + stx %l7, [%g5 + 0x38]; \ + stx %i0, [%g5 + 0x40]; \ + stx %i1, [%g5 + 0x48]; \ + stx %i2, [%g5 + 0x50]; \ + stx %i3, [%g5 + 0x58]; \ + stx %i4, [%g5 + 0x60]; \ + stx %i5, [%g5 + 0x68]; \ + stx %i6, [%g5 + 0x70]; \ + stx %i7, [%g5 + 0x78]; \ + bne save_cpu_window_##type; \ + add %g5, 0x80, %g5; \ + \ + /* For 8 windows with 16 registers to save in the window, memory required \ + is 16*8*8 = 0x400 bytes */ \ + \ + /* Now we should be in window 0 so update the other window registers */ \ + rdpr %ver, %g6; \ + and %g6, 0xf, %g6; \ + dec %g6; \ + wrpr %g6, %cansave; \ + \ + wrpr %g0, %cleanwin; \ + wrpr %g0, %canrestore; \ + wrpr %g0, %otherwin; \ + + +#define SAVE_CPU_TRAP_STATE(type) \ + /* Save trap state into context at %g1 */ \ + add %g1, 0x490, %g5; \ + mov 4, %g6; \ + \ +save_trap_state_##type: \ + deccc %g6; \ + wrpr %g6, %tl; \ + rdpr %tpc, %g7; \ + stx %g7, [%g5]; \ + rdpr %tnpc, %g7; \ + stx %g7, [%g5 + 0x8]; \ + rdpr %tstate, %g7; \ + stx %g7, [%g5 + 0x10]; \ + rdpr %tt, %g7; \ + stx %g7, [%g5 + 0x18]; \ + bne save_trap_state_##type; \ + add %g5, 0x20, %g5; \ + \ + /* For 4 trap levels with 4 registers, memory required is \ + 4*8*4 = 0x80 bytes */ + +/* Save all state into context at %g1 */ +#define SAVE_CPU_STATE(type) \ + SAVE_CPU_WINDOW_STATE(type); \ + SAVE_CPU_TRAP_STATE(type); + + +#define RESTORE_CPU_WINDOW_STATE(type) \ + /* Restore window state from context at %g1 */ \ + \ + /* Get the number of windows in %g6 */ \ + rdpr %ver, %g6; \ + and %g6, 0xf, %g6; \ + inc %g6; \ + \ + /* Now iterate through all of the windows restoring all l and i registers */ \ + add %g1, 0x90, %g5; \ + \ +restore_cpu_window_##type: \ + deccc %g6; \ + wrpr %g6, %cwp; \ + ldx [%g5], %l0; \ + ldx [%g5 + 0x8], %l1; \ + ldx [%g5 + 0x10], %l2; \ + ldx [%g5 + 0x18], %l3; \ + ldx [%g5 + 0x20], %l4; \ + ldx [%g5 + 0x28], %l5; \ + ldx [%g5 + 0x30], %l6; \ + ldx [%g5 + 0x38], %l7; \ + ldx [%g5 + 0x40], %i0; \ + ldx [%g5 + 0x48], %i1; \ + ldx [%g5 + 0x50], %i2; \ + ldx [%g5 + 0x58], %i3; \ + ldx [%g5 + 0x60], %i4; \ + ldx [%g5 + 0x68], %i5; \ + ldx [%g5 + 0x70], %i6; \ + ldx [%g5 + 0x78], %i7; \ + bne restore_cpu_window_##type; \ + add %g5, 0x80, %g5; \ + \ + /* Restore the window registers to their original value */ \ + ldx [%g1], %g7; \ + wrpr %g7, %cwp; \ + ldx [%g1 + 0x8], %g7; \ + wrpr %g7, %cansave; \ + ldx [%g1 + 0x10], %g7; \ + wrpr %g7, %canrestore; \ + ldx [%g1 + 0x18], %g7; \ + wrpr %g7, %otherwin; \ + ldx [%g1 + 0x20], %g7; \ + wrpr %g7, %wstate; \ + ldx [%g1 + 0x28], %g7; \ + wrpr %g7, %cleanwin; \ + \ + ldx [%g1 + 0x30], %o0; \ + ldx [%g1 + 0x38], %o1; \ + ldx [%g1 + 0x40], %o2; \ + ldx [%g1 + 0x48], %o3; \ + ldx [%g1 + 0x50], %o4; \ + ldx [%g1 + 0x58], %o5; \ + ldx [%g1 + 0x60], %o6; \ + ldx [%g1 + 0x68], %o7; \ + \ + ldx [%g1 + 0x70], %g7; \ + wrpr %g7, %pstate; \ + ldx [%g1 + 0x78], %g7; \ + wr %g7, 0, %y; \ + ldx [%g1 + 0x80], %g7; \ + wr %g7, 0, %fprs; \ + + +#define RESTORE_CPU_TRAP_STATE(type) \ + /* Restore trap state from context at %g1 */ \ + add %g1, 0x490, %g5; \ + mov 4, %g6; \ + \ +restore_trap_state_##type: \ + deccc %g6; \ + wrpr %g6, %tl; \ + ldx [%g5], %g7; \ + wrpr %g7, %tpc; \ + ldx [%g5 + 0x8], %g7; \ + wrpr %g7, %tnpc; \ + ldx [%g5 + 0x10], %g7; \ + wrpr %g7, %tstate; \ + ldx [%g5 + 0x18], %g7; \ + wrpr %g7, %tt; \ + bne restore_trap_state_##type; \ + add %g5, 0x20, %g5; \ + \ + ldx [%g1 + 0x88], %g7; \ + wrpr %g7, %tl + +/* Restore all state from context at %g1 */ +#define RESTORE_CPU_STATE(type) \ + RESTORE_CPU_WINDOW_STATE(type); \ + RESTORE_CPU_TRAP_STATE(type); diff --git a/openbios-devel/arch/sparc64/vectors.S b/openbios-devel/arch/sparc64/vectors.S index f489f35..9d86b6b 100644 --- a/openbios-devel/arch/sparc64/vectors.S +++ b/openbios-devel/arch/sparc64/vectors.S @@ -24,6 +24,7 @@ */
#define __ASSEMBLY__ +#include "cpustate.h" #include "pstate.h" #include <asm/asi.h> #define ASI_BP ASI_PHYS_BYPASS_EC_E @@ -327,206 +328,6 @@ fill_32bit: restored retry
-/* - * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch - * to C to occur within the MMU I/D TLB miss handlers. - * - * Because these handlers are called on a TLB miss, we cannot use flushw to store - * processor window state on the stack, as the memory areas used by each window's - * stack pointer may not be in the TLB, causing recursive TLB miss traps. - * - * For this reason, we save window state by manually rotating the window registers - * and saving their contents (along with other vital registers) into a special - * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and - * so won't cause issues with trap recursion. - * - * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow - * window fill/spill traps if required), switch to our safe tlb_handler_stack and - * invoke the miss handler. - */ - -#define SAVE_CPU_STATE(type) \ - /* First save the various state registers */ \ - rdpr %cwp, %g7; \ - stx %g7, [%g1]; \ - rdpr %cansave, %g7; \ - stx %g7, [%g1 + 0x8]; \ - rdpr %canrestore, %g7; \ - stx %g7, [%g1 + 0x10]; \ - rdpr %otherwin, %g7; \ - stx %g7, [%g1 + 0x18]; \ - rdpr %wstate, %g7; \ - stx %g7, [%g1 + 0x20]; \ - rdpr %cleanwin, %g7; \ - stx %g7, [%g1 + 0x28]; \ - rdpr %pstate, %g7; \ - stx %g7, [%g1 + 0x30]; \ - \ - rd %y, %g7; \ - stx %g7, [%g1 + 0x38]; \ - rd %fprs, %g7; \ - stx %g7, [%g1 + 0x40]; \ - \ - rdpr %tl, %g7; \ - stx %g7, [%g1 + 0x48]; \ - \ - /* Trap state */ \ - add %g1, 0x50, %g5; \ - mov 4, %g6; \ - \ -save_trap_state_##type: \ - deccc %g6; \ - wrpr %g6, %tl; \ - rdpr %tpc, %g7; \ - stx %g7, [%g5]; \ - rdpr %tnpc, %g7; \ - stx %g7, [%g5 + 0x8]; \ - rdpr %tstate, %g7; \ - stx %g7, [%g5 + 0x10]; \ - rdpr %tt, %g7; \ - stx %g7, [%g5 + 0x18]; \ - bne save_trap_state_##type; \ - add %g5, 0x20, %g5; \ - \ - /* For 4 trap levels with 4 registers, memory required is - 4*8*4 = 0x80 bytes */ \ - \ - /* Save the o registers */ \ - stx %o0, [%g1 + 0xd0]; \ - stx %o1, [%g1 + 0xd8]; \ - stx %o2, [%g1 + 0xe0]; \ - stx %o3, [%g1 + 0xe8]; \ - stx %o4, [%g1 + 0xf0]; \ - stx %o5, [%g1 + 0xf8]; \ - stx %o6, [%g1 + 0x100]; \ - stx %o7, [%g1 + 0x108]; \ - \ - /* Now iterate through all of the windows saving all l and i registers */ \ - add %g1, 0x110, %g5; \ - \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ -save_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - stx %l0, [%g5]; \ - stx %l1, [%g5 + 0x8]; \ - stx %l2, [%g5 + 0x10]; \ - stx %l3, [%g5 + 0x18]; \ - stx %l4, [%g5 + 0x20]; \ - stx %l5, [%g5 + 0x28]; \ - stx %l6, [%g5 + 0x30]; \ - stx %l7, [%g5 + 0x38]; \ - stx %i0, [%g5 + 0x40]; \ - stx %i1, [%g5 + 0x48]; \ - stx %i2, [%g5 + 0x50]; \ - stx %i3, [%g5 + 0x58]; \ - stx %i4, [%g5 + 0x60]; \ - stx %i5, [%g5 + 0x68]; \ - stx %i6, [%g5 + 0x70]; \ - stx %i7, [%g5 + 0x78]; \ - bne save_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* For 8 windows with 16 registers to save in the window, memory required - is 16*8*8 = 0x400 bytes */ \ - \ - /* Now we should be in window 0 so update the other window registers */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - dec %g6; \ - wrpr %g6, %cansave; \ - \ - wrpr %g0, %cleanwin; \ - wrpr %g0, %canrestore; \ - wrpr %g0, %otherwin - - -#define RESTORE_CPU_STATE(type) \ - /* Get the number of windows in %g6 */ \ - rdpr %ver, %g6; \ - and %g6, 0xf, %g6; \ - inc %g6; \ - \ - /* Now iterate through all of the windows restoring all l and i registers */ \ - add %g1, 0x110, %g5; \ - \ -restore_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ - ldx [%g5], %l0; \ - ldx [%g5 + 0x8], %l1; \ - ldx [%g5 + 0x10], %l2; \ - ldx [%g5 + 0x18], %l3; \ - ldx [%g5 + 0x20], %l4; \ - ldx [%g5 + 0x28], %l5; \ - ldx [%g5 + 0x30], %l6; \ - ldx [%g5 + 0x38], %l7; \ - ldx [%g5 + 0x40], %i0; \ - ldx [%g5 + 0x48], %i1; \ - ldx [%g5 + 0x50], %i2; \ - ldx [%g5 + 0x58], %i3; \ - ldx [%g5 + 0x60], %i4; \ - ldx [%g5 + 0x68], %i5; \ - ldx [%g5 + 0x70], %i6; \ - ldx [%g5 + 0x78], %i7; \ - bne restore_cpu_window_##type; \ - add %g5, 0x80, %g5; \ - \ - /* Restore the window registers to their original value */ \ - ldx [%g1], %g7; \ - wrpr %g7, %cwp; \ - ldx [%g1 + 0x8], %g7; \ - wrpr %g7, %cansave; \ - ldx [%g1 + 0x10], %g7; \ - wrpr %g7, %canrestore; \ - ldx [%g1 + 0x18], %g7; \ - wrpr %g7, %otherwin; \ - ldx [%g1 + 0x20], %g7; \ - wrpr %g7, %wstate; \ - ldx [%g1 + 0x28], %g7; \ - wrpr %g7, %cleanwin; \ - ldx [%g1 + 0x30], %g7; \ - wrpr %g7, %pstate; \ - \ - /* Restore the o registers */ \ - ldx [%g1 + 0xd0], %o0; \ - ldx [%g1 + 0xd8], %o1; \ - ldx [%g1 + 0xe0], %o2; \ - ldx [%g1 + 0xe8], %o3; \ - ldx [%g1 + 0xf0], %o4; \ - ldx [%g1 + 0xf8], %o5; \ - ldx [%g1 + 0x100], %o6; \ - ldx [%g1 + 0x108], %o7; \ - \ - /* Restore the trap state */ \ - add %g1, 0x50, %g5; \ - mov 4, %g6; \ - \ -restore_trap_state_##type: \ - deccc %g6; \ - wrpr %g6, %tl; \ - ldx [%g5], %g7; \ - wrpr %g7, %tpc; \ - ldx [%g5 + 0x8], %g7; \ - wrpr %g7, %tnpc; \ - ldx [%g5 + 0x10], %g7; \ - wrpr %g7, %tstate; \ - ldx [%g5 + 0x18], %g7; \ - wrpr %g7, %tt; \ - bne restore_trap_state_##type; \ - add %g5, 0x20, %g5; \ - \ - ldx [%g1 + 0x38], %g7; \ - wr %g7, 0, %y; \ - ldx [%g1 + 0x40], %g7; \ - wr %g7, 0, %fprs; \ - ldx [%g1 + 0x48], %g7; \ - wrpr %g7, %tl -
.globl reload_DMMU_tlb, reload_IMMU_tlb, bug
@@ -535,7 +336,7 @@ reload_DMMU_tlb: /* Save CPU state to stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - add %g1, -0x510, %g1 + add %g1, -CONTEXT_STATE_SIZE, %g1 stx %g1, [%g7] SAVE_CPU_STATE(dtlb) @@ -544,7 +345,7 @@ reload_DMMU_tlb: gcc to save its arguments when building with -O0) */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g6 - setx 0x2000, %g4, %g5 + setx CONTEXT_STACK_SIZE, %g4, %g5 sub %g6, %g5, %g6 stx %g6, [%g7] @@ -568,7 +369,7 @@ reload_DMMU_tlb: /* Restore CPU state from stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - setx 0x2000, %g4, %g5 + setx CONTEXT_STACK_SIZE, %g4, %g5 add %g1, %g5, %g1 stx %g1, [%g7] @@ -576,7 +377,7 @@ reload_DMMU_tlb: setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - add %g1, 0x510, %g1 + add %g1, CONTEXT_STATE_SIZE, %g1 stx %g1, [%g7] retry @@ -586,7 +387,7 @@ reload_IMMU_tlb: /* Save CPU state to stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - add %g1, -0x510, %g1 + add %g1, -CONTEXT_STATE_SIZE, %g1 stx %g1, [%g7] SAVE_CPU_STATE(itlb) @@ -595,7 +396,7 @@ reload_IMMU_tlb: gcc to save its arguments when building with -O0) */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g6 - setx 0x2000, %g4, %g5 + setx CONTEXT_STACK_SIZE, %g4, %g5 sub %g6, %g5, %g6 stx %g6, [%g7] @@ -619,7 +420,7 @@ reload_IMMU_tlb: /* Restore CPU state from stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - setx 0x2000, %g4, %g5 + setx CONTEXT_STACK_SIZE, %g4, %g5 add %g1, %g5, %g1 stx %g1, [%g7] @@ -627,7 +428,7 @@ reload_IMMU_tlb: setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g1 - add %g1, 0x510, %g1 + add %g1, CONTEXT_STATE_SIZE, %g1 stx %g1, [%g7]
retry
Instead of storing the windows in numerical order, store them starting from %cwp. This means the current window can be located at a fixed point in the state, rather than calculating the offset based upon %cwp.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/sparc64/cpustate.h | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/openbios-devel/arch/sparc64/cpustate.h b/openbios-devel/arch/sparc64/cpustate.h index 35ca712..0c276bf 100644 --- a/openbios-devel/arch/sparc64/cpustate.h +++ b/openbios-devel/arch/sparc64/cpustate.h @@ -72,11 +72,15 @@ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ - inc %g6; \ + \ + mov %g6, %g4; \ + inc %g4; \ + \ + /* Starting cwp in g7 */ \ + rdpr %cwp, %g7; \ \ save_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ + wrpr %g7, %cwp; \ stx %l0, [%g5]; \ stx %l1, [%g5 + 0x8]; \ stx %l2, [%g5 + 0x10]; \ @@ -93,6 +97,9 @@ save_cpu_window_##type: \ stx %i5, [%g5 + 0x68]; \ stx %i6, [%g5 + 0x70]; \ stx %i7, [%g5 + 0x78]; \ + dec %g7; \ + and %g7, %g6, %g7; \ + subcc %g4, 1, %g4; \ bne save_cpu_window_##type; \ add %g5, 0x80, %g5; \ \ @@ -144,14 +151,18 @@ save_trap_state_##type: \ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ - inc %g6; \ + \ + mov %g6, %g4; \ + inc %g4; \ + \ + /* Set starting window */ \ + ldx [%g1], %g7; \ \ /* Now iterate through all of the windows restoring all l and i registers */ \ add %g1, 0x90, %g5; \ \ restore_cpu_window_##type: \ - deccc %g6; \ - wrpr %g6, %cwp; \ + wrpr %g7, %cwp; \ ldx [%g5], %l0; \ ldx [%g5 + 0x8], %l1; \ ldx [%g5 + 0x10], %l2; \ @@ -168,6 +179,9 @@ restore_cpu_window_##type: \ ldx [%g5 + 0x68], %i5; \ ldx [%g5 + 0x70], %i6; \ ldx [%g5 + 0x78], %i7; \ + dec %g7; \ + and %g7, %g6, %g7; \ + subcc %g4, 1, %g4; \ bne restore_cpu_window_##type; \ add %g5, 0x80, %g5; \ \
On 22/11/15 18:38, Mark Cave-Ayland wrote:
This patchset is aimed at unifying the code used to preserve CPU context when switching from client programs into Forth, via either the CIF or interrupt handlers.
It is part of a longer process to enable access to saved CPU context state from within Forth which will eventually enable proper implementation of the init-program and go words.
Given that there was no negative feedback and there are no regressions in my test images, I've applied this to SVN trunk as I have further work based upon these patches.
ATB,
Mark.