1 | /* |
---|
2 | * Assembly support routines for Xen/ia64 |
---|
3 | * |
---|
4 | * Copyright (C) 2004 Hewlett-Packard Co |
---|
5 | * Dan Magenheimer <dan.magenheimer@hp.com> |
---|
6 | */ |
---|
7 | |
---|
8 | #include <linux/config.h> |
---|
9 | #include <asm/asmmacro.h> |
---|
10 | #include <asm/processor.h> |
---|
11 | #include <asm/pgtable.h> |
---|
12 | #include <asm/vhpt.h> |
---|
13 | #include <asm/asm-xsi-offsets.h> |
---|
14 | #include <public/xen.h> |
---|
15 | |
---|
16 | // Change rr7 to the passed value while ensuring |
---|
17 | // Xen is mapped into the new region. |
---|
18 | #define PSR_BITS_TO_CLEAR \ |
---|
19 | (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \ |
---|
20 | IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ |
---|
21 | IA64_PSR_DFL | IA64_PSR_DFH | IA64_PSR_IC) |
---|
22 | // FIXME? Note that this turns off the DB bit (debug) |
---|
23 | #define PSR_BITS_TO_SET IA64_PSR_BN |
---|
24 | |
---|
25 | //extern void ia64_new_rr7(unsigned long rid, /* in0 */ |
---|
26 | // void *shared_info, /* in1 */ |
---|
27 | // void *shared_arch_info, /* in2 */ |
---|
28 | // unsigned long shared_info_va, /* in3 */ |
---|
29 | // unsigned long va_vhpt) /* in4 */ |
---|
30 | //Local usage: |
---|
31 | // loc0=rp, loc1=ar.pfs, loc2=percpu_paddr, loc3=psr, loc4=ar.rse |
---|
32 | // loc5=pal_vaddr, loc6=xen_paddr, loc7=shared_archinfo_paddr, |
---|
33 | // r16, r19, r20 are used by ia64_switch_mode_{phys, virt}() |
---|
34 | GLOBAL_ENTRY(ia64_new_rr7) |
---|
35 | // FIXME? not sure this unwind statement is correct... |
---|
36 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1) |
---|
37 | alloc loc1 = ar.pfs, 5, 8, 0, 0 |
---|
38 | movl loc2=PERCPU_ADDR |
---|
39 | 1: { |
---|
40 | mov loc3 = psr // save psr |
---|
41 | mov loc0 = rp // save rp |
---|
42 | mov r8 = ip // save ip to compute branch |
---|
43 | };; |
---|
44 | .body |
---|
45 | tpa loc2=loc2 // grab this BEFORE changing rr7 |
---|
46 | tpa in1=in1 // grab shared_info BEFORE changing rr7 |
---|
47 | adds r8 = 1f-1b,r8 // calculate return address for call |
---|
48 | ;; |
---|
49 | tpa loc7=in2 // grab arch_vcpu_info BEFORE chg rr7 |
---|
50 | movl r17=PSR_BITS_TO_SET |
---|
51 | mov loc4=ar.rsc // save RSE configuration |
---|
52 | movl r16=PSR_BITS_TO_CLEAR |
---|
53 | ;; |
---|
54 | tpa r8=r8 // convert rp to physical |
---|
55 | mov ar.rsc=0 // put RSE in enforced lazy, LE mode |
---|
56 | or loc3=loc3,r17 // add in psr the bits to set |
---|
57 | ;; |
---|
58 | andcm r16=loc3,r16 // removes bits to clear from psr |
---|
59 | dep loc6=0,r8,0,KERNEL_TR_PAGE_SHIFT // Xen code paddr |
---|
60 | br.call.sptk.many rp=ia64_switch_mode_phys |
---|
61 | 1: |
---|
62 | // now in physical mode with psr.i/ic off so do rr7 switch |
---|
63 | movl r16=pal_vaddr // Note: belong to region 7! |
---|
64 | ;; |
---|
65 | mov rr[r16]=in0 |
---|
66 | ;; |
---|
67 | srlz.d |
---|
68 | dep r16=0,r16,60,4 // Get physical address. |
---|
69 | ;; |
---|
70 | ld8 loc5=[r16] // read pal_vaddr |
---|
71 | movl r26=PAGE_KERNEL |
---|
72 | ;; |
---|
73 | |
---|
74 | // re-pin mappings for kernel text and data |
---|
75 | mov r24=KERNEL_TR_PAGE_SHIFT<<2 |
---|
76 | movl r17=KERNEL_START |
---|
77 | ;; |
---|
78 | ptr.i r17,r24 |
---|
79 | ptr.d r17,r24 |
---|
80 | mov r16=IA64_TR_KERNEL |
---|
81 | mov cr.itir=r24 |
---|
82 | mov cr.ifa=r17 |
---|
83 | or r18=loc6,r26 |
---|
84 | ;; |
---|
85 | itr.i itr[r16]=r18 |
---|
86 | ;; |
---|
87 | itr.d dtr[r16]=r18 |
---|
88 | |
---|
89 | // re-pin mappings for stack (current) |
---|
90 | |
---|
91 | // unless overlaps with KERNEL_TR |
---|
92 | dep r18=0,r13,0,KERNEL_TR_PAGE_SHIFT |
---|
93 | ;; |
---|
94 | cmp.eq p7,p0=r17,r18 |
---|
95 | (p7) br.cond.sptk .stack_overlaps |
---|
96 | mov r25=IA64_GRANULE_SHIFT<<2 |
---|
97 | dep r21=0,r13,60,4 // physical address of "current" |
---|
98 | ;; |
---|
99 | ptr.d r13,r25 |
---|
100 | or r23=r21,r26 // construct PA | page properties |
---|
101 | mov cr.itir=r25 |
---|
102 | mov cr.ifa=r13 // VA of next task... |
---|
103 | mov r21=IA64_TR_CURRENT_STACK |
---|
104 | ;; |
---|
105 | itr.d dtr[r21]=r23 // wire in new mapping... |
---|
106 | |
---|
107 | // Per-cpu |
---|
108 | .stack_overlaps: |
---|
109 | mov r24=PERCPU_PAGE_SHIFT<<2 |
---|
110 | movl r22=PERCPU_ADDR |
---|
111 | ;; |
---|
112 | ptr.d r22,r24 |
---|
113 | or r23=loc2,r26 // construct PA | page properties |
---|
114 | mov cr.itir=r24 |
---|
115 | mov cr.ifa=r22 |
---|
116 | mov r25=IA64_TR_PERCPU_DATA |
---|
117 | ;; |
---|
118 | itr.d dtr[r25]=r23 // wire in new mapping... |
---|
119 | |
---|
120 | // VHPT |
---|
121 | #if VHPT_ENABLED |
---|
122 | #if IA64_GRANULE_SHIFT < VHPT_SIZE_LOG2 |
---|
123 | #error "it must be that VHPT_SIZE_LOG2 <= IA64_GRANULE_SHIFT" |
---|
124 | #endif |
---|
125 | // unless overlaps with KERNEL_TR and IA64_TR_CURRENT_STACK |
---|
126 | dep r14=0,in4,0,KERNEL_TR_PAGE_SHIFT |
---|
127 | dep r15=0,in4,0,IA64_GRANULE_SHIFT |
---|
128 | dep r21=0,r13,0,IA64_GRANULE_SHIFT |
---|
129 | ;; |
---|
130 | cmp.eq p7,p0=r17,r14 |
---|
131 | cmp.eq p8,p0=r15,r21 |
---|
132 | (p7) br.cond.sptk .vhpt_overlaps |
---|
133 | (p8) br.cond.sptk .vhpt_overlaps |
---|
134 | mov r21=IA64_TR_VHPT |
---|
135 | dep r22=0,r15,60,4 // physical address of |
---|
136 | // va_vhpt & ~(IA64_GRANULE_SIZE - 1) |
---|
137 | mov r24=IA64_GRANULE_SHIFT<<2 |
---|
138 | ;; |
---|
139 | ptr.d r15,r24 |
---|
140 | or r23=r22,r26 // construct PA | page properties |
---|
141 | mov cr.itir=r24 |
---|
142 | mov cr.ifa=r15 |
---|
143 | srlz.d |
---|
144 | ;; |
---|
145 | itr.d dtr[r21]=r23 // wire in new mapping... |
---|
146 | .vhpt_overlaps: |
---|
147 | #endif |
---|
148 | |
---|
149 | // Shared info |
---|
150 | mov r24=XSI_SHIFT<<2 |
---|
151 | movl r25=__pgprot(__DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RW) |
---|
152 | ;; |
---|
153 | ptr.d in3,r24 |
---|
154 | or r23=in1,r25 // construct PA | page properties |
---|
155 | mov cr.itir=r24 |
---|
156 | mov cr.ifa=in3 |
---|
157 | mov r21=IA64_TR_SHARED_INFO |
---|
158 | ;; |
---|
159 | itr.d dtr[r21]=r23 // wire in new mapping... |
---|
160 | |
---|
161 | // Map mapped_regs |
---|
162 | mov r22=XMAPPEDREGS_OFS |
---|
163 | mov r24=XMAPPEDREGS_SHIFT<<2 |
---|
164 | ;; |
---|
165 | add r22=r22,in3 |
---|
166 | ;; |
---|
167 | ptr.d r22,r24 |
---|
168 | or r23=loc7,r25 // construct PA | page properties |
---|
169 | mov cr.itir=r24 |
---|
170 | mov cr.ifa=r22 |
---|
171 | mov r21=IA64_TR_MAPPED_REGS |
---|
172 | ;; |
---|
173 | itr.d dtr[r21]=r23 // wire in new mapping... |
---|
174 | |
---|
175 | // Purge/insert PAL TR |
---|
176 | mov r24=IA64_TR_PALCODE |
---|
177 | mov r23=IA64_GRANULE_SHIFT<<2 |
---|
178 | dep r25=0,loc5,60,4 // convert pal vaddr to paddr |
---|
179 | ;; |
---|
180 | ptr.i loc5,r23 |
---|
181 | or r25=r25,r26 // construct PA | page properties |
---|
182 | mov cr.itir=r23 |
---|
183 | mov cr.ifa=loc5 |
---|
184 | ;; |
---|
185 | itr.i itr[r24]=r25 |
---|
186 | |
---|
187 | // done, switch back to virtual and return |
---|
188 | mov r16=loc3 // r16= original psr |
---|
189 | br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode |
---|
190 | mov psr.l = loc3 // restore init PSR |
---|
191 | |
---|
192 | mov ar.pfs = loc1 |
---|
193 | mov rp = loc0 |
---|
194 | ;; |
---|
195 | mov ar.rsc=loc4 // restore RSE configuration |
---|
196 | srlz.d // seralize restoration of psr.l |
---|
197 | br.ret.sptk.many rp |
---|
198 | END(ia64_new_rr7) |
---|
199 | |
---|
200 | #if 0 /* Not used */ |
---|
201 | #include "minstate.h" |
---|
202 | |
---|
203 | GLOBAL_ENTRY(ia64_prepare_handle_privop) |
---|
204 | .prologue |
---|
205 | /* |
---|
206 | * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 |
---|
207 | */ |
---|
208 | mov r16=r0 |
---|
209 | DO_SAVE_SWITCH_STACK |
---|
210 | br.call.sptk.many rp=ia64_handle_privop // stack frame setup in ivt |
---|
211 | .ret22: .body |
---|
212 | DO_LOAD_SWITCH_STACK |
---|
213 | br.cond.sptk.many rp // goes to ia64_leave_kernel |
---|
214 | END(ia64_prepare_handle_privop) |
---|
215 | |
---|
216 | GLOBAL_ENTRY(ia64_prepare_handle_break) |
---|
217 | .prologue |
---|
218 | /* |
---|
219 | * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 |
---|
220 | */ |
---|
221 | mov r16=r0 |
---|
222 | DO_SAVE_SWITCH_STACK |
---|
223 | br.call.sptk.many rp=ia64_handle_break // stack frame setup in ivt |
---|
224 | .ret23: .body |
---|
225 | DO_LOAD_SWITCH_STACK |
---|
226 | br.cond.sptk.many rp // goes to ia64_leave_kernel |
---|
227 | END(ia64_prepare_handle_break) |
---|
228 | |
---|
229 | GLOBAL_ENTRY(ia64_prepare_handle_reflection) |
---|
230 | .prologue |
---|
231 | /* |
---|
232 | * r16 = fake ar.pfs, we simply need to make sure privilege is still 0 |
---|
233 | */ |
---|
234 | mov r16=r0 |
---|
235 | DO_SAVE_SWITCH_STACK |
---|
236 | br.call.sptk.many rp=ia64_handle_reflection // stack frame setup in ivt |
---|
237 | .ret24: .body |
---|
238 | DO_LOAD_SWITCH_STACK |
---|
239 | br.cond.sptk.many rp // goes to ia64_leave_kernel |
---|
240 | END(ia64_prepare_handle_reflection) |
---|
241 | #endif |
---|
242 | |
---|
243 | GLOBAL_ENTRY(__get_domain_bundle) |
---|
244 | EX(.failure_in_get_bundle,ld8 r8=[r32],8) |
---|
245 | ;; |
---|
246 | EX(.failure_in_get_bundle,ld8 r9=[r32]) |
---|
247 | ;; |
---|
248 | br.ret.sptk.many rp |
---|
249 | ;; |
---|
250 | .failure_in_get_bundle: |
---|
251 | mov r8=0 |
---|
252 | ;; |
---|
253 | mov r9=0 |
---|
254 | ;; |
---|
255 | br.ret.sptk.many rp |
---|
256 | ;; |
---|
257 | END(__get_domain_bundle) |
---|
258 | |
---|
259 | /* derived from linux/arch/ia64/hp/sim/boot/boot_head.S */ |
---|
260 | GLOBAL_ENTRY(pal_emulator_static) |
---|
261 | mov r8=-1 |
---|
262 | mov r9=256 |
---|
263 | ;; |
---|
264 | cmp.gtu p7,p8=r9,r32 /* r32 <= 255? */ |
---|
265 | (p7) br.cond.sptk.few static |
---|
266 | ;; |
---|
267 | mov r9=512 |
---|
268 | ;; |
---|
269 | cmp.gtu p7,p8=r9,r32 |
---|
270 | (p7) br.cond.sptk.few stacked |
---|
271 | ;; |
---|
272 | static: cmp.eq p7,p8=6,r32 /* PAL_PTCE_INFO */ |
---|
273 | (p8) br.cond.sptk.few 1f |
---|
274 | ;; |
---|
275 | mov r8=0 /* status = 0 */ |
---|
276 | movl r9=0x100000000 /* tc.base */ |
---|
277 | movl r10=0x0000000200000003 /* count[0], count[1] */ |
---|
278 | movl r11=0x1000000000002000 /* stride[0], stride[1] */ |
---|
279 | br.ret.sptk.few rp |
---|
280 | 1: cmp.eq p7,p8=14,r32 /* PAL_FREQ_RATIOS */ |
---|
281 | (p8) br.cond.sptk.few 1f |
---|
282 | mov r8=0 /* status = 0 */ |
---|
283 | movl r9 =0x900000002 /* proc_ratio (1/100) */ |
---|
284 | movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ |
---|
285 | movl r11=0x900000002 /* itc_ratio<<32 (1/100) */ |
---|
286 | ;; |
---|
287 | 1: cmp.eq p7,p8=19,r32 /* PAL_RSE_INFO */ |
---|
288 | (p8) br.cond.sptk.few 1f |
---|
289 | mov r8=0 /* status = 0 */ |
---|
290 | mov r9=96 /* num phys stacked */ |
---|
291 | mov r10=0 /* hints */ |
---|
292 | mov r11=0 |
---|
293 | br.ret.sptk.few rp |
---|
294 | 1: cmp.eq p7,p8=1,r32 /* PAL_CACHE_FLUSH */ |
---|
295 | (p8) br.cond.sptk.few 1f |
---|
296 | #if 0 |
---|
297 | mov r9=ar.lc |
---|
298 | movl r8=524288 /* flush 512k million cache lines (16MB) */ |
---|
299 | ;; |
---|
300 | mov ar.lc=r8 |
---|
301 | movl r8=0xe000000000000000 |
---|
302 | ;; |
---|
303 | .loop: fc r8 |
---|
304 | add r8=32,r8 |
---|
305 | br.cloop.sptk.few .loop |
---|
306 | sync.i |
---|
307 | ;; |
---|
308 | srlz.i |
---|
309 | ;; |
---|
310 | mov ar.lc=r9 |
---|
311 | mov r8=r0 |
---|
312 | ;; |
---|
313 | 1: cmp.eq p7,p8=15,r32 /* PAL_PERF_MON_INFO */ |
---|
314 | (p8) br.cond.sptk.few 1f |
---|
315 | mov r8=0 /* status = 0 */ |
---|
316 | movl r9 =0x08122f04 /* generic=4 width=47 retired=8 |
---|
317 | * cycles=18 |
---|
318 | */ |
---|
319 | mov r10=0 /* reserved */ |
---|
320 | mov r11=0 /* reserved */ |
---|
321 | mov r16=0xffff /* implemented PMC */ |
---|
322 | mov r17=0x3ffff /* implemented PMD */ |
---|
323 | add r18=8,r29 /* second index */ |
---|
324 | ;; |
---|
325 | st8 [r29]=r16,16 /* store implemented PMC */ |
---|
326 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
327 | ;; |
---|
328 | st8 [r29]=r0,16 /* clear remaining bits */ |
---|
329 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
330 | ;; |
---|
331 | st8 [r29]=r17,16 /* store implemented PMD */ |
---|
332 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
333 | mov r16=0xf0 /* cycles count capable PMC */ |
---|
334 | ;; |
---|
335 | st8 [r29]=r0,16 /* clear remaining bits */ |
---|
336 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
337 | mov r17=0xf0 /* retired bundles capable PMC */ |
---|
338 | ;; |
---|
339 | st8 [r29]=r16,16 /* store cycles capable */ |
---|
340 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
341 | ;; |
---|
342 | st8 [r29]=r0,16 /* clear remaining bits */ |
---|
343 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
344 | ;; |
---|
345 | st8 [r29]=r17,16 /* store retired bundle capable */ |
---|
346 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
347 | ;; |
---|
348 | st8 [r29]=r0,16 /* clear remaining bits */ |
---|
349 | st8 [r18]=r0,16 /* clear remaining bits */ |
---|
350 | ;; |
---|
351 | 1: br.cond.sptk.few rp |
---|
352 | #else |
---|
353 | 1: |
---|
354 | #endif |
---|
355 | stacked: |
---|
356 | br.ret.sptk.few rp |
---|
357 | END(pal_emulator_static) |
---|
358 | |
---|
359 | // These instructions are copied in the domains. |
---|
360 | // This is the virtual PAL, which simply does a hypercall. |
---|
361 | // The size is 2 bundles (32 Bytes). It handles both static and stacked |
---|
362 | // convention. |
---|
363 | // If you modify this code, you have to modify dom_fw.h (for the size) and |
---|
364 | // dom_fw_pal_hypercall_patch. |
---|
365 | GLOBAL_ENTRY(pal_call_stub) |
---|
366 | { |
---|
367 | .mii |
---|
368 | addl r2=0x1000,r0 // Hypercall number (Value is patched). |
---|
369 | mov r9=256 |
---|
370 | ;; |
---|
371 | cmp.gtu p7,p8=r9,r28 /* r32 <= 255? */ |
---|
372 | } |
---|
373 | { |
---|
374 | .mbb |
---|
375 | break 0x1000 // Hypercall vector (Value is patched). |
---|
376 | (p7) br.cond.sptk.few rp |
---|
377 | (p8) br.ret.sptk.few rp |
---|
378 | } |
---|
379 | END(pal_call_stub) |
---|
380 | |
---|
381 | |
---|