Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / arch / sparc64 / call-client.S
1         .globl  sparc64_of_client_interface, client_tba
2
3
4 /*
5  * SAVE_WINDOW_STATE and RESTORE_WINDOW_STATE are used to ensure
6  * that the CPU window state is preserved across CIF calls. This is
7  * to workaround a *BSD restriction that window fill/spill traps must
8  * be minimised during trap table takeover, and likely emulates the
9  * behaviour of OBP.
10  */
11
12 #define SAVE_WINDOW_STATE(type) \
13         setx    client_window, %g6, %g1; \
14         rdpr    %cwp, %g7; \
15         stx     %g7, [%g1]; \
16         rdpr    %cansave, %g7; \
17         stx     %g7, [%g1 + 0x8]; \
18         rdpr    %canrestore, %g7; \
19         stx     %g7, [%g1 + 0x10]; \
20         rdpr    %otherwin, %g7; \
21         stx     %g7, [%g1 + 0x18]; \
22         rdpr    %wstate, %g7; \
23         stx     %g7, [%g1 + 0x20]; \
24         rdpr    %cleanwin, %g7; \
25         stx     %g7, [%g1 + 0x28]; \
26         \
27         stx     %o0, [%g1 + 0x30]; \
28         stx     %o1, [%g1 + 0x38]; \
29         stx     %o2, [%g1 + 0x40]; \
30         stx     %o3, [%g1 + 0x48]; \
31         stx     %o4, [%g1 + 0x50]; \
32         stx     %o5, [%g1 + 0x58]; \
33         stx     %o6, [%g1 + 0x60]; \
34         stx     %o7, [%g1 + 0x68]; \
35         \
36         rdpr    %pstate, %g7; \
37         stx     %g7, [%g1 + 0x70]; \
38         rd      %y, %g7; \
39         stx     %g7, [%g1 + 0x78]; \
40         rd      %fprs, %g7; \
41         stx     %g7, [%g1 + 0x80]; \
42         \
43         /* Now iterate through all of the windows saving all l and i registers */ \
44         add     %g1, 0x90, %g5; \
45         \
46         /* Get the number of windows in %g6 */ \
47         rdpr    %ver, %g6; \
48         and     %g6, 0xf, %g6; \
49         inc     %g6; \
50         \
51 save_cpu_window_##type: \
52         deccc   %g6; \
53         wrpr    %g6, %cwp; \
54         stx     %l0, [%g5]; \
55         stx     %l1, [%g5 + 0x8]; \
56         stx     %l2, [%g5 + 0x10]; \
57         stx     %l3, [%g5 + 0x18]; \
58         stx     %l4, [%g5 + 0x20]; \
59         stx     %l5, [%g5 + 0x28]; \
60         stx     %l6, [%g5 + 0x30]; \
61         stx     %l7, [%g5 + 0x38]; \
62         stx     %i0, [%g5 + 0x40]; \
63         stx     %i1, [%g5 + 0x48]; \
64         stx     %i2, [%g5 + 0x50]; \
65         stx     %i3, [%g5 + 0x58]; \
66         stx     %i4, [%g5 + 0x60]; \
67         stx     %i5, [%g5 + 0x68]; \
68         stx     %i6, [%g5 + 0x70]; \
69         stx     %i7, [%g5 + 0x78]; \
70         bne     save_cpu_window_##type; \
71          add    %g5, 0x80, %g5; \
72         \
73         /* For 8 windows with 16 registers to save in the window, memory required \
74         is 16*8*8 = 0x400 bytes */ \
75         \
76         /* Now we should be in window 0 so update the other window registers */ \
77         rdpr    %ver, %g6; \
78         and     %g6, 0xf, %g6; \
79         dec     %g6; \
80         wrpr    %g6, %cansave; \
81         \
82         wrpr    %g0, %cleanwin; \
83         wrpr    %g0, %canrestore; \
84         wrpr    %g0, %otherwin;
85
86
87 #define RESTORE_WINDOW_STATE(type) \
88         setx    client_window, %g6, %g1; \
89         \
90         /* Get the number of windows in %g6 */ \
91         rdpr    %ver, %g6; \
92         and     %g6, 0xf, %g6; \
93         inc     %g6; \
94         \
95         /* Now iterate through all of the windows restoring all l and i registers */ \
96         add     %g1, 0x90, %g5; \
97         \
98 restore_cpu_window_##type: \
99         deccc   %g6; \
100         wrpr    %g6, %cwp; \
101         ldx     [%g5], %l0; \
102         ldx     [%g5 + 0x8], %l1; \
103         ldx     [%g5 + 0x10], %l2; \
104         ldx     [%g5 + 0x18], %l3; \
105         ldx     [%g5 + 0x20], %l4; \
106         ldx     [%g5 + 0x28], %l5; \
107         ldx     [%g5 + 0x30], %l6; \
108         ldx     [%g5 + 0x38], %l7; \
109         ldx     [%g5 + 0x40], %i0; \
110         ldx     [%g5 + 0x48], %i1; \
111         ldx     [%g5 + 0x50], %i2; \
112         ldx     [%g5 + 0x58], %i3; \
113         ldx     [%g5 + 0x60], %i4; \
114         ldx     [%g5 + 0x68], %i5; \
115         ldx     [%g5 + 0x70], %i6; \
116         ldx     [%g5 + 0x78], %i7; \
117         bne     restore_cpu_window_##type; \
118          add    %g5, 0x80, %g5; \
119         \
120         /* Restore the window registers to their original value */ \
121         ldx     [%g1], %g7; \
122         wrpr    %g7, %cwp; \
123         ldx     [%g1 + 0x8], %g7; \
124         wrpr    %g7, %cansave; \
125         ldx     [%g1 + 0x10], %g7; \
126         wrpr    %g7, %canrestore; \
127         ldx     [%g1 + 0x18], %g7; \
128         wrpr    %g7, %otherwin; \
129         ldx     [%g1 + 0x20], %g7; \
130         wrpr    %g7, %wstate; \
131         ldx     [%g1 + 0x28], %g7; \
132         wrpr    %g7, %cleanwin; \
133         \
134         ldx     [%g1 + 0x30], %o0; \
135         ldx     [%g1 + 0x38], %o1; \
136         ldx     [%g1 + 0x40], %o2; \
137         ldx     [%g1 + 0x48], %o3; \
138         ldx     [%g1 + 0x50], %o4; \
139         ldx     [%g1 + 0x58], %o5; \
140         ldx     [%g1 + 0x60], %o6; \
141         ldx     [%g1 + 0x68], %o7; \
142         \
143         ldx     [%g1 + 0x70], %g7; \
144         wrpr    %g7, %pstate; \
145         ldx     [%g1 + 0x78], %g7; \
146         wr      %g7, 0, %y; \
147         ldx     [%g1 + 0x80], %g7; \
148         wr      %g7, 0, %fprs
149
150
151         .data
152         .align  8
153
154         .skip   16384
155 openbios_stack:
156
157 client_stack:
158         .xword  0
159 client_tba:
160         .xword  0
161 client_window:
162         .skip   2048
163
164
165         .text
166         .align  4
167         .register %g2, #scratch
168         .register %g3, #scratch
169         .register %g6, #scratch
170         .register %g7, #scratch
171 /*
172         make some more space on stack since linux kernel only provides 128 bytes
173         without memory to spill registers (used by gcc in -O0 mode)
174 */
175
176 sparc64_of_client_interface:
177
178         /* Save globals on callers stack */
179         add     %sp, -56, %sp
180
181         stx     %g1, [%sp + 2047 + 0]
182         stx     %g2, [%sp + 2047 + 8]
183         stx     %g3, [%sp + 2047 + 16]
184         stx     %g4, [%sp + 2047 + 24]
185         stx     %g5, [%sp + 2047 + 32]
186         stx     %g6, [%sp + 2047 + 40]
187         stx     %g7, [%sp + 2047 + 48]
188
189         /* Save client trap table */
190         setx    client_tba, %g6, %g7
191         rdpr    %tba, %g6
192         stx     %g6, [%g7]
193
194         /* Save existing stack */
195         setx    client_stack, %g6, %g7
196         stx     %sp, [%g7]
197
198         /* Save windows */
199         SAVE_WINDOW_STATE(cif)
200
201         /* Move to OpenBIOS stack */
202         setx    openbios_stack - 2047 - 192, %g6, %g7
203         mov     %g7, %sp
204
205         /* Call client inteface */
206         call of_client_interface
207          ldx    [%g1 + 0x30], %o0
208
209         setx    client_window, %g6, %g1
210         stx     %o0, [%g1 + 0x30]
211
212         /* Restore windows */
213         RESTORE_WINDOW_STATE(cif)
214
215         /* Restore stack */
216         setx    client_stack, %g6, %g7
217         ldx     [%g7], %sp
218
219         /* Restore client trap table */
220         setx    client_tba, %g6, %g7
221         ldx     [%g7], %g6
222         wrpr    %g6, %tba
223
224         /* Restore globals */
225         ldx     [%sp + 2047 + 0], %g1
226         ldx     [%sp + 2047 + 8], %g2
227         ldx     [%sp + 2047 + 16], %g3
228         ldx     [%sp + 2047 + 24], %g4
229         ldx     [%sp + 2047 + 32], %g5
230         ldx     [%sp + 2047 + 40], %g6
231         ldx     [%sp + 2047 + 48], %g7
232
233         add     %sp, 56, %sp
234
235         jmp     %o7+8
236          nop