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