Linux 2.6.31
[deliverable/linux.git] / arch / ia64 / kernel / mca_asm.S
CommitLineData
fe77efb8
HS
1/*
2 * File: mca_asm.S
3 * Purpose: assembly portion of the IA64 MCA handling
4 *
5 * Mods by cfleck to integrate into kernel build
6 *
7 * 2000-03-15 David Mosberger-Tang <davidm@hpl.hp.com>
8 * Added various stop bits to get a clean compile
9 *
10 * 2000-03-29 Chuck Fleckenstein <cfleck@co.intel.com>
11 * Added code to save INIT handoff state in pt_regs format,
12 * switch to temp kstack, switch modes, jump to C INIT handler
13 *
14 * 2002-01-04 J.Hall <jenna.s.hall@intel.com>
15 * Before entering virtual mode code:
16 * 1. Check for TLB CPU error
17 * 2. Restore current thread pointer to kr6
18 * 3. Move stack ptr 16 bytes to conform to C calling convention
19 *
20 * 2004-11-12 Russ Anderson <rja@sgi.com>
21 * Added per cpu MCA/INIT stack save areas.
22 *
23 * 2005-12-08 Keith Owens <kaos@sgi.com>
24 * Use per cpu MCA/INIT stacks for all data.
25 */
1da177e4
LT
26#include <linux/threads.h>
27
28#include <asm/asmmacro.h>
29#include <asm/pgtable.h>
30#include <asm/processor.h>
31#include <asm/mca_asm.h>
32#include <asm/mca.h>
33
7f613c7d 34#include "entry.h"
1da177e4
LT
35
36#define GET_IA64_MCA_DATA(reg) \
37 GET_THIS_PADDR(reg, ia64_mca_data) \
38 ;; \
39 ld8 reg=[reg]
40
b8d8b883 41 .global ia64_do_tlb_purge
7f613c7d
KO
42 .global ia64_os_mca_dispatch
43 .global ia64_os_init_dispatch_monarch
44 .global ia64_os_init_dispatch_slave
1da177e4
LT
45
46 .text
47 .align 16
48
7f613c7d
KO
49//StartMain////////////////////////////////////////////////////////////////////
50
b8d8b883
AR
51/*
52 * Just the TLB purge part is moved to a separate function
53 * so we can re-use the code for cpu hotplug code as well
54 * Caller should now setup b1, so we can branch once the
55 * tlb flush is complete.
56 */
1da177e4 57
b8d8b883 58ia64_do_tlb_purge:
1da177e4
LT
59#define O(member) IA64_CPUINFO_##member##_OFFSET
60
61 GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2
62 ;;
63 addl r17=O(PTCE_STRIDE),r2
64 addl r2=O(PTCE_BASE),r2
65 ;;
66 ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base
67 ld4 r19=[r2],4 // r19=ptce_count[0]
68 ld4 r21=[r17],4 // r21=ptce_stride[0]
69 ;;
70 ld4 r20=[r2] // r20=ptce_count[1]
71 ld4 r22=[r17] // r22=ptce_stride[1]
72 mov r24=0
73 ;;
74 adds r20=-1,r20
75 ;;
76#undef O
77
782:
79 cmp.ltu p6,p7=r24,r19
80(p7) br.cond.dpnt.few 4f
81 mov ar.lc=r20
823:
83 ptc.e r18
84 ;;
85 add r18=r22,r18
86 br.cloop.sptk.few 3b
87 ;;
88 add r18=r21,r18
89 add r24=1,r24
90 ;;
91 br.sptk.few 2b
924:
93 srlz.i // srlz.i implies srlz.d
94 ;;
95
96 // Now purge addresses formerly mapped by TR registers
97 // 1. Purge ITR&DTR for kernel.
98 movl r16=KERNEL_START
99 mov r18=KERNEL_TR_PAGE_SHIFT<<2
100 ;;
101 ptr.i r16, r18
102 ptr.d r16, r18
103 ;;
104 srlz.i
105 ;;
106 srlz.d
107 ;;
1da177e4
LT
108 // 3. Purge ITR for PAL code.
109 GET_THIS_PADDR(r2, ia64_mca_pal_base)
110 ;;
111 ld8 r16=[r2]
112 mov r18=IA64_GRANULE_SHIFT<<2
113 ;;
114 ptr.i r16,r18
115 ;;
116 srlz.i
117 ;;
118 // 4. Purge DTR for stack.
119 mov r16=IA64_KR(CURRENT_STACK)
120 ;;
121 shl r16=r16,IA64_GRANULE_SHIFT
122 movl r19=PAGE_OFFSET
123 ;;
124 add r16=r19,r16
125 mov r18=IA64_GRANULE_SHIFT<<2
126 ;;
127 ptr.d r16,r18
128 ;;
129 srlz.i
130 ;;
b8d8b883
AR
131 // Now branch away to caller.
132 br.sptk.many b1
133 ;;
134
7f613c7d
KO
135//EndMain//////////////////////////////////////////////////////////////////////
136
137//StartMain////////////////////////////////////////////////////////////////////
b8d8b883 138
7f613c7d 139ia64_os_mca_dispatch:
7f613c7d
KO
140 mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack
141 LOAD_PHYSICAL(p0,r2,1f) // return address
142 mov r19=1 // All MCA events are treated as monarch (for now)
143 br.sptk ia64_state_save // save the state that is not in minstate
1441:
b8d8b883 145
7f613c7d
KO
146 GET_IA64_MCA_DATA(r2)
147 // Using MCA stack, struct ia64_sal_os_state, variable proc_state_param
148 ;;
d270acbc 149 add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+SOS(PROC_STATE_PARAM), r2
b8d8b883 150 ;;
7f613c7d 151 ld8 r18=[r3] // Get processor state parameter on existing PALE_CHECK.
b8d8b883
AR
152 ;;
153 tbit.nz p6,p7=r18,60
154(p7) br.spnt done_tlb_purge_and_reload
155
156 // The following code purges TC and TR entries. Then reload all TC entries.
157 // Purge percpu data TC entries.
158begin_tlb_purge_and_reload:
159 movl r18=ia64_reload_tr;;
160 LOAD_PHYSICAL(p0,r18,ia64_reload_tr);;
161 mov b1=r18;;
162 br.sptk.many ia64_do_tlb_purge;;
163
164ia64_reload_tr:
1da177e4
LT
165 // Finally reload the TR registers.
166 // 1. Reload DTR/ITR registers for kernel.
167 mov r18=KERNEL_TR_PAGE_SHIFT<<2
168 movl r17=KERNEL_START
169 ;;
170 mov cr.itir=r18
171 mov cr.ifa=r17
172 mov r16=IA64_TR_KERNEL
173 mov r19=ip
174 movl r18=PAGE_KERNEL
175 ;;
176 dep r17=0,r19,0, KERNEL_TR_PAGE_SHIFT
177 ;;
178 or r18=r17,r18
179 ;;
180 itr.i itr[r16]=r18
181 ;;
182 itr.d dtr[r16]=r18
183 ;;
184 srlz.i
185 srlz.d
186 ;;
1da177e4
LT
187 // 3. Reload ITR for PAL code.
188 GET_THIS_PADDR(r2, ia64_mca_pal_pte)
189 ;;
190 ld8 r18=[r2] // load PAL PTE
191 ;;
192 GET_THIS_PADDR(r2, ia64_mca_pal_base)
193 ;;
194 ld8 r16=[r2] // load PAL vaddr
195 mov r19=IA64_GRANULE_SHIFT<<2
196 ;;
197 mov cr.itir=r19
198 mov cr.ifa=r16
199 mov r20=IA64_TR_PALCODE
200 ;;
201 itr.i itr[r20]=r18
202 ;;
203 srlz.i
204 ;;
205 // 4. Reload DTR for stack.
206 mov r16=IA64_KR(CURRENT_STACK)
207 ;;
208 shl r16=r16,IA64_GRANULE_SHIFT
209 movl r19=PAGE_OFFSET
210 ;;
211 add r18=r19,r16
212 movl r20=PAGE_KERNEL
213 ;;
214 add r16=r20,r16
215 mov r19=IA64_GRANULE_SHIFT<<2
216 ;;
217 mov cr.itir=r19
218 mov cr.ifa=r18
219 mov r20=IA64_TR_CURRENT_STACK
220 ;;
221 itr.d dtr[r20]=r16
96651896
XZ
222 GET_THIS_PADDR(r2, ia64_mca_tr_reload)
223 mov r18 = 1
1da177e4
LT
224 ;;
225 srlz.d
96651896
XZ
226 ;;
227 st8 [r2] =r18
228 ;;
1da177e4
LT
229
230done_tlb_purge_and_reload:
231
7f613c7d
KO
232 // switch to per cpu MCA stack
233 mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack
234 LOAD_PHYSICAL(p0,r2,1f) // return address
235 br.sptk ia64_new_stack
2361:
237
238 // everything saved, now we can set the kernel registers
239 mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack
240 LOAD_PHYSICAL(p0,r2,1f) // return address
241 br.sptk ia64_set_kernel_registers
2421:
1da177e4 243
7f613c7d 244 // This must be done in physical mode
1da177e4
LT
245 GET_IA64_MCA_DATA(r2)
246 ;;
7f613c7d 247 mov r7=r2
1da177e4
LT
248
249 // Enter virtual mode from physical mode
250 VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
7f613c7d
KO
251
252 // This code returns to SAL via SOS r2, in general SAL has no unwind
253 // data. To get a clean termination when backtracing the C MCA/INIT
254 // handler, set a dummy return address of 0 in this routine. That
255 // requires that ia64_os_mca_virtual_begin be a global function.
256ENTRY(ia64_os_mca_virtual_begin)
257 .prologue
258 .save rp,r0
259 .body
260
261 mov ar.rsc=3 // set eager mode for C handler
262 mov r2=r7 // see GET_IA64_MCA_DATA above
263 ;;
1da177e4
LT
264
265 // Call virtual mode handler
7f613c7d
KO
266 alloc r14=ar.pfs,0,0,3,0
267 ;;
268 DATA_PA_TO_VA(r2,r7)
269 ;;
270 add out0=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_PT_REGS_OFFSET, r2
271 add out1=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SWITCH_STACK_OFFSET, r2
272 add out2=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET, r2
273 br.call.sptk.many b0=ia64_mca_handler
274
1da177e4
LT
275 // Revert back to physical mode before going back to SAL
276 PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
277ia64_os_mca_virtual_end:
278
7f613c7d
KO
279END(ia64_os_mca_virtual_begin)
280
281 // switch back to previous stack
282 alloc r14=ar.pfs,0,0,0,0 // remove the MCA handler frame
283 mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack
284 LOAD_PHYSICAL(p0,r2,1f) // return address
285 br.sptk ia64_old_stack
2861:
287
288 mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack
289 LOAD_PHYSICAL(p0,r2,1f) // return address
290 br.sptk ia64_state_restore // restore the SAL state
2911:
292
293 mov b0=r12 // SAL_CHECK return address
294
7f613c7d
KO
295 br b0
296
297//EndMain//////////////////////////////////////////////////////////////////////
298
299//StartMain////////////////////////////////////////////////////////////////////
300
301//
302// SAL to OS entry point for INIT on all processors. This has been defined for
303// registration purposes with SAL as a part of ia64_mca_init. Monarch and
304// slave INIT have identical processing, except for the value of the
305// sos->monarch flag in r19.
306//
307
308ia64_os_init_dispatch_monarch:
309 mov r19=1 // Bow, bow, ye lower middle classes!
310 br.sptk ia64_os_init_dispatch
311
312ia64_os_init_dispatch_slave:
313 mov r19=0 // <igor>yeth, mathter</igor>
314
315ia64_os_init_dispatch:
316
317 mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack
318 LOAD_PHYSICAL(p0,r2,1f) // return address
319 br.sptk ia64_state_save // save the state that is not in minstate
3201:
321
322 // switch to per cpu INIT stack
323 mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack
324 LOAD_PHYSICAL(p0,r2,1f) // return address
325 br.sptk ia64_new_stack
3261:
327
328 // everything saved, now we can set the kernel registers
329 mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack
330 LOAD_PHYSICAL(p0,r2,1f) // return address
331 br.sptk ia64_set_kernel_registers
3321:
333
334 // This must be done in physical mode
1da177e4
LT
335 GET_IA64_MCA_DATA(r2)
336 ;;
7f613c7d
KO
337 mov r7=r2
338
339 // Enter virtual mode from physical mode
340 VIRTUAL_MODE_ENTER(r2, r3, ia64_os_init_virtual_begin, r4)
341
342 // This code returns to SAL via SOS r2, in general SAL has no unwind
343 // data. To get a clean termination when backtracing the C MCA/INIT
344 // handler, set a dummy return address of 0 in this routine. That
345 // requires that ia64_os_init_virtual_begin be a global function.
346ENTRY(ia64_os_init_virtual_begin)
347 .prologue
348 .save rp,r0
349 .body
350
351 mov ar.rsc=3 // set eager mode for C handler
352 mov r2=r7 // see GET_IA64_MCA_DATA above
1da177e4 353 ;;
1da177e4 354
7f613c7d
KO
355 // Call virtual mode handler
356 alloc r14=ar.pfs,0,0,3,0
357 ;;
358 DATA_PA_TO_VA(r2,r7)
1da177e4 359 ;;
7f613c7d
KO
360 add out0=IA64_MCA_CPU_INIT_STACK_OFFSET+MCA_PT_REGS_OFFSET, r2
361 add out1=IA64_MCA_CPU_INIT_STACK_OFFSET+MCA_SWITCH_STACK_OFFSET, r2
362 add out2=IA64_MCA_CPU_INIT_STACK_OFFSET+MCA_SOS_OFFSET, r2
363 br.call.sptk.many b0=ia64_init_handler
1da177e4 364
7f613c7d
KO
365 // Revert back to physical mode before going back to SAL
366 PHYSICAL_MODE_ENTER(r2, r3, ia64_os_init_virtual_end, r4)
367ia64_os_init_virtual_end:
1da177e4 368
7f613c7d
KO
369END(ia64_os_init_virtual_begin)
370
371 mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack
372 LOAD_PHYSICAL(p0,r2,1f) // return address
373 br.sptk ia64_state_restore // restore the SAL state
3741:
1da177e4 375
7f613c7d
KO
376 // switch back to previous stack
377 alloc r14=ar.pfs,0,0,0,0 // remove the INIT handler frame
378 mov r3=IA64_MCA_CPU_INIT_STACK_OFFSET // use the INIT stack
379 LOAD_PHYSICAL(p0,r2,1f) // return address
380 br.sptk ia64_old_stack
3811:
382
383 mov b0=r12 // SAL_CHECK return address
1da177e4 384 br b0
7f613c7d 385
1da177e4
LT
386//EndMain//////////////////////////////////////////////////////////////////////
387
7f613c7d
KO
388// common defines for the stubs
389#define ms r4
390#define regs r5
391#define temp1 r2 /* careful, it overlaps with input registers */
392#define temp2 r3 /* careful, it overlaps with input registers */
393#define temp3 r7
394#define temp4 r14
395
1da177e4
LT
396
397//++
398// Name:
7f613c7d 399// ia64_state_save()
1da177e4
LT
400//
401// Stub Description:
402//
7f613c7d
KO
403// Save the state that is not in minstate. This is sensitive to the layout of
404// struct ia64_sal_os_state in mca.h.
405//
406// r2 contains the return address, r3 contains either
407// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET.
408//
409// The OS to SAL section of struct ia64_sal_os_state is set to a default
410// value of cold boot (MCA) or warm boot (INIT) and return to the same
411// context. ia64_sal_os_state is also used to hold some registers that
412// need to be saved and restored across the stack switches.
413//
414// Most input registers to this stub come from PAL/SAL
415// r1 os gp, physical
416// r8 pal_proc entry point
417// r9 sal_proc entry point
418// r10 sal gp
419// r11 MCA - rendevzous state, INIT - reason code
420// r12 sal return address
421// r17 pal min_state
422// r18 processor state parameter
423// r19 monarch flag, set by the caller of this routine
424//
425// In addition to the SAL to OS state, this routine saves all the
426// registers that appear in struct pt_regs and struct switch_stack,
427// excluding those that are already in the PAL minstate area. This
428// results in a partial pt_regs and switch_stack, the C code copies the
429// remaining registers from PAL minstate to pt_regs and switch_stack. The
430// resulting structures contain all the state of the original process when
431// MCA/INIT occurred.
1da177e4
LT
432//
433//--
434
7f613c7d
KO
435ia64_state_save:
436 add regs=MCA_SOS_OFFSET, r3
437 add ms=MCA_SOS_OFFSET+8, r3
438 mov b0=r2 // save return address
439 cmp.eq p1,p2=IA64_MCA_CPU_MCA_STACK_OFFSET, r3
440 ;;
441 GET_IA64_MCA_DATA(temp2)
442 ;;
443 add temp1=temp2, regs // struct ia64_sal_os_state on MCA or INIT stack
444 add temp2=temp2, ms // struct ia64_sal_os_state+8 on MCA or INIT stack
445 ;;
446 mov regs=temp1 // save the start of sos
447 st8 [temp1]=r1,16 // os_gp
448 st8 [temp2]=r8,16 // pal_proc
449 ;;
450 st8 [temp1]=r9,16 // sal_proc
451 st8 [temp2]=r11,16 // rv_rc
452 mov r11=cr.iipa
453 ;;
d270acbc
KO
454 st8 [temp1]=r18 // proc_state_param
455 st8 [temp2]=r19 // monarch
7f613c7d 456 mov r6=IA64_KR(CURRENT)
d270acbc
KO
457 add temp1=SOS(SAL_RA), regs
458 add temp2=SOS(SAL_GP), regs
7f613c7d
KO
459 ;;
460 st8 [temp1]=r12,16 // sal_ra
461 st8 [temp2]=r10,16 // sal_gp
462 mov r12=cr.isr
463 ;;
464 st8 [temp1]=r17,16 // pal_min_state
465 st8 [temp2]=r6,16 // prev_IA64_KR_CURRENT
20bb8685
KO
466 mov r6=IA64_KR(CURRENT_STACK)
467 ;;
468 st8 [temp1]=r6,16 // prev_IA64_KR_CURRENT_STACK
469 st8 [temp2]=r0,16 // prev_task, starts off as NULL
7f613c7d
KO
470 mov r6=cr.ifa
471 ;;
20bb8685
KO
472 st8 [temp1]=r12,16 // cr.isr
473 st8 [temp2]=r6,16 // cr.ifa
7f613c7d
KO
474 mov r12=cr.itir
475 ;;
20bb8685
KO
476 st8 [temp1]=r12,16 // cr.itir
477 st8 [temp2]=r11,16 // cr.iipa
7f613c7d
KO
478 mov r12=cr.iim
479 ;;
d270acbc 480 st8 [temp1]=r12 // cr.iim
7f613c7d
KO
481(p1) mov r12=IA64_MCA_COLD_BOOT
482(p2) mov r12=IA64_INIT_WARM_BOOT
20bb8685 483 mov r6=cr.iha
d270acbc 484 add temp1=SOS(OS_STATUS), regs
7f613c7d 485 ;;
d270acbc
KO
486 st8 [temp2]=r6 // cr.iha
487 add temp2=SOS(CONTEXT), regs
20bb8685 488 st8 [temp1]=r12 // os_status, default is cold boot
7f613c7d
KO
489 mov r6=IA64_MCA_SAME_CONTEXT
490 ;;
2a792058 491 st8 [temp2]=r6 // context, default is same context
7f613c7d
KO
492
493 // Save the pt_regs data that is not in minstate. The previous code
494 // left regs at sos.
495 add regs=MCA_PT_REGS_OFFSET-MCA_SOS_OFFSET, regs
496 ;;
497 add temp1=PT(B6), regs
498 mov temp3=b6
499 mov temp4=b7
500 add temp2=PT(B7), regs
501 ;;
502 st8 [temp1]=temp3,PT(AR_CSD)-PT(B6) // save b6
503 st8 [temp2]=temp4,PT(AR_SSD)-PT(B7) // save b7
504 mov temp3=ar.csd
505 mov temp4=ar.ssd
506 cover // must be last in group
1da177e4 507 ;;
7f613c7d
KO
508 st8 [temp1]=temp3,PT(AR_UNAT)-PT(AR_CSD) // save ar.csd
509 st8 [temp2]=temp4,PT(AR_PFS)-PT(AR_SSD) // save ar.ssd
510 mov temp3=ar.unat
511 mov temp4=ar.pfs
512 ;;
513 st8 [temp1]=temp3,PT(AR_RNAT)-PT(AR_UNAT) // save ar.unat
514 st8 [temp2]=temp4,PT(AR_BSPSTORE)-PT(AR_PFS) // save ar.pfs
515 mov temp3=ar.rnat
516 mov temp4=ar.bspstore
517 ;;
518 st8 [temp1]=temp3,PT(LOADRS)-PT(AR_RNAT) // save ar.rnat
519 st8 [temp2]=temp4,PT(AR_FPSR)-PT(AR_BSPSTORE) // save ar.bspstore
520 mov temp3=ar.bsp
521 ;;
522 sub temp3=temp3, temp4 // ar.bsp - ar.bspstore
523 mov temp4=ar.fpsr
524 ;;
525 shl temp3=temp3,16 // compute ar.rsc to be used for "loadrs"
526 ;;
527 st8 [temp1]=temp3,PT(AR_CCV)-PT(LOADRS) // save loadrs
528 st8 [temp2]=temp4,PT(F6)-PT(AR_FPSR) // save ar.fpsr
529 mov temp3=ar.ccv
530 ;;
531 st8 [temp1]=temp3,PT(F7)-PT(AR_CCV) // save ar.ccv
532 stf.spill [temp2]=f6,PT(F8)-PT(F6)
533 ;;
534 stf.spill [temp1]=f7,PT(F9)-PT(F7)
535 stf.spill [temp2]=f8,PT(F10)-PT(F8)
536 ;;
537 stf.spill [temp1]=f9,PT(F11)-PT(F9)
538 stf.spill [temp2]=f10
539 ;;
540 stf.spill [temp1]=f11
541
542 // Save the switch_stack data that is not in minstate nor pt_regs. The
543 // previous code left regs at pt_regs.
544 add regs=MCA_SWITCH_STACK_OFFSET-MCA_PT_REGS_OFFSET, regs
545 ;;
546 add temp1=SW(F2), regs
547 add temp2=SW(F3), regs
548 ;;
549 stf.spill [temp1]=f2,32
550 stf.spill [temp2]=f3,32
551 ;;
552 stf.spill [temp1]=f4,32
553 stf.spill [temp2]=f5,32
554 ;;
555 stf.spill [temp1]=f12,32
556 stf.spill [temp2]=f13,32
557 ;;
558 stf.spill [temp1]=f14,32
559 stf.spill [temp2]=f15,32
560 ;;
561 stf.spill [temp1]=f16,32
562 stf.spill [temp2]=f17,32
563 ;;
564 stf.spill [temp1]=f18,32
565 stf.spill [temp2]=f19,32
566 ;;
567 stf.spill [temp1]=f20,32
568 stf.spill [temp2]=f21,32
569 ;;
570 stf.spill [temp1]=f22,32
571 stf.spill [temp2]=f23,32
572 ;;
573 stf.spill [temp1]=f24,32
574 stf.spill [temp2]=f25,32
575 ;;
576 stf.spill [temp1]=f26,32
577 stf.spill [temp2]=f27,32
578 ;;
579 stf.spill [temp1]=f28,32
580 stf.spill [temp2]=f29,32
581 ;;
582 stf.spill [temp1]=f30,SW(B2)-SW(F30)
583 stf.spill [temp2]=f31,SW(B3)-SW(F31)
584 mov temp3=b2
585 mov temp4=b3
586 ;;
587 st8 [temp1]=temp3,16 // save b2
588 st8 [temp2]=temp4,16 // save b3
589 mov temp3=b4
590 mov temp4=b5
591 ;;
592 st8 [temp1]=temp3,SW(AR_LC)-SW(B4) // save b4
593 st8 [temp2]=temp4 // save b5
594 mov temp3=ar.lc
595 ;;
596 st8 [temp1]=temp3 // save ar.lc
597
598 // FIXME: Some proms are incorrectly accessing the minstate area as
599 // cached data. The C code uses region 6, uncached virtual. Ensure
600 // that there is no cache data lying around for the first 1K of the
601 // minstate area.
602 // Remove this code in September 2006, that gives platforms a year to
603 // fix their proms and get their customers updated.
604
605 add r1=32*1,r17
606 add r2=32*2,r17
607 add r3=32*3,r17
608 add r4=32*4,r17
609 add r5=32*5,r17
610 add r6=32*6,r17
611 add r7=32*7,r17
612 ;;
613 fc r17
614 fc r1
615 fc r2
616 fc r3
617 fc r4
618 fc r5
619 fc r6
620 fc r7
621 add r17=32*8,r17
622 add r1=32*8,r1
623 add r2=32*8,r2
624 add r3=32*8,r3
625 add r4=32*8,r4
626 add r5=32*8,r5
627 add r6=32*8,r6
628 add r7=32*8,r7
629 ;;
630 fc r17
631 fc r1
632 fc r2
633 fc r3
634 fc r4
635 fc r5
636 fc r6
637 fc r7
638 add r17=32*8,r17
639 add r1=32*8,r1
640 add r2=32*8,r2
641 add r3=32*8,r3
642 add r4=32*8,r4
643 add r5=32*8,r5
644 add r6=32*8,r6
645 add r7=32*8,r7
646 ;;
647 fc r17
648 fc r1
649 fc r2
650 fc r3
651 fc r4
652 fc r5
653 fc r6
654 fc r7
655 add r17=32*8,r17
656 add r1=32*8,r1
657 add r2=32*8,r2
658 add r3=32*8,r3
659 add r4=32*8,r4
660 add r5=32*8,r5
661 add r6=32*8,r6
662 add r7=32*8,r7
663 ;;
664 fc r17
665 fc r1
666 fc r2
667 fc r3
668 fc r4
669 fc r5
670 fc r6
671 fc r7
672
673 br.sptk b0
1da177e4
LT
674
675//EndStub//////////////////////////////////////////////////////////////////////
676
677
678//++
679// Name:
7f613c7d 680// ia64_state_restore()
1da177e4
LT
681//
682// Stub Description:
683//
7f613c7d
KO
684// Restore the SAL/OS state. This is sensitive to the layout of struct
685// ia64_sal_os_state in mca.h.
686//
687// r2 contains the return address, r3 contains either
688// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET.
689//
690// In addition to the SAL to OS state, this routine restores all the
691// registers that appear in struct pt_regs and struct switch_stack,
692// excluding those in the PAL minstate area.
1da177e4
LT
693//
694//--
695
7f613c7d
KO
696ia64_state_restore:
697 // Restore the switch_stack data that is not in minstate nor pt_regs.
698 add regs=MCA_SWITCH_STACK_OFFSET, r3
699 mov b0=r2 // save return address
700 ;;
701 GET_IA64_MCA_DATA(temp2)
702 ;;
703 add regs=temp2, regs
704 ;;
705 add temp1=SW(F2), regs
706 add temp2=SW(F3), regs
707 ;;
708 ldf.fill f2=[temp1],32
709 ldf.fill f3=[temp2],32
710 ;;
711 ldf.fill f4=[temp1],32
712 ldf.fill f5=[temp2],32
713 ;;
714 ldf.fill f12=[temp1],32
715 ldf.fill f13=[temp2],32
716 ;;
717 ldf.fill f14=[temp1],32
718 ldf.fill f15=[temp2],32
719 ;;
720 ldf.fill f16=[temp1],32
721 ldf.fill f17=[temp2],32
722 ;;
723 ldf.fill f18=[temp1],32
724 ldf.fill f19=[temp2],32
725 ;;
726 ldf.fill f20=[temp1],32
727 ldf.fill f21=[temp2],32
728 ;;
729 ldf.fill f22=[temp1],32
730 ldf.fill f23=[temp2],32
731 ;;
732 ldf.fill f24=[temp1],32
733 ldf.fill f25=[temp2],32
734 ;;
735 ldf.fill f26=[temp1],32
736 ldf.fill f27=[temp2],32
737 ;;
738 ldf.fill f28=[temp1],32
739 ldf.fill f29=[temp2],32
740 ;;
741 ldf.fill f30=[temp1],SW(B2)-SW(F30)
742 ldf.fill f31=[temp2],SW(B3)-SW(F31)
743 ;;
744 ld8 temp3=[temp1],16 // restore b2
745 ld8 temp4=[temp2],16 // restore b3
746 ;;
747 mov b2=temp3
748 mov b3=temp4
749 ld8 temp3=[temp1],SW(AR_LC)-SW(B4) // restore b4
750 ld8 temp4=[temp2] // restore b5
751 ;;
752 mov b4=temp3
753 mov b5=temp4
754 ld8 temp3=[temp1] // restore ar.lc
755 ;;
756 mov ar.lc=temp3
1da177e4 757
7f613c7d
KO
758 // Restore the pt_regs data that is not in minstate. The previous code
759 // left regs at switch_stack.
760 add regs=MCA_PT_REGS_OFFSET-MCA_SWITCH_STACK_OFFSET, regs
761 ;;
762 add temp1=PT(B6), regs
763 add temp2=PT(B7), regs
764 ;;
765 ld8 temp3=[temp1],PT(AR_CSD)-PT(B6) // restore b6
766 ld8 temp4=[temp2],PT(AR_SSD)-PT(B7) // restore b7
767 ;;
768 mov b6=temp3
769 mov b7=temp4
770 ld8 temp3=[temp1],PT(AR_UNAT)-PT(AR_CSD) // restore ar.csd
771 ld8 temp4=[temp2],PT(AR_PFS)-PT(AR_SSD) // restore ar.ssd
772 ;;
773 mov ar.csd=temp3
774 mov ar.ssd=temp4
775 ld8 temp3=[temp1] // restore ar.unat
776 add temp1=PT(AR_CCV)-PT(AR_UNAT), temp1
777 ld8 temp4=[temp2],PT(AR_FPSR)-PT(AR_PFS) // restore ar.pfs
778 ;;
779 mov ar.unat=temp3
780 mov ar.pfs=temp4
781 // ar.rnat, ar.bspstore, loadrs are restore in ia64_old_stack.
782 ld8 temp3=[temp1],PT(F6)-PT(AR_CCV) // restore ar.ccv
783 ld8 temp4=[temp2],PT(F7)-PT(AR_FPSR) // restore ar.fpsr
784 ;;
785 mov ar.ccv=temp3
786 mov ar.fpsr=temp4
787 ldf.fill f6=[temp1],PT(F8)-PT(F6)
788 ldf.fill f7=[temp2],PT(F9)-PT(F7)
789 ;;
790 ldf.fill f8=[temp1],PT(F10)-PT(F8)
791 ldf.fill f9=[temp2],PT(F11)-PT(F9)
792 ;;
793 ldf.fill f10=[temp1]
794 ldf.fill f11=[temp2]
795
796 // Restore the SAL to OS state. The previous code left regs at pt_regs.
797 add regs=MCA_SOS_OFFSET-MCA_PT_REGS_OFFSET, regs
1da177e4 798 ;;
d270acbc
KO
799 add temp1=SOS(SAL_RA), regs
800 add temp2=SOS(SAL_GP), regs
7f613c7d
KO
801 ;;
802 ld8 r12=[temp1],16 // sal_ra
803 ld8 r9=[temp2],16 // sal_gp
804 ;;
20bb8685 805 ld8 r22=[temp1],16 // pal_min_state, virtual
8cab7ccc 806 ld8 r13=[temp2],16 // prev_IA64_KR_CURRENT
7f613c7d 807 ;;
20bb8685
KO
808 ld8 r16=[temp1],16 // prev_IA64_KR_CURRENT_STACK
809 ld8 r20=[temp2],16 // prev_task
810 ;;
7f613c7d
KO
811 ld8 temp3=[temp1],16 // cr.isr
812 ld8 temp4=[temp2],16 // cr.ifa
813 ;;
814 mov cr.isr=temp3
815 mov cr.ifa=temp4
816 ld8 temp3=[temp1],16 // cr.itir
817 ld8 temp4=[temp2],16 // cr.iipa
818 ;;
819 mov cr.itir=temp3
820 mov cr.iipa=temp4
d270acbc
KO
821 ld8 temp3=[temp1] // cr.iim
822 ld8 temp4=[temp2] // cr.iha
823 add temp1=SOS(OS_STATUS), regs
824 add temp2=SOS(CONTEXT), regs
7f613c7d
KO
825 ;;
826 mov cr.iim=temp3
827 mov cr.iha=temp4
8a4b7b6f 828 dep r22=0,r22,62,1 // pal_min_state, physical, uncached
8cab7ccc 829 mov IA64_KR(CURRENT)=r13
7f613c7d
KO
830 ld8 r8=[temp1] // os_status
831 ld8 r10=[temp2] // context
832
20bb8685
KO
833 /* Wire IA64_TR_CURRENT_STACK to the stack that we are resuming to. To
834 * avoid any dependencies on the algorithm in ia64_switch_to(), just
835 * purge any existing CURRENT_STACK mapping and insert the new one.
836 *
8cab7ccc 837 * r16 contains prev_IA64_KR_CURRENT_STACK, r13 contains
20bb8685
KO
838 * prev_IA64_KR_CURRENT, these values may have been changed by the C
839 * code. Do not use r8, r9, r10, r22, they contain values ready for
840 * the return to SAL.
841 */
842
843 mov r15=IA64_KR(CURRENT_STACK) // physical granule mapped by IA64_TR_CURRENT_STACK
844 ;;
845 shl r15=r15,IA64_GRANULE_SHIFT
846 ;;
847 dep r15=-1,r15,61,3 // virtual granule
848 mov r18=IA64_GRANULE_SHIFT<<2 // for cr.itir.ps
849 ;;
850 ptr.d r15,r18
851 ;;
852 srlz.d
853
8cab7ccc 854 extr.u r19=r13,61,3 // r13 = prev_IA64_KR_CURRENT
20bb8685
KO
855 shl r20=r16,IA64_GRANULE_SHIFT // r16 = prev_IA64_KR_CURRENT_STACK
856 movl r21=PAGE_KERNEL // page properties
857 ;;
858 mov IA64_KR(CURRENT_STACK)=r16
859 cmp.ne p6,p0=RGN_KERNEL,r19 // new stack is in the kernel region?
860 or r21=r20,r21 // construct PA | page properties
861(p6) br.spnt 1f // the dreaded cpu 0 idle task in region 5:(
862 ;;
863 mov cr.itir=r18
8cab7ccc 864 mov cr.ifa=r13
20bb8685
KO
865 mov r20=IA64_TR_CURRENT_STACK
866 ;;
867 itr.d dtr[r20]=r21
868 ;;
869 srlz.d
8701:
871
7f613c7d 872 br.sptk b0
1da177e4
LT
873
874//EndStub//////////////////////////////////////////////////////////////////////
875
876
7f613c7d
KO
877//++
878// Name:
879// ia64_new_stack()
1da177e4 880//
7f613c7d 881// Stub Description:
1da177e4 882//
7f613c7d 883// Switch to the MCA/INIT stack.
1da177e4 884//
7f613c7d
KO
885// r2 contains the return address, r3 contains either
886// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET.
1da177e4 887//
7f613c7d
KO
888// On entry RBS is still on the original stack, this routine switches RBS
889// to use the MCA/INIT stack.
1da177e4 890//
7f613c7d
KO
891// On entry, sos->pal_min_state is physical, on exit it is virtual.
892//
893//--
1da177e4 894
7f613c7d
KO
895ia64_new_stack:
896 add regs=MCA_PT_REGS_OFFSET, r3
d270acbc 897 add temp2=MCA_SOS_OFFSET+SOS(PAL_MIN_STATE), r3
7f613c7d
KO
898 mov b0=r2 // save return address
899 GET_IA64_MCA_DATA(temp1)
900 invala
1da177e4 901 ;;
7f613c7d
KO
902 add temp2=temp2, temp1 // struct ia64_sal_os_state.pal_min_state on MCA or INIT stack
903 add regs=regs, temp1 // struct pt_regs on MCA or INIT stack
1da177e4 904 ;;
7f613c7d
KO
905 // Address of minstate area provided by PAL is physical, uncacheable.
906 // Convert to Linux virtual address in region 6 for C code.
907 ld8 ms=[temp2] // pal_min_state, physical
1da177e4 908 ;;
7f613c7d
KO
909 dep temp1=-1,ms,62,2 // set region 6
910 mov temp3=IA64_RBS_OFFSET-MCA_PT_REGS_OFFSET
911 ;;
912 st8 [temp2]=temp1 // pal_min_state, virtual
1da177e4 913
7f613c7d 914 add temp4=temp3, regs // start of bspstore on new stack
1da177e4 915 ;;
7f613c7d 916 mov ar.bspstore=temp4 // switch RBS to MCA/INIT stack
1da177e4 917 ;;
7f613c7d
KO
918 flushrs // must be first in group
919 br.sptk b0
920
921//EndStub//////////////////////////////////////////////////////////////////////
922
923
924//++
925// Name:
926// ia64_old_stack()
927//
928// Stub Description:
929//
930// Switch to the old stack.
931//
932// r2 contains the return address, r3 contains either
933// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET.
934//
935// On entry, pal_min_state is virtual, on exit it is physical.
936//
937// On entry RBS is on the MCA/INIT stack, this routine switches RBS
938// back to the previous stack.
939//
940// The psr is set to all zeroes. SAL return requires either all zeroes or
941// just psr.mc set. Leaving psr.mc off allows INIT to be issued if this
942// code does not perform correctly.
943//
944// The dirty registers at the time of the event were flushed to the
945// MCA/INIT stack in ia64_pt_regs_save(). Restore the dirty registers
946// before reverting to the previous bspstore.
947//--
948
949ia64_old_stack:
950 add regs=MCA_PT_REGS_OFFSET, r3
951 mov b0=r2 // save return address
952 GET_IA64_MCA_DATA(temp2)
953 LOAD_PHYSICAL(p0,temp1,1f)
1da177e4 954 ;;
7f613c7d
KO
955 mov cr.ipsr=r0
956 mov cr.ifs=r0
957 mov cr.iip=temp1
1da177e4 958 ;;
7f613c7d 959 invala
1da177e4 960 rfi
7f613c7d
KO
9611:
962
963 add regs=regs, temp2 // struct pt_regs on MCA or INIT stack
1da177e4 964 ;;
7f613c7d 965 add temp1=PT(LOADRS), regs
1da177e4 966 ;;
7f613c7d 967 ld8 temp2=[temp1],PT(AR_BSPSTORE)-PT(LOADRS) // restore loadrs
1da177e4 968 ;;
7f613c7d
KO
969 ld8 temp3=[temp1],PT(AR_RNAT)-PT(AR_BSPSTORE) // restore ar.bspstore
970 mov ar.rsc=temp2
971 ;;
972 loadrs
973 ld8 temp4=[temp1] // restore ar.rnat
974 ;;
975 mov ar.bspstore=temp3 // back to old stack
976 ;;
977 mov ar.rnat=temp4
978 ;;
979
980 br.sptk b0
1da177e4 981
7f613c7d 982//EndStub//////////////////////////////////////////////////////////////////////
1da177e4 983
1da177e4 984
7f613c7d
KO
985//++
986// Name:
987// ia64_set_kernel_registers()
1da177e4 988//
7f613c7d
KO
989// Stub Description:
990//
991// Set the registers that are required by the C code in order to run on an
992// MCA/INIT stack.
993//
994// r2 contains the return address, r3 contains either
995// IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET.
1da177e4 996//
7f613c7d
KO
997//--
998
999ia64_set_kernel_registers:
1000 add temp3=MCA_SP_OFFSET, r3
7f613c7d
KO
1001 mov b0=r2 // save return address
1002 GET_IA64_MCA_DATA(temp1)
1003 ;;
7f613c7d
KO
1004 add r12=temp1, temp3 // kernel stack pointer on MCA/INIT stack
1005 add r13=temp1, r3 // set current to start of MCA/INIT stack
20bb8685 1006 add r20=temp1, r3 // physical start of MCA/INIT stack
7f613c7d 1007 ;;
7f613c7d
KO
1008 DATA_PA_TO_VA(r12,temp2)
1009 DATA_PA_TO_VA(r13,temp3)
1010 ;;
1011 mov IA64_KR(CURRENT)=r13
1012
20bb8685
KO
1013 /* Wire IA64_TR_CURRENT_STACK to the MCA/INIT handler stack. To avoid
1014 * any dependencies on the algorithm in ia64_switch_to(), just purge
1015 * any existing CURRENT_STACK mapping and insert the new one.
1016 */
1017
1018 mov r16=IA64_KR(CURRENT_STACK) // physical granule mapped by IA64_TR_CURRENT_STACK
1019 ;;
1020 shl r16=r16,IA64_GRANULE_SHIFT
1021 ;;
1022 dep r16=-1,r16,61,3 // virtual granule
1023 mov r18=IA64_GRANULE_SHIFT<<2 // for cr.itir.ps
1024 ;;
1025 ptr.d r16,r18
1026 ;;
1027 srlz.d
1028
1029 shr.u r16=r20,IA64_GRANULE_SHIFT // r20 = physical start of MCA/INIT stack
1030 movl r21=PAGE_KERNEL // page properties
1031 ;;
1032 mov IA64_KR(CURRENT_STACK)=r16
1033 or r21=r20,r21 // construct PA | page properties
1034 ;;
1035 mov cr.itir=r18
1036 mov cr.ifa=r13
1037 mov r20=IA64_TR_CURRENT_STACK
8f9e1467
RA
1038
1039 movl r17=FPSR_DEFAULT
1040 ;;
1041 mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value
20bb8685
KO
1042 ;;
1043 itr.d dtr[r20]=r21
1044 ;;
1045 srlz.d
7f613c7d
KO
1046
1047 br.sptk b0
1048
1049//EndStub//////////////////////////////////////////////////////////////////////
1050
1051#undef ms
1052#undef regs
1053#undef temp1
1054#undef temp2
1055#undef temp3
1056#undef temp4
1057
1da177e4 1058
7f613c7d
KO
1059// Support function for mca.c, it is here to avoid using inline asm. Given the
1060// address of an rnat slot, if that address is below the current ar.bspstore
1061// then return the contents of that slot, otherwise return the contents of
1062// ar.rnat.
1063GLOBAL_ENTRY(ia64_get_rnat)
1064 alloc r14=ar.pfs,1,0,0,0
1065 mov ar.rsc=0
1066 ;;
1067 mov r14=ar.bspstore
1068 ;;
1069 cmp.lt p6,p7=in0,r14
1070 ;;
1071(p6) ld8 r8=[in0]
1072(p7) mov r8=ar.rnat
1073 mov ar.rsc=3
1074 br.ret.sptk.many rp
1075END(ia64_get_rnat)
This page took 0.395386 seconds and 5 git commands to generate.