2 * Save/restore CPU state macros
4 * Copyright (C) 2015 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk>)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
12 /* State size for context (see below) */
13 #define CONTEXT_STATE_SIZE 0x510
15 /* Stack size for context (allocated inline of the context stack) */
16 #define CONTEXT_STACK_SIZE 0x2000
19 * SAVE_CPU_STATE and RESTORE_CPU_STATE are macros used to enable a context switch
20 * to C to occur within the MMU I/D TLB miss handlers.
22 * Because these handlers are called on a TLB miss, we cannot use flushw to store
23 * processor window state on the stack, as the memory areas used by each window's
24 * stack pointer may not be in the TLB, causing recursive TLB miss traps.
26 * For this reason, we save window state by manually rotating the window registers
27 * and saving their contents (along with other vital registers) into a special
28 * tlb_handler_stack defined above which is guaranteed to be locked in the TLB, and
29 * so won't cause issues with trap recursion.
31 * Once this process is complete, we remain in a TL=0, CWP=0 state (with IE=1 to allow
32 * window fill/spill traps if required), switch to our safe tlb_handler_stack and
33 * invoke the miss handler.
36 #define SAVE_CPU_WINDOW_STATE(type) \
37 /* Save window state into context at %g1 */ \
41 stx %g7, [%g1 + 0x8]; \
42 rdpr %canrestore, %g7; \
43 stx %g7, [%g1 + 0x10]; \
44 rdpr %otherwin, %g7; \
45 stx %g7, [%g1 + 0x18]; \
47 stx %g7, [%g1 + 0x20]; \
48 rdpr %cleanwin, %g7; \
49 stx %g7, [%g1 + 0x28]; \
51 stx %o0, [%g1 + 0x30]; \
52 stx %o1, [%g1 + 0x38]; \
53 stx %o2, [%g1 + 0x40]; \
54 stx %o3, [%g1 + 0x48]; \
55 stx %o4, [%g1 + 0x50]; \
56 stx %o5, [%g1 + 0x58]; \
57 stx %o6, [%g1 + 0x60]; \
58 stx %o7, [%g1 + 0x68]; \
61 stx %g7, [%g1 + 0x70]; \
63 stx %g7, [%g1 + 0x78]; \
65 stx %g7, [%g1 + 0x80]; \
67 stx %g7, [%g1 + 0x88]; \
69 /* Now iterate through all of the windows saving all l and i registers */ \
72 /* Get the number of windows in %g6 */ \
79 /* Starting cwp in g7 */ \
82 save_cpu_window_##type: \
85 stx %l1, [%g5 + 0x8]; \
86 stx %l2, [%g5 + 0x10]; \
87 stx %l3, [%g5 + 0x18]; \
88 stx %l4, [%g5 + 0x20]; \
89 stx %l5, [%g5 + 0x28]; \
90 stx %l6, [%g5 + 0x30]; \
91 stx %l7, [%g5 + 0x38]; \
92 stx %i0, [%g5 + 0x40]; \
93 stx %i1, [%g5 + 0x48]; \
94 stx %i2, [%g5 + 0x50]; \
95 stx %i3, [%g5 + 0x58]; \
96 stx %i4, [%g5 + 0x60]; \
97 stx %i5, [%g5 + 0x68]; \
98 stx %i6, [%g5 + 0x70]; \
99 stx %i7, [%g5 + 0x78]; \
103 bne save_cpu_window_##type; \
104 add %g5, 0x80, %g5; \
106 /* For 8 windows with 16 registers to save in the window, memory required \
107 is 16*8*8 = 0x400 bytes */ \
109 /* Now we should be in window 0 so update the other window registers */ \
113 wrpr %g6, %cansave; \
115 wrpr %g0, %cleanwin; \
116 wrpr %g0, %canrestore; \
117 wrpr %g0, %otherwin; \
120 #define SAVE_CPU_TRAP_STATE(type) \
121 /* Save trap state into context at %g1 */ \
122 add %g1, 0x490, %g5; \
125 save_trap_state_##type: \
131 stx %g7, [%g5 + 0x8]; \
133 stx %g7, [%g5 + 0x10]; \
135 stx %g7, [%g5 + 0x18]; \
136 bne save_trap_state_##type; \
137 add %g5, 0x20, %g5; \
139 /* For 4 trap levels with 4 registers, memory required is \
140 4*8*4 = 0x80 bytes */
142 /* Save all state into context at %g1 */
143 #define SAVE_CPU_STATE(type) \
144 SAVE_CPU_WINDOW_STATE(type); \
145 SAVE_CPU_TRAP_STATE(type);
148 #define RESTORE_CPU_WINDOW_STATE(type) \
149 /* Restore window state from context at %g1 */ \
151 /* Get the number of windows in %g6 */ \
158 /* Set starting window */ \
161 /* Now iterate through all of the windows restoring all l and i registers */ \
162 add %g1, 0x90, %g5; \
164 restore_cpu_window_##type: \
167 ldx [%g5 + 0x8], %l1; \
168 ldx [%g5 + 0x10], %l2; \
169 ldx [%g5 + 0x18], %l3; \
170 ldx [%g5 + 0x20], %l4; \
171 ldx [%g5 + 0x28], %l5; \
172 ldx [%g5 + 0x30], %l6; \
173 ldx [%g5 + 0x38], %l7; \
174 ldx [%g5 + 0x40], %i0; \
175 ldx [%g5 + 0x48], %i1; \
176 ldx [%g5 + 0x50], %i2; \
177 ldx [%g5 + 0x58], %i3; \
178 ldx [%g5 + 0x60], %i4; \
179 ldx [%g5 + 0x68], %i5; \
180 ldx [%g5 + 0x70], %i6; \
181 ldx [%g5 + 0x78], %i7; \
185 bne restore_cpu_window_##type; \
186 add %g5, 0x80, %g5; \
188 /* Restore the window registers to their original value */ \
191 ldx [%g1 + 0x8], %g7; \
192 wrpr %g7, %cansave; \
193 ldx [%g1 + 0x10], %g7; \
194 wrpr %g7, %canrestore; \
195 ldx [%g1 + 0x18], %g7; \
196 wrpr %g7, %otherwin; \
197 ldx [%g1 + 0x20], %g7; \
199 ldx [%g1 + 0x28], %g7; \
200 wrpr %g7, %cleanwin; \
202 ldx [%g1 + 0x30], %o0; \
203 ldx [%g1 + 0x38], %o1; \
204 ldx [%g1 + 0x40], %o2; \
205 ldx [%g1 + 0x48], %o3; \
206 ldx [%g1 + 0x50], %o4; \
207 ldx [%g1 + 0x58], %o5; \
208 ldx [%g1 + 0x60], %o6; \
209 ldx [%g1 + 0x68], %o7; \
211 ldx [%g1 + 0x70], %g7; \
213 ldx [%g1 + 0x78], %g7; \
215 ldx [%g1 + 0x80], %g7; \
219 #define RESTORE_CPU_TRAP_STATE(type) \
220 /* Restore trap state from context at %g1 */ \
221 add %g1, 0x490, %g5; \
224 restore_trap_state_##type: \
229 ldx [%g5 + 0x8], %g7; \
231 ldx [%g5 + 0x10], %g7; \
233 ldx [%g5 + 0x18], %g7; \
235 bne restore_trap_state_##type; \
236 add %g5, 0x20, %g5; \
238 ldx [%g1 + 0x88], %g7; \
241 /* Restore all state from context at %g1 */
242 #define RESTORE_CPU_STATE(type) \
243 RESTORE_CPU_WINDOW_STATE(type); \
244 RESTORE_CPU_TRAP_STATE(type);