This patchset improves the context handling in 2 ways: firstly it unifies the context structures between switch_to() and CIF entry, and secondly fixes up the context switch code enough so that we can switch and return from an arbitrary PC address in testing.
This is a precursor to fixing up the load/init-program logic so that clients are able to access and alter their own context from Forth.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
v2: - Make sure trap level is preserved after SAVE_CPU_TRAP_STATE - Add separate RESET_CPU_WINDOW_STATE macro - Ensure that __context points to the saved entry state during CIF calls
Mark Cave-Ayland (11): SPARC64: add parameter to indicate %cwp save/restore direction SPARC64: allocate space in context to save global registers SPARC64: save/restore global registers to context when entering CIF SPARC64: save CIF entry globals under the client stack SPARC64: introduce %pc into context and use it when exiting CIF SPARC64: make sure that %tl is restored after SAVE_CPU_TRAP_STATE SPARC64: save/restore entire CPU state when entering/leaving CIF SPARC64: split off CPU window reset logic into RESET_CPU_WINDOW_STATE macro SPARC64: split off general CPU registers into *_GENERAL_STATE macros SPARC64: point __context to saved context during CIF calls SPARC64: switch entry.S over to use existing context macros
arch/sparc64/call-client.S | 94 ++++++++++++++++++++++---------- arch/sparc64/context.c | 6 +-- arch/sparc64/context.h | 7 +-- arch/sparc64/cpustate.h | 115 ++++++++++++++++++++++++--------------- arch/sparc64/entry.S | 17 +++++- arch/sparc64/switch.S | 129 ++++++++++++++++---------------------------- arch/sparc64/vectors.S | 8 ++- 7 files changed, 213 insertions(+), 163 deletions(-)
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/cpustate.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/arch/sparc64/cpustate.h b/arch/sparc64/cpustate.h index 0c276bf..d83d062 100644 --- a/arch/sparc64/cpustate.h +++ b/arch/sparc64/cpustate.h @@ -9,12 +9,22 @@ * */
+#include "autoconf.h" + /* 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
+/* %cwp save/restore direction */ +#if defined(CONFIG_QEMU) + /* QEMU SPARCv9 %cwp save/restore direction is reversed compared to real hardware */ + #define CWP_DIRECTION -1 +#else + #define CWP_DIRECTION 1 +#endif + /* * 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. @@ -97,7 +107,7 @@ save_cpu_window_##type: \ stx %i5, [%g5 + 0x68]; \ stx %i6, [%g5 + 0x70]; \ stx %i7, [%g5 + 0x78]; \ - dec %g7; \ + add %g7, CWP_DIRECTION, %g7; \ and %g7, %g6, %g7; \ subcc %g4, 1, %g4; \ bne save_cpu_window_##type; \ @@ -179,7 +189,7 @@ restore_cpu_window_##type: \ ldx [%g5 + 0x68], %i5; \ ldx [%g5 + 0x70], %i6; \ ldx [%g5 + 0x78], %i7; \ - dec %g7; \ + add %g7, CWP_DIRECTION, %g7; \ and %g7, %g6, %g7; \ subcc %g4, 1, %g4; \ bne restore_cpu_window_##type; \
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 4 +-- arch/sparc64/cpustate.h | 62 +++++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index a8c0348..ee0f865 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -76,7 +76,7 @@ sparc64_of_client_interface:
/* Call client inteface */ call of_client_interface - ldx [%g1 + 0x30], %o0 + ldx [%g1 + 0x70], %o0
/* Restore windows */ setx _fcstack_ptr, %g6, %g7 @@ -86,7 +86,7 @@ sparc64_of_client_interface: stx %g1, [%g7] /* Return value */ - stx %o0, [%g1 + 0x30] + stx %o0, [%g1 + 0x70] RESTORE_CPU_WINDOW_STATE(cif) diff --git a/arch/sparc64/cpustate.h b/arch/sparc64/cpustate.h index d83d062..8ea45c4 100644 --- a/arch/sparc64/cpustate.h +++ b/arch/sparc64/cpustate.h @@ -12,7 +12,7 @@ #include "autoconf.h"
/* State size for context (see below) */ -#define CONTEXT_STATE_SIZE 0x510 +#define CONTEXT_STATE_SIZE 0x550
/* Stack size for context (allocated inline of the context stack) */ #define CONTEXT_STACK_SIZE 0x2000 @@ -58,26 +58,28 @@ 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]; \ + /* %g1-%g7 stored at 0x30 - 0x68 */ \ + \ + stx %o0, [%g1 + 0x70]; \ + stx %o1, [%g1 + 0x78]; \ + stx %o2, [%g1 + 0x80]; \ + stx %o3, [%g1 + 0x88]; \ + stx %o4, [%g1 + 0x90]; \ + stx %o5, [%g1 + 0x98]; \ + stx %o6, [%g1 + 0xa0]; \ + stx %o7, [%g1 + 0xa8]; \ \ rdpr %pstate, %g7; \ - stx %g7, [%g1 + 0x70]; \ + stx %g7, [%g1 + 0xb0]; \ rd %y, %g7; \ - stx %g7, [%g1 + 0x78]; \ + stx %g7, [%g1 + 0xb8]; \ rd %fprs, %g7; \ - stx %g7, [%g1 + 0x80]; \ + stx %g7, [%g1 + 0xc0]; \ rdpr %tl, %g7; \ - stx %g7, [%g1 + 0x88]; \ + stx %g7, [%g1 + 0xc8]; \ \ /* Now iterate through all of the windows saving all l and i registers */ \ - add %g1, 0x90, %g5; \ + add %g1, 0xd0, %g5; \ \ /* Get the number of windows in %g6 */ \ rdpr %ver, %g6; \ @@ -129,7 +131,7 @@ save_cpu_window_##type: \ #define SAVE_CPU_TRAP_STATE(type) \ /* Save trap state into context at %g1 */ \ - add %g1, 0x490, %g5; \ + add %g1, 0x4d0, %g5; \ mov 4, %g6; \ \ save_trap_state_##type: \ @@ -169,7 +171,7 @@ save_trap_state_##type: \ ldx [%g1], %g7; \ \ /* Now iterate through all of the windows restoring all l and i registers */ \ - add %g1, 0x90, %g5; \ + add %g1, 0xd0, %g5; \ \ restore_cpu_window_##type: \ wrpr %g7, %cwp; \ @@ -209,26 +211,28 @@ restore_cpu_window_##type: \ 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; \ + /* %g1-%g7 stored at 0x30 - 0x68 */ \ + \ + ldx [%g1 + 0x70], %o0; \ + ldx [%g1 + 0x78], %o1; \ + ldx [%g1 + 0x80], %o2; \ + ldx [%g1 + 0x88], %o3; \ + ldx [%g1 + 0x90], %o4; \ + ldx [%g1 + 0x98], %o5; \ + ldx [%g1 + 0xa0], %o6; \ + ldx [%g1 + 0xa8], %o7; \ \ - ldx [%g1 + 0x70], %g7; \ + ldx [%g1 + 0xb0], %g7; \ wrpr %g7, %pstate; \ - ldx [%g1 + 0x78], %g7; \ + ldx [%g1 + 0xb8], %g7; \ wr %g7, 0, %y; \ - ldx [%g1 + 0x80], %g7; \ + ldx [%g1 + 0xc0], %g7; \ wr %g7, 0, %fprs; \
#define RESTORE_CPU_TRAP_STATE(type) \ /* Restore trap state from context at %g1 */ \ - add %g1, 0x490, %g5; \ + add %g1, 0x4d0, %g5; \ mov 4, %g6; \ \ restore_trap_state_##type: \ @@ -245,7 +249,7 @@ restore_trap_state_##type: \ bne restore_trap_state_##type; \ add %g5, 0x20, %g5; \ \ - ldx [%g1 + 0x88], %g7; \ + ldx [%g1 + 0xc8], %g7; \ wrpr %g7, %tl
/* Restore all state from context at %g1 */
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index ee0f865..a0c2fae 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -61,6 +61,22 @@ sparc64_of_client_interface: add %g1, -CONTEXT_STATE_SIZE, %g1 stx %g1, [%g7] + /* Save globals */ + ldx [%sp + 2047 + 192], %g7 + stx %g7, [%g1 + 0x30] + ldx [%sp + 2047 + 200], %g7 + stx %g7, [%g1 + 0x38] + ldx [%sp + 2047 + 208], %g7 + stx %g7, [%g1 + 0x40] + ldx [%sp + 2047 + 216], %g7 + stx %g7, [%g1 + 0x48] + ldx [%sp + 2047 + 224], %g7 + stx %g7, [%g1 + 0x50] + ldx [%sp + 2047 + 232], %g7 + stx %g7, [%g1 + 0x58] + ldx [%sp + 2047 + 240], %g7 + stx %g7, [%g1 + 0x60] + SAVE_CPU_WINDOW_STATE(cif)
/* Move to OpenBIOS context stack */ @@ -90,9 +106,9 @@ sparc64_of_client_interface: RESTORE_CPU_WINDOW_STATE(cif) - add %g1, CONTEXT_STATE_SIZE, %g1 + add %g1, CONTEXT_STATE_SIZE, %g5 setx _fcstack_ptr, %g6, %g7 - stx %g1, [%g7] + stx %g5, [%g7] /* Restore stack */ setx client_stack, %g6, %g7 @@ -104,13 +120,13 @@ sparc64_of_client_interface: wrpr %g6, %tba
/* Restore globals */ - 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 + ldx [%g1 + 0x38], %g2 + ldx [%g1 + 0x40], %g3 + ldx [%g1 + 0x48], %g4 + ldx [%g1 + 0x50], %g5 + ldx [%g1 + 0x58], %g6 + ldx [%g1 + 0x60], %g7 + ldx [%g1 + 0x30], %g1
add %sp, 248, %sp
Since we switch to a separate stack when entering the CIF, store the globals at known offsets beneath it. This saves having to alter the stack pointer during CIF entry.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index a0c2fae..a4f8104 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -36,15 +36,13 @@ client_window: sparc64_of_client_interface:
/* Save globals on callers stack */ - add %sp, -248, %sp - - 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] + stx %g1, [%sp + 2047 - 248 + 192] + stx %g2, [%sp + 2047 - 248 + 200] + stx %g3, [%sp + 2047 - 248 + 208] + stx %g4, [%sp + 2047 - 248 + 216] + stx %g5, [%sp + 2047 - 248 + 224] + stx %g6, [%sp + 2047 - 248 + 232] + stx %g7, [%sp + 2047 - 248 + 240]
/* Save client trap table */ setx client_tba, %g6, %g7 @@ -62,19 +60,19 @@ sparc64_of_client_interface: stx %g1, [%g7] /* Save globals */ - ldx [%sp + 2047 + 192], %g7 + ldx [%sp + 2047 - 248 + 192], %g7 stx %g7, [%g1 + 0x30] - ldx [%sp + 2047 + 200], %g7 + ldx [%sp + 2047 - 248 + 200], %g7 stx %g7, [%g1 + 0x38] - ldx [%sp + 2047 + 208], %g7 + ldx [%sp + 2047 - 248 + 208], %g7 stx %g7, [%g1 + 0x40] - ldx [%sp + 2047 + 216], %g7 + ldx [%sp + 2047 - 248 + 216], %g7 stx %g7, [%g1 + 0x48] - ldx [%sp + 2047 + 224], %g7 + ldx [%sp + 2047 - 248 + 224], %g7 stx %g7, [%g1 + 0x50] - ldx [%sp + 2047 + 232], %g7 + ldx [%sp + 2047 - 248 + 232], %g7 stx %g7, [%g1 + 0x58] - ldx [%sp + 2047 + 240], %g7 + ldx [%sp + 2047 - 248 + 240], %g7 stx %g7, [%g1 + 0x60] SAVE_CPU_WINDOW_STATE(cif) @@ -128,7 +126,5 @@ sparc64_of_client_interface: ldx [%g1 + 0x60], %g7 ldx [%g1 + 0x30], %g1
- add %sp, 248, %sp - jmp %o7+8 nop
This is because some loaders expect to be able to resume execution at an alternative location by altering %pc from within Forth.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 19 +++++++++++++------ arch/sparc64/cpustate.h | 4 ++-- 2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index a4f8104..9489aa6 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -75,6 +75,11 @@ sparc64_of_client_interface: ldx [%sp + 2047 - 248 + 240], %g7 stx %g7, [%g1 + 0x60] + /* Save %pc */ + mov %o7, %g7 + add %g7, 8, %g7 + stx %g7, [%g1 + 0x4d0] + SAVE_CPU_WINDOW_STATE(cif)
/* Move to OpenBIOS context stack */ @@ -116,15 +121,17 @@ sparc64_of_client_interface: setx client_tba, %g6, %g7 ldx [%g7], %g6 wrpr %g6, %tba - + + /* Restore %pc */ + ldx [%g1 + 0x4d0], %o7 + /* Restore globals */ ldx [%g1 + 0x38], %g2 ldx [%g1 + 0x40], %g3 ldx [%g1 + 0x48], %g4 ldx [%g1 + 0x50], %g5 ldx [%g1 + 0x58], %g6 - ldx [%g1 + 0x60], %g7 - ldx [%g1 + 0x30], %g1 - - jmp %o7+8 - nop + ldx [%g1 + 0x60], %g7 + + jmp %o7 + ldx [%g1 + 0x30], %g1 diff --git a/arch/sparc64/cpustate.h b/arch/sparc64/cpustate.h index 8ea45c4..a0e838a 100644 --- a/arch/sparc64/cpustate.h +++ b/arch/sparc64/cpustate.h @@ -131,7 +131,7 @@ save_cpu_window_##type: \ #define SAVE_CPU_TRAP_STATE(type) \ /* Save trap state into context at %g1 */ \ - add %g1, 0x4d0, %g5; \ + add %g1, 0x4e0, %g5; \ mov 4, %g6; \ \ save_trap_state_##type: \ @@ -232,7 +232,7 @@ restore_cpu_window_##type: \
#define RESTORE_CPU_TRAP_STATE(type) \ /* Restore trap state from context at %g1 */ \ - add %g1, 0x4d0, %g5; \ + add %g1, 0x4e0, %g5; \ mov 4, %g6; \ \ restore_trap_state_##type: \
Otherwise we end up in the wrong trap level after saving the CPU state.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/cpustate.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/arch/sparc64/cpustate.h b/arch/sparc64/cpustate.h index a0e838a..1f6c1a0 100644 --- a/arch/sparc64/cpustate.h +++ b/arch/sparc64/cpustate.h @@ -126,14 +126,16 @@ save_cpu_window_##type: \ \ wrpr %g0, %cleanwin; \ wrpr %g0, %canrestore; \ - wrpr %g0, %otherwin; \ + wrpr %g0, %otherwin;
- #define SAVE_CPU_TRAP_STATE(type) \ /* Save trap state into context at %g1 */ \ add %g1, 0x4e0, %g5; \ mov 4, %g6; \ \ + /* Save current trap level */ \ + rdpr %tl, %g4; \ + \ save_trap_state_##type: \ deccc %g6; \ wrpr %g6, %tl; \ @@ -149,7 +151,10 @@ save_trap_state_##type: \ add %g5, 0x20, %g5; \ \ /* For 4 trap levels with 4 registers, memory required is \ - 4*8*4 = 0x80 bytes */ + 4*8*4 = 0x80 bytes */ \ + \ + /* Switch back to original trap level */ \ + wrpr %g4, %tl;
/* Save all state into context at %g1 */ #define SAVE_CPU_STATE(type) \
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index 9489aa6..82657c6 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -80,7 +80,7 @@ sparc64_of_client_interface: add %g7, 8, %g7 stx %g7, [%g1 + 0x4d0] - SAVE_CPU_WINDOW_STATE(cif) + SAVE_CPU_STATE(cif)
/* Move to OpenBIOS context stack */ setx _fcstack_ptr, %g6, %g7 @@ -107,7 +107,7 @@ sparc64_of_client_interface: /* Return value */ stx %o0, [%g1 + 0x70] - RESTORE_CPU_WINDOW_STATE(cif) + RESTORE_CPU_STATE(cif) add %g1, CONTEXT_STATE_SIZE, %g5 setx _fcstack_ptr, %g6, %g7
Use the new macro in places where an empty register window set is required.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 4 +++- arch/sparc64/cpustate.h | 6 ++++-- arch/sparc64/vectors.S | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index 82657c6..5b5cae2 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -81,7 +81,9 @@ sparc64_of_client_interface: stx %g7, [%g1 + 0x4d0] SAVE_CPU_STATE(cif) - + + RESET_CPU_WINDOW_STATE(cif) + /* Move to OpenBIOS context stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g6 diff --git a/arch/sparc64/cpustate.h b/arch/sparc64/cpustate.h index 1f6c1a0..bb5823b 100644 --- a/arch/sparc64/cpustate.h +++ b/arch/sparc64/cpustate.h @@ -116,8 +116,10 @@ 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 */ \ - \ + is 16*8*8 = 0x400 bytes */ + +#define RESET_CPU_WINDOW_STATE(type) \ + wrpr %g0, %cwp; \ /* Now we should be in window 0 so update the other window registers */ \ rdpr %ver, %g6; \ and %g6, 0xf, %g6; \ diff --git a/arch/sparc64/vectors.S b/arch/sparc64/vectors.S index 9d86b6b..fa30546 100644 --- a/arch/sparc64/vectors.S +++ b/arch/sparc64/vectors.S @@ -340,7 +340,9 @@ reload_DMMU_tlb: stx %g1, [%g7] SAVE_CPU_STATE(dtlb) - + + RESET_CPU_WINDOW_STATE(dtlb) + /* 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 _fcstack_ptr, %g6, %g7 @@ -391,7 +393,9 @@ reload_IMMU_tlb: stx %g1, [%g7] SAVE_CPU_STATE(itlb) - + + RESET_CPU_WINDOW_STATE(itlb) + /* 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 _fcstack_ptr, %g6, %g7
A few of the CPU registers were included in the *_WINDOW_STATE macros. Split them out so that they can be used on their own without altering the window state.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/cpustate.h | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/arch/sparc64/cpustate.h b/arch/sparc64/cpustate.h index bb5823b..9358f85 100644 --- a/arch/sparc64/cpustate.h +++ b/arch/sparc64/cpustate.h @@ -43,6 +43,18 @@ * invoke the miss handler. */
+#define SAVE_CPU_GENERAL_STATE(type) \ + /* Save generate state into context at %g1 */ \ + rdpr %pstate, %g7; \ + stx %g7, [%g1 + 0xb0]; \ + rd %y, %g7; \ + stx %g7, [%g1 + 0xb8]; \ + rd %fprs, %g7; \ + stx %g7, [%g1 + 0xc0]; \ + rdpr %tl, %g7; \ + stx %g7, [%g1 + 0xc8]; + + #define SAVE_CPU_WINDOW_STATE(type) \ /* Save window state into context at %g1 */ \ rdpr %cwp, %g7; \ @@ -69,15 +81,6 @@ stx %o6, [%g1 + 0xa0]; \ stx %o7, [%g1 + 0xa8]; \ \ - rdpr %pstate, %g7; \ - stx %g7, [%g1 + 0xb0]; \ - rd %y, %g7; \ - stx %g7, [%g1 + 0xb8]; \ - rd %fprs, %g7; \ - stx %g7, [%g1 + 0xc0]; \ - rdpr %tl, %g7; \ - stx %g7, [%g1 + 0xc8]; \ - \ /* Now iterate through all of the windows saving all l and i registers */ \ add %g1, 0xd0, %g5; \ \ @@ -160,10 +163,21 @@ save_trap_state_##type: \
/* Save all state into context at %g1 */ #define SAVE_CPU_STATE(type) \ + SAVE_CPU_GENERAL_STATE(type); \ SAVE_CPU_WINDOW_STATE(type); \ SAVE_CPU_TRAP_STATE(type);
+#define RESTORE_CPU_GENERAL_STATE(type) \ + /* Restore general state from context at %g1 */ \ + ldx [%g1 + 0xb0], %g7; \ + wrpr %g7, %pstate; \ + ldx [%g1 + 0xb8], %g7; \ + wr %g7, 0, %y; \ + ldx [%g1 + 0xc0], %g7; \ + wr %g7, 0, %fprs; + + #define RESTORE_CPU_WINDOW_STATE(type) \ /* Restore window state from context at %g1 */ \ \ @@ -227,14 +241,7 @@ restore_cpu_window_##type: \ ldx [%g1 + 0x90], %o4; \ ldx [%g1 + 0x98], %o5; \ ldx [%g1 + 0xa0], %o6; \ - ldx [%g1 + 0xa8], %o7; \ - \ - ldx [%g1 + 0xb0], %g7; \ - wrpr %g7, %pstate; \ - ldx [%g1 + 0xb8], %g7; \ - wr %g7, 0, %y; \ - ldx [%g1 + 0xc0], %g7; \ - wr %g7, 0, %fprs; \ + ldx [%g1 + 0xa8], %o7;
#define RESTORE_CPU_TRAP_STATE(type) \ @@ -261,5 +268,6 @@ restore_trap_state_##type: \
/* Restore all state from context at %g1 */ #define RESTORE_CPU_STATE(type) \ + RESTORE_CPU_GENERAL_STATE(type); \ RESTORE_CPU_WINDOW_STATE(type); \ RESTORE_CPU_TRAP_STATE(type);
This will enable Forth executed in CIF calls to be able to modify its own context and return.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/call-client.S | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/arch/sparc64/call-client.S b/arch/sparc64/call-client.S index 5b5cae2..ebab6b9 100644 --- a/arch/sparc64/call-client.S +++ b/arch/sparc64/call-client.S @@ -14,6 +14,8 @@ .data .align 8
+client_context: + .xword 0 client_stack: .xword 0 client_tba: @@ -84,6 +86,13 @@ sparc64_of_client_interface: RESET_CPU_WINDOW_STATE(cif) + /* Update __context to point to saved area */ + setx __context, %g6, %g7 + ldx [%g7], %g3 + setx client_context, %g4, %g5 + stx %g3, [%g5] + stx %g1, [%g7] + /* Move to OpenBIOS context stack */ setx _fcstack_ptr, %g6, %g7 ldx [%g7], %g6 @@ -109,6 +118,12 @@ sparc64_of_client_interface: /* Return value */ stx %o0, [%g1 + 0x70] + /* Restore __context */ + setx client_context, %g4, %g5 + ldx [%g5], %g3 + setx __context, %g6, %g7 + stx %g3, [%g7] + RESTORE_CPU_STATE(cif) add %g1, CONTEXT_STATE_SIZE, %g5
This also requires aligning the CPU context struct as defined in cpustate.h.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/context.c | 6 +-- arch/sparc64/context.h | 7 +-- arch/sparc64/entry.S | 17 ++++++- arch/sparc64/switch.S | 129 ++++++++++++++++++------------------------------ 4 files changed, 70 insertions(+), 89 deletions(-)
diff --git a/arch/sparc64/context.c b/arch/sparc64/context.c index 823116f..5ab0045 100644 --- a/arch/sparc64/context.c +++ b/arch/sparc64/context.c @@ -24,7 +24,6 @@ void __exit_context(void); /* assembly routine */ * to start us up. */ static struct context main_ctx = { - .regs[REG_SP] = (uint64_t) &_estack - STACK_BIAS - 96, .pc = (uint64_t) start_main, .npc = (uint64_t) start_main + 4, .return_addr = (uint64_t) __exit_context, @@ -76,7 +75,8 @@ init_context(uint8_t *stack, uint64_t stack_size, int num_params)
ctx = (struct context *) (stack_top - ALIGN_SIZE(sizeof(*ctx) + num_params*sizeof(uint64_t), sizeof(uint64_t))); - memset(ctx, 0, sizeof(*ctx)); + /* Use valid window state from startup */ + memcpy(ctx, &main_ctx, sizeof(struct context));
/* Fill in reasonable default for flat memory model */ ctx->regs[REG_SP] = virt_to_phys(stack_top - STACK_BIAS - 192); @@ -95,7 +95,7 @@ struct context *switch_to(struct context *ctx) save = __context; __context = ctx; //asm ("pushl %cs; call __switch_context"); - asm ("call __switch_context_nosave; nop"); + asm ("call __switch_context; nop"); ret = __context; __context = (struct context *)save; return ret; diff --git a/arch/sparc64/context.h b/arch/sparc64/context.h index 2756fa1..a047b9c 100644 --- a/arch/sparc64/context.h +++ b/arch/sparc64/context.h @@ -5,12 +5,13 @@
struct context { /* General registers */ - uint64_t regs[32]; + uint64_t regs[154]; uint64_t pc; uint64_t npc; -#define REG_O0 8 -#define REG_SP 14 +#define REG_O0 14 +#define REG_SP 20 #define SP_LOC(ctx) (&(ctx)->regs[REG_SP]) + uint64_t tregs[20]; /* Flags */ /* Optional stack contents */ uint64_t return_addr; diff --git a/arch/sparc64/entry.S b/arch/sparc64/entry.S index d03128a..3a46d89 100644 --- a/arch/sparc64/entry.S +++ b/arch/sparc64/entry.S @@ -11,6 +11,7 @@ #include <asm/asi.h> #include "pstate.h" #include "lsu.h" +#include "cpustate.h" #define NO_QEMU_PROTOS #define NO_OPENBIOS_PROTOS #include "arch/common/fw_cfg.h" @@ -264,6 +265,20 @@ lowmem: /* Finally, turn on traps so that we can call c-code. */ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+ /* Set up a default context */ + setx __context, %g2, %g1 + ldx [%g1], %g1 + + SAVE_CPU_GENERAL_STATE(entry) + SAVE_CPU_WINDOW_STATE(entry) + + /* Set up local stack pointer */ + setx _estack - 2047, %o2, %sp + + /* And for the main context */ + add %sp, - 192 - 0x500, %g2 + stx %g2, [%g1 + 0xa0] + ! 100 Hz timer setx TICK_INT_DIS, %g2, %g1 rd %tick, %g2 @@ -276,7 +291,7 @@ lowmem: * Main context is statically defined in C. */
- call __switch_context_nosave + call __switch_context nop
/* We get here when the main context switches back to diff --git a/arch/sparc64/switch.S b/arch/sparc64/switch.S index d2cc7be..e6c63f0 100644 --- a/arch/sparc64/switch.S +++ b/arch/sparc64/switch.S @@ -1,5 +1,6 @@ #include "pstate.h" #include <asm/asi.h> +#include "cpustate.h" #define ASI_BP ASI_M_BYPASS #define REGWIN_SZ 0x40
@@ -22,47 +23,36 @@ * this routine to get back to the original context. */
-/* XXX: totally bogus for sparc, need to save and restore all windows */ __switch_context: - /* make sure caller's windows are on caller's stack */ flushw;
/* Save everything in current stack */ - - setx __context, %g2, %g1 - stx %g3, [%g1 + 24] - stx %g4, [%g1 + 32] - stx %g5, [%g1 + 40] - stx %g6, [%g1 + 48] - stx %g7, [%g1 + 56] - - stx %o0, [%g1 + 64] - stx %o1, [%g1 + 72] - stx %o2, [%g1 + 80] - stx %o3, [%g1 + 88] - stx %o4, [%g1 + 96] - stx %o5, [%g1 + 104] - stx %o6, [%g1 + 112] - stx %o7, [%g1 + 120] - - stx %l0, [%g1 + 128] - stx %l1, [%g1 + 136] - stx %l2, [%g1 + 144] - stx %l3, [%g1 + 152] - stx %l4, [%g1 + 160] - stx %l5, [%g1 + 168] - stx %l6, [%g1 + 176] - stx %l7, [%g1 + 184] - - stx %i0, [%g1 + 192] - stx %i1, [%g1 + 200] - stx %i2, [%g1 + 208] - stx %i3, [%g1 + 216] - stx %i4, [%g1 + 224] - stx %i5, [%g1 + 232] - stx %i6, [%g1 + 240] - stx %i7, [%g1 + 248] + stx %g1, [%sp + 2047 - 192 - 0x500 + 0x30] + stx %g2, [%sp + 2047 - 192 - 0x500 + 0x38] + stx %g3, [%sp + 2047 - 192 - 0x500 + 0x40] + stx %g4, [%sp + 2047 - 192 - 0x500 + 0x48] + stx %g5, [%sp + 2047 - 192 - 0x500 + 0x50] + stx %g6, [%sp + 2047 - 192 - 0x500 + 0x58] + stx %g7, [%sp + 2047 - 192 - 0x500 + 0x60] + + mov %sp, %g1 + add %g1, 2047 - 192 - 0x500, %g1 + + /* Return PC value */ + mov %o7, %g2 + add %g2, 0x8, %g2 + stx %g2, [%g1 + 0x4d0] + + SAVE_CPU_STATE(switch) + + /* swap context */ + setx __context, %g2, %g3 + ldx [%g3], %g2 + stx %g1, [%g3] + mov %g2, %g1 + + ba __set_context
__switch_context_nosave: /* Interrupts are not allowed... */ @@ -72,53 +62,28 @@ __switch_context_nosave: */ setx __context, %g2, %g1 ldx [%g1], %g1 - ldx [%g1 + 16], %g2 - ldx [%g1 + 24], %g3 - ldx [%g1 + 32], %g4 - ldx [%g1 + 40], %g5 - ldx [%g1 + 48], %g6 - ldx [%g1 + 56], %g7 - - ldx [%g1 + 64], %o0 - ldx [%g1 + 72], %o1 - ldx [%g1 + 80], %o2 - ldx [%g1 + 88], %o3 - ldx [%g1 + 96], %o4 - ldx [%g1 + 104], %o5 - ldx [%g1 + 112], %o6 - ldx [%g1 + 120], %o7 - - ldx [%g1 + 128], %l0 - ldx [%g1 + 136], %l1 - ldx [%g1 + 144], %l2 - ldx [%g1 + 152], %l3 - ldx [%g1 + 160], %l4 - ldx [%g1 + 168], %l5 - ldx [%g1 + 176], %l6 - ldx [%g1 + 184], %l7 - - ldx [%g1 + 192], %i0 - ldx [%g1 + 200], %i1 - ldx [%g1 + 208], %i2 - ldx [%g1 + 216], %i3 - ldx [%g1 + 224], %i4 - ldx [%g1 + 232], %i5 - ldx [%g1 + 240], %i6 - ldx [%g1 + 248], %i7 - - ldx [%g1 + 256], %g1 - /* Finally, load new %pc */ - jmp %g1 - clr %g1 + +__set_context: + RESTORE_CPU_STATE(switch) + + /* Restore globals */ + mov %g1, %g2 + add %g2, 0x30, %g2 + stx %g2, [%sp + 2047 - 192] + + ldx [%g1 + 0x38], %g2 + ldx [%g1 + 0x40], %g3 + ldx [%g1 + 0x48], %g4 + ldx [%g1 + 0x50], %g5 + ldx [%g1 + 0x58], %g6 + ldx [%g1 + 0x60], %g7 + + /* Finally, load new %pc */ + ldx [%g1 + 0x4d0], %g1 + jmpl %g1, %o7 + ldx [%sp + 2047 - 192], %g1
__exit_context: /* Get back to the original context */ - call __switch_context - nop - - /* We get here if the other context attempt to switch to this - * dead context. This should not happen. */ - -halt: - b halt + ba __switch_context nop