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