Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mca_asm.h
Go to the documentation of this file.
1 /*
2  * File: mca_asm.h
3  * Purpose: Machine check handling specific defines
4  *
5  * Copyright (C) 1999 Silicon Graphics, Inc.
6  * Copyright (C) Vijay Chander <[email protected]>
7  * Copyright (C) Srinivasa Thirumalachar <[email protected]>
8  * Copyright (C) 2000 Hewlett-Packard Co.
9  * Copyright (C) 2000 David Mosberger-Tang <[email protected]>
10  * Copyright (C) 2002 Intel Corp.
11  * Copyright (C) 2002 Jenna Hall <[email protected]>
12  * Copyright (C) 2005 Silicon Graphics, Inc
13  * Copyright (C) 2005 Keith Owens <[email protected]>
14  */
15 #ifndef _ASM_IA64_MCA_ASM_H
16 #define _ASM_IA64_MCA_ASM_H
17 
18 #include <asm/percpu.h>
19 
20 #define PSR_IC 13
21 #define PSR_I 14
22 #define PSR_DT 17
23 #define PSR_RT 27
24 #define PSR_MC 35
25 #define PSR_IT 36
26 #define PSR_BN 44
27 
28 /*
29  * This macro converts a instruction virtual address to a physical address
30  * Right now for simulation purposes the virtual addresses are
31  * direct mapped to physical addresses.
32  * 1. Lop off bits 61 thru 63 in the virtual address
33  */
34 #define INST_VA_TO_PA(addr) \
35  dep addr = 0, addr, 61, 3
36 /*
37  * This macro converts a data virtual address to a physical address
38  * Right now for simulation purposes the virtual addresses are
39  * direct mapped to physical addresses.
40  * 1. Lop off bits 61 thru 63 in the virtual address
41  */
42 #define DATA_VA_TO_PA(addr) \
43  tpa addr = addr
44 /*
45  * This macro converts a data physical address to a virtual address
46  * Right now for simulation purposes the virtual addresses are
47  * direct mapped to physical addresses.
48  * 1. Put 0x7 in bits 61 thru 63.
49  */
50 #define DATA_PA_TO_VA(addr,temp) \
51  mov temp = 0x7 ;; \
52  dep addr = temp, addr, 61, 3
53 
54 #define GET_THIS_PADDR(reg, var) \
55  mov reg = IA64_KR(PER_CPU_DATA);; \
56  addl reg = THIS_CPU(var), reg
57 
58 /*
59  * This macro jumps to the instruction at the given virtual address
60  * and starts execution in physical mode with all the address
61  * translations turned off.
62  * 1. Save the current psr
63  * 2. Make sure that all the upper 32 bits are off
64  *
65  * 3. Clear the interrupt enable and interrupt state collection bits
66  * in the psr before updating the ipsr and iip.
67  *
68  * 4. Turn off the instruction, data and rse translation bits of the psr
69  * and store the new value into ipsr
70  * Also make sure that the interrupts are disabled.
71  * Ensure that we are in little endian mode.
72  * [psr.{rt, it, dt, i, be} = 0]
73  *
74  * 5. Get the physical address corresponding to the virtual address
75  * of the next instruction bundle and put it in iip.
76  * (Using magic numbers 24 and 40 in the deposint instruction since
77  * the IA64_SDK code directly maps to lower 24bits as physical address
78  * from a virtual address).
79  *
80  * 6. Do an rfi to move the values from ipsr to psr and iip to ip.
81  */
82 #define PHYSICAL_MODE_ENTER(temp1, temp2, start_addr, old_psr) \
83  mov old_psr = psr; \
84  ;; \
85  dep old_psr = 0, old_psr, 32, 32; \
86  \
87  mov ar.rsc = 0 ; \
88  ;; \
89  srlz.d; \
90  mov temp2 = ar.bspstore; \
91  ;; \
92  DATA_VA_TO_PA(temp2); \
93  ;; \
94  mov temp1 = ar.rnat; \
95  ;; \
96  mov ar.bspstore = temp2; \
97  ;; \
98  mov ar.rnat = temp1; \
99  mov temp1 = psr; \
100  mov temp2 = psr; \
101  ;; \
102  \
103  dep temp2 = 0, temp2, PSR_IC, 2; \
104  ;; \
105  mov psr.l = temp2; \
106  ;; \
107  srlz.d; \
108  dep temp1 = 0, temp1, 32, 32; \
109  ;; \
110  dep temp1 = 0, temp1, PSR_IT, 1; \
111  ;; \
112  dep temp1 = 0, temp1, PSR_DT, 1; \
113  ;; \
114  dep temp1 = 0, temp1, PSR_RT, 1; \
115  ;; \
116  dep temp1 = 0, temp1, PSR_I, 1; \
117  ;; \
118  dep temp1 = 0, temp1, PSR_IC, 1; \
119  ;; \
120  dep temp1 = -1, temp1, PSR_MC, 1; \
121  ;; \
122  mov cr.ipsr = temp1; \
123  ;; \
124  LOAD_PHYSICAL(p0, temp2, start_addr); \
125  ;; \
126  mov cr.iip = temp2; \
127  mov cr.ifs = r0; \
128  DATA_VA_TO_PA(sp); \
129  DATA_VA_TO_PA(gp); \
130  ;; \
131  srlz.i; \
132  ;; \
133  nop 1; \
134  nop 2; \
135  nop 1; \
136  nop 2; \
137  rfi; \
138  ;;
139 
140 /*
141  * This macro jumps to the instruction at the given virtual address
142  * and starts execution in virtual mode with all the address
143  * translations turned on.
144  * 1. Get the old saved psr
145  *
146  * 2. Clear the interrupt state collection bit in the current psr.
147  *
148  * 3. Set the instruction translation bit back in the old psr
149  * Note we have to do this since we are right now saving only the
150  * lower 32-bits of old psr.(Also the old psr has the data and
151  * rse translation bits on)
152  *
153  * 4. Set ipsr to this old_psr with "it" bit set and "bn" = 1.
154  *
155  * 5. Reset the current thread pointer (r13).
156  *
157  * 6. Set iip to the virtual address of the next instruction bundle.
158  *
159  * 7. Do an rfi to move ipsr to psr and iip to ip.
160  */
161 
162 #define VIRTUAL_MODE_ENTER(temp1, temp2, start_addr, old_psr) \
163  mov temp2 = psr; \
164  ;; \
165  mov old_psr = temp2; \
166  ;; \
167  dep temp2 = 0, temp2, PSR_IC, 2; \
168  ;; \
169  mov psr.l = temp2; \
170  mov ar.rsc = 0; \
171  ;; \
172  srlz.d; \
173  mov r13 = ar.k6; \
174  mov temp2 = ar.bspstore; \
175  ;; \
176  DATA_PA_TO_VA(temp2,temp1); \
177  ;; \
178  mov temp1 = ar.rnat; \
179  ;; \
180  mov ar.bspstore = temp2; \
181  ;; \
182  mov ar.rnat = temp1; \
183  ;; \
184  mov temp1 = old_psr; \
185  ;; \
186  mov temp2 = 1; \
187  ;; \
188  dep temp1 = temp2, temp1, PSR_IC, 1; \
189  ;; \
190  dep temp1 = temp2, temp1, PSR_IT, 1; \
191  ;; \
192  dep temp1 = temp2, temp1, PSR_DT, 1; \
193  ;; \
194  dep temp1 = temp2, temp1, PSR_RT, 1; \
195  ;; \
196  dep temp1 = temp2, temp1, PSR_BN, 1; \
197  ;; \
198  \
199  mov cr.ipsr = temp1; \
200  movl temp2 = start_addr; \
201  ;; \
202  mov cr.iip = temp2; \
203  movl gp = __gp \
204  ;; \
205  DATA_PA_TO_VA(sp, temp1); \
206  srlz.i; \
207  ;; \
208  nop 1; \
209  nop 2; \
210  nop 1; \
211  rfi \
212  ;;
213 
214 /*
215  * The MCA and INIT stacks in struct ia64_mca_cpu look like normal kernel
216  * stacks, except that the SAL/OS state and a switch_stack are stored near the
217  * top of the MCA/INIT stack. To support concurrent entry to MCA or INIT, as
218  * well as MCA over INIT, each event needs its own SAL/OS state. All entries
219  * are 16 byte aligned.
220  *
221  * +---------------------------+
222  * | pt_regs |
223  * +---------------------------+
224  * | switch_stack |
225  * +---------------------------+
226  * | SAL/OS state |
227  * +---------------------------+
228  * | 16 byte scratch area |
229  * +---------------------------+ <-------- SP at start of C MCA handler
230  * | ..... |
231  * +---------------------------+
232  * | RBS for MCA/INIT handler |
233  * +---------------------------+
234  * | struct task for MCA/INIT |
235  * +---------------------------+ <-------- Bottom of MCA/INIT stack
236  */
237 
238 #define ALIGN16(x) ((x)&~15)
239 #define MCA_PT_REGS_OFFSET ALIGN16(KERNEL_STACK_SIZE-IA64_PT_REGS_SIZE)
240 #define MCA_SWITCH_STACK_OFFSET ALIGN16(MCA_PT_REGS_OFFSET-IA64_SWITCH_STACK_SIZE)
241 #define MCA_SOS_OFFSET ALIGN16(MCA_SWITCH_STACK_OFFSET-IA64_SAL_OS_STATE_SIZE)
242 #define MCA_SP_OFFSET ALIGN16(MCA_SOS_OFFSET-16)
243 
244 #endif /* _ASM_IA64_MCA_ASM_H */