xref: /openbmc/linux/arch/ia64/kernel/mca_asm.S (revision c537b994)
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	// 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	;;
135	// Now branch away to caller.
136	br.sptk.many b1
137	;;
138
139//EndMain//////////////////////////////////////////////////////////////////////
140
141//StartMain////////////////////////////////////////////////////////////////////
142
143ia64_os_mca_dispatch:
144	// Serialize all MCA processing
145	mov	r3=1;;
146	LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);;
147ia64_os_mca_spin:
148	xchg4	r4=[r2],r3;;
149	cmp.ne	p6,p0=r4,r0
150(p6)	br ia64_os_mca_spin
151
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:
157
158	GET_IA64_MCA_DATA(r2)
159	// Using MCA stack, struct ia64_sal_os_state, variable proc_state_param
160	;;
161	add r3=IA64_MCA_CPU_MCA_STACK_OFFSET+MCA_SOS_OFFSET+SOS(PROC_STATE_PARAM), r2
162	;;
163	ld8 r18=[r3]				// Get processor state parameter on existing PALE_CHECK.
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:
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
252
253done_tlb_purge_and_reload:
254
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:
266
267	// This must be done in physical mode
268	GET_IA64_MCA_DATA(r2)
269	;;
270	mov r7=r2
271
272        // Enter virtual mode from physical mode
273	VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
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	;;
287
288	// Call virtual mode handler
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
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
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
362	GET_IA64_MCA_DATA(r2)
363	;;
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
380	;;
381
382	// Call virtual mode handler
383	alloc r14=ar.pfs,0,0,3,0
384	;;
385	DATA_PA_TO_VA(r2,r7)
386	;;
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
391
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:
395
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:
402
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
411	br		b0
412
413//EndMain//////////////////////////////////////////////////////////////////////
414
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
423
424//++
425// Name:
426//	ia64_state_save()
427//
428// Stub Description:
429//
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.
459//
460//--
461
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	;;
481	st8 [temp1]=r18		// proc_state_param
482	st8 [temp2]=r19		// monarch
483	mov r6=IA64_KR(CURRENT)
484	add temp1=SOS(SAL_RA), regs
485	add temp2=SOS(SAL_GP), regs
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
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
497	mov r6=cr.ifa
498	;;
499	st8 [temp1]=r12,16	// cr.isr
500	st8 [temp2]=r6,16	// cr.ifa
501	mov r12=cr.itir
502	;;
503	st8 [temp1]=r12,16	// cr.itir
504	st8 [temp2]=r11,16	// cr.iipa
505	mov r12=cr.iim
506	;;
507	st8 [temp1]=r12		// cr.iim
508(p1)	mov r12=IA64_MCA_COLD_BOOT
509(p2)	mov r12=IA64_INIT_WARM_BOOT
510	mov r6=cr.iha
511	add temp1=SOS(OS_STATUS), regs
512	;;
513	st8 [temp2]=r6		// cr.iha
514	add temp2=SOS(CONTEXT), regs
515	st8 [temp1]=r12		// os_status, default is cold boot
516	mov r6=IA64_MCA_SAME_CONTEXT
517	;;
518	st8 [temp2]=r6		// context, default is same context
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
534	;;
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
701
702//EndStub//////////////////////////////////////////////////////////////////////
703
704
705//++
706// Name:
707//	ia64_state_restore()
708//
709// Stub Description:
710//
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.
720//
721//--
722
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
784
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
825	;;
826	add temp1=SOS(SAL_RA), regs
827	add temp2=SOS(SAL_GP), regs
828	;;
829	ld8 r12=[temp1],16	// sal_ra
830	ld8 r9=[temp2],16	// sal_gp
831	;;
832	ld8 r22=[temp1],16	// pal_min_state, virtual
833	ld8 r13=[temp2],16	// prev_IA64_KR_CURRENT
834	;;
835	ld8 r16=[temp1],16	// prev_IA64_KR_CURRENT_STACK
836	ld8 r20=[temp2],16	// prev_task
837	;;
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
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
852	;;
853	mov cr.iim=temp3
854	mov cr.iha=temp4
855	dep r22=0,r22,62,1	// pal_min_state, physical, uncached
856	mov IA64_KR(CURRENT)=r13
857	ld8 r8=[temp1]		// os_status
858	ld8 r10=[temp2]		// context
859
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	 *
864	 * r16 contains prev_IA64_KR_CURRENT_STACK, r13 contains
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
881	extr.u r19=r13,61,3			// r13 = prev_IA64_KR_CURRENT
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
891	mov cr.ifa=r13
892	mov r20=IA64_TR_CURRENT_STACK
893	;;
894	itr.d dtr[r20]=r21
895	;;
896	srlz.d
8971:
898
899	br.sptk b0
900
901//EndStub//////////////////////////////////////////////////////////////////////
902
903
904//++
905// Name:
906//	ia64_new_stack()
907//
908// Stub Description:
909//
910//	Switch to the MCA/INIT stack.
911//
912//	r2 contains the return address, r3 contains either
913//	IA64_MCA_CPU_MCA_STACK_OFFSET or IA64_MCA_CPU_INIT_STACK_OFFSET.
914//
915//	On entry RBS is still on the original stack, this routine switches RBS
916//	to use the MCA/INIT stack.
917//
918//	On entry, sos->pal_min_state is physical, on exit it is virtual.
919//
920//--
921
922ia64_new_stack:
923	add regs=MCA_PT_REGS_OFFSET, r3
924	add temp2=MCA_SOS_OFFSET+SOS(PAL_MIN_STATE), r3
925	mov b0=r2			// save return address
926	GET_IA64_MCA_DATA(temp1)
927	invala
928	;;
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
931	;;
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
935	;;
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
940
941	add temp4=temp3, regs		// start of bspstore on new stack
942	;;
943	mov ar.bspstore=temp4		// switch RBS to MCA/INIT stack
944	;;
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)
981	;;
982	mov cr.ipsr=r0
983	mov cr.ifs=r0
984	mov cr.iip=temp1
985	;;
986	invala
987	rfi
9881:
989
990	add regs=regs, temp2		// struct pt_regs on MCA or INIT stack
991	;;
992	add temp1=PT(LOADRS), regs
993	;;
994	ld8 temp2=[temp1],PT(AR_BSPSTORE)-PT(LOADRS)	// restore loadrs
995	;;
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
1008
1009//EndStub//////////////////////////////////////////////////////////////////////
1010
1011
1012//++
1013// Name:
1014//	ia64_set_kernel_registers()
1015//
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.
1023//
1024//--
1025
1026ia64_set_kernel_registers:
1027	add temp3=MCA_SP_OFFSET, r3
1028	mov b0=r2		// save return address
1029	GET_IA64_MCA_DATA(temp1)
1030	;;
1031	add r12=temp1, temp3	// kernel stack pointer on MCA/INIT stack
1032	add r13=temp1, r3	// set current to start of MCA/INIT stack
1033	add r20=temp1, r3	// physical start of MCA/INIT stack
1034	;;
1035	DATA_PA_TO_VA(r12,temp2)
1036	DATA_PA_TO_VA(r13,temp3)
1037	;;
1038	mov IA64_KR(CURRENT)=r13
1039
1040	/* Wire IA64_TR_CURRENT_STACK to the MCA/INIT handler stack.  To avoid
1041	 * any dependencies on the algorithm in ia64_switch_to(), just purge
1042	 * any existing CURRENT_STACK mapping and insert the new one.
1043	 */
1044
1045	mov r16=IA64_KR(CURRENT_STACK)		// physical granule mapped by IA64_TR_CURRENT_STACK
1046	;;
1047	shl r16=r16,IA64_GRANULE_SHIFT
1048	;;
1049	dep r16=-1,r16,61,3			// virtual granule
1050	mov r18=IA64_GRANULE_SHIFT<<2		// for cr.itir.ps
1051	;;
1052	ptr.d r16,r18
1053	;;
1054	srlz.d
1055
1056	shr.u r16=r20,IA64_GRANULE_SHIFT	// r20 = physical start of MCA/INIT stack
1057	movl r21=PAGE_KERNEL			// page properties
1058	;;
1059	mov IA64_KR(CURRENT_STACK)=r16
1060	or r21=r20,r21				// construct PA | page properties
1061	;;
1062	mov cr.itir=r18
1063	mov cr.ifa=r13
1064	mov r20=IA64_TR_CURRENT_STACK
1065
1066	movl r17=FPSR_DEFAULT
1067	;;
1068	mov.m ar.fpsr=r17			// set ar.fpsr to kernel default value
1069	;;
1070	itr.d dtr[r20]=r21
1071	;;
1072	srlz.d
1073
1074	br.sptk b0
1075
1076//EndStub//////////////////////////////////////////////////////////////////////
1077
1078#undef	ms
1079#undef	regs
1080#undef	temp1
1081#undef	temp2
1082#undef	temp3
1083#undef	temp4
1084
1085
1086// Support function for mca.c, it is here to avoid using inline asm.  Given the
1087// address of an rnat slot, if that address is below the current ar.bspstore
1088// then return the contents of that slot, otherwise return the contents of
1089// ar.rnat.
1090GLOBAL_ENTRY(ia64_get_rnat)
1091	alloc r14=ar.pfs,1,0,0,0
1092	mov ar.rsc=0
1093	;;
1094	mov r14=ar.bspstore
1095	;;
1096	cmp.lt p6,p7=in0,r14
1097	;;
1098(p6)	ld8 r8=[in0]
1099(p7)	mov r8=ar.rnat
1100	mov ar.rsc=3
1101	br.ret.sptk.many rp
1102END(ia64_get_rnat)
1103