These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc64 / cpustate.h
1 /*
2  *   Save/restore CPU state macros
3  *
4  *   Copyright (C) 2015 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk>)
5  *
6  *   This program is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU General Public License
8  *   version 2
9  *
10  */
11
12 /* State size for context (see below) */
13 #define CONTEXT_STATE_SIZE 0x510
14
15 /* Stack size for context (allocated inline of the context stack) */
16 #define CONTEXT_STACK_SIZE 0x2000
17
18 /*
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.
21  *
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.
25  *
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.
30  *
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.
34  */
35
36 #define SAVE_CPU_WINDOW_STATE(type) \
37         /* Save window state into context at %g1 */ \
38         rdpr    %cwp, %g7; \
39         stx     %g7, [%g1]; \
40         rdpr    %cansave, %g7; \
41         stx     %g7, [%g1 + 0x8]; \
42         rdpr    %canrestore, %g7; \
43         stx     %g7, [%g1 + 0x10]; \
44         rdpr    %otherwin, %g7; \
45         stx     %g7, [%g1 + 0x18]; \
46         rdpr    %wstate, %g7; \
47         stx     %g7, [%g1 + 0x20]; \
48         rdpr    %cleanwin, %g7; \
49         stx     %g7, [%g1 + 0x28]; \
50         \
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]; \
59         \
60         rdpr    %pstate, %g7; \
61         stx     %g7, [%g1 + 0x70]; \
62         rd      %y, %g7; \
63         stx     %g7, [%g1 + 0x78]; \
64         rd      %fprs, %g7; \
65         stx     %g7, [%g1 + 0x80]; \
66         rdpr    %tl, %g7; \
67         stx     %g7, [%g1 + 0x88]; \
68         \
69         /* Now iterate through all of the windows saving all l and i registers */ \
70         add     %g1, 0x90, %g5; \
71         \
72         /* Get the number of windows in %g6 */ \
73         rdpr    %ver, %g6; \
74         and     %g6, 0xf, %g6; \
75         \
76         mov     %g6, %g4; \
77         inc     %g4; \
78         \
79         /* Starting cwp in g7 */ \
80         rdpr    %cwp, %g7; \
81         \
82 save_cpu_window_##type: \
83         wrpr    %g7, %cwp; \
84         stx     %l0, [%g5]; \
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]; \
100         dec     %g7; \
101         and     %g7, %g6, %g7; \
102         subcc   %g4, 1, %g4; \
103         bne     save_cpu_window_##type; \
104          add    %g5, 0x80, %g5; \
105         \
106         /* For 8 windows with 16 registers to save in the window, memory required \
107         is 16*8*8 = 0x400 bytes */ \
108         \
109         /* Now we should be in window 0 so update the other window registers */ \
110         rdpr    %ver, %g6; \
111         and     %g6, 0xf, %g6; \
112         dec     %g6; \
113         wrpr    %g6, %cansave; \
114         \
115         wrpr    %g0, %cleanwin; \
116         wrpr    %g0, %canrestore; \
117         wrpr    %g0, %otherwin; \
118
119         
120 #define SAVE_CPU_TRAP_STATE(type) \
121         /* Save trap state into context at %g1 */ \
122         add     %g1, 0x490, %g5; \
123         mov     4, %g6; \
124         \
125 save_trap_state_##type: \
126         deccc   %g6; \
127         wrpr    %g6, %tl; \
128         rdpr    %tpc, %g7; \
129         stx     %g7, [%g5]; \
130         rdpr    %tnpc, %g7; \
131         stx     %g7, [%g5 + 0x8]; \
132         rdpr    %tstate, %g7; \
133         stx     %g7, [%g5 + 0x10]; \
134         rdpr    %tt, %g7; \
135         stx     %g7, [%g5 + 0x18]; \
136         bne     save_trap_state_##type; \
137          add    %g5, 0x20, %g5; \
138         \
139         /* For 4 trap levels with 4 registers, memory required is \
140         4*8*4 = 0x80 bytes */
141
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);
146
147
148 #define RESTORE_CPU_WINDOW_STATE(type) \
149         /* Restore window state from context at %g1 */ \
150         \
151         /* Get the number of windows in %g6 */ \
152         rdpr    %ver, %g6; \
153         and     %g6, 0xf, %g6; \
154         \
155         mov     %g6, %g4; \
156         inc     %g4; \
157         \
158         /* Set starting window */ \
159         ldx     [%g1], %g7; \
160         \
161         /* Now iterate through all of the windows restoring all l and i registers */ \
162         add     %g1, 0x90, %g5; \
163         \
164 restore_cpu_window_##type: \
165         wrpr    %g7, %cwp; \
166         ldx     [%g5], %l0; \
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; \
182         dec     %g7; \
183         and     %g7, %g6, %g7; \
184         subcc   %g4, 1, %g4; \
185         bne     restore_cpu_window_##type; \
186          add    %g5, 0x80, %g5; \
187         \
188         /* Restore the window registers to their original value */ \
189         ldx     [%g1], %g7; \
190         wrpr    %g7, %cwp; \
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; \
198         wrpr    %g7, %wstate; \
199         ldx     [%g1 + 0x28], %g7; \
200         wrpr    %g7, %cleanwin; \
201         \
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; \
210         \
211         ldx     [%g1 + 0x70], %g7; \
212         wrpr    %g7, %pstate; \
213         ldx     [%g1 + 0x78], %g7; \
214         wr      %g7, 0, %y; \
215         ldx     [%g1 + 0x80], %g7; \
216         wr      %g7, 0, %fprs; \
217
218
219 #define RESTORE_CPU_TRAP_STATE(type) \
220         /* Restore trap state from context at %g1 */ \
221         add     %g1, 0x490, %g5; \
222         mov     4, %g6; \
223         \
224 restore_trap_state_##type: \
225         deccc   %g6; \
226         wrpr    %g6, %tl; \
227         ldx     [%g5], %g7; \
228         wrpr    %g7, %tpc; \
229         ldx     [%g5 + 0x8], %g7; \
230         wrpr    %g7, %tnpc; \
231         ldx     [%g5 + 0x10], %g7; \
232         wrpr    %g7, %tstate; \
233         ldx     [%g5 + 0x18], %g7; \
234         wrpr    %g7, %tt; \
235         bne     restore_trap_state_##type; \
236          add    %g5, 0x20, %g5; \
237         \
238         ldx     [%g1 + 0x88], %g7; \
239         wrpr    %g7, %tl
240
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);