]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * S390 version | |
3 | * Copyright IBM Corp. 1999 | |
4 | * Author(s): Hartmut Penner (hp@de.ibm.com), | |
5 | * Martin Schwidefsky (schwidefsky@de.ibm.com) | |
6 | * | |
7 | * Derived from "include/asm-i386/processor.h" | |
8 | * Copyright (C) 1994, Linus Torvalds | |
9 | */ | |
10 | ||
11 | #ifndef __ASM_S390_PROCESSOR_H | |
12 | #define __ASM_S390_PROCESSOR_H | |
13 | ||
14 | #include <linux/const.h> | |
15 | ||
16 | #define CIF_MCCK_PENDING 0 /* machine check handling is pending */ | |
17 | #define CIF_ASCE 1 /* user asce needs fixup / uaccess */ | |
18 | #define CIF_NOHZ_DELAY 2 /* delay HZ disable for a tick */ | |
19 | #define CIF_FPU 3 /* restore FPU registers */ | |
20 | #define CIF_IGNORE_IRQ 4 /* ignore interrupt (for udelay) */ | |
21 | #define CIF_ENABLED_WAIT 5 /* in enabled wait state */ | |
22 | ||
23 | #define _CIF_MCCK_PENDING _BITUL(CIF_MCCK_PENDING) | |
24 | #define _CIF_ASCE _BITUL(CIF_ASCE) | |
25 | #define _CIF_NOHZ_DELAY _BITUL(CIF_NOHZ_DELAY) | |
26 | #define _CIF_FPU _BITUL(CIF_FPU) | |
27 | #define _CIF_IGNORE_IRQ _BITUL(CIF_IGNORE_IRQ) | |
28 | #define _CIF_ENABLED_WAIT _BITUL(CIF_ENABLED_WAIT) | |
29 | ||
30 | #ifndef __ASSEMBLY__ | |
31 | ||
32 | #include <linux/linkage.h> | |
33 | #include <linux/irqflags.h> | |
34 | #include <asm/cpu.h> | |
35 | #include <asm/page.h> | |
36 | #include <asm/ptrace.h> | |
37 | #include <asm/setup.h> | |
38 | #include <asm/runtime_instr.h> | |
39 | #include <asm/fpu/types.h> | |
40 | #include <asm/fpu/internal.h> | |
41 | ||
42 | static inline void set_cpu_flag(int flag) | |
43 | { | |
44 | S390_lowcore.cpu_flags |= (1UL << flag); | |
45 | } | |
46 | ||
47 | static inline void clear_cpu_flag(int flag) | |
48 | { | |
49 | S390_lowcore.cpu_flags &= ~(1UL << flag); | |
50 | } | |
51 | ||
52 | static inline int test_cpu_flag(int flag) | |
53 | { | |
54 | return !!(S390_lowcore.cpu_flags & (1UL << flag)); | |
55 | } | |
56 | ||
57 | /* | |
58 | * Test CIF flag of another CPU. The caller needs to ensure that | |
59 | * CPU hotplug can not happen, e.g. by disabling preemption. | |
60 | */ | |
61 | static inline int test_cpu_flag_of(int flag, int cpu) | |
62 | { | |
63 | struct lowcore *lc = lowcore_ptr[cpu]; | |
64 | return !!(lc->cpu_flags & (1UL << flag)); | |
65 | } | |
66 | ||
67 | #define arch_needs_cpu() test_cpu_flag(CIF_NOHZ_DELAY) | |
68 | ||
69 | /* | |
70 | * Default implementation of macro that returns current | |
71 | * instruction pointer ("program counter"). | |
72 | */ | |
73 | #define current_text_addr() ({ void *pc; asm("basr %0,0" : "=a" (pc)); pc; }) | |
74 | ||
75 | static inline void get_cpu_id(struct cpuid *ptr) | |
76 | { | |
77 | asm volatile("stidp %0" : "=Q" (*ptr)); | |
78 | } | |
79 | ||
80 | void s390_adjust_jiffies(void); | |
81 | void s390_update_cpu_mhz(void); | |
82 | void cpu_detect_mhz_feature(void); | |
83 | ||
84 | extern const struct seq_operations cpuinfo_op; | |
85 | extern int sysctl_ieee_emulation_warnings; | |
86 | extern void execve_tail(void); | |
87 | ||
88 | /* | |
89 | * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. | |
90 | */ | |
91 | ||
92 | #define TASK_SIZE_OF(tsk) ((tsk)->mm ? \ | |
93 | (tsk)->mm->context.asce_limit : TASK_MAX_SIZE) | |
94 | #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ | |
95 | (1UL << 30) : (1UL << 41)) | |
96 | #define TASK_SIZE TASK_SIZE_OF(current) | |
97 | #define TASK_MAX_SIZE (1UL << 53) | |
98 | ||
99 | #define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:42)) | |
100 | #define STACK_TOP_MAX (1UL << 42) | |
101 | ||
102 | #define HAVE_ARCH_PICK_MMAP_LAYOUT | |
103 | ||
104 | typedef struct { | |
105 | __u32 ar4; | |
106 | } mm_segment_t; | |
107 | ||
108 | /* | |
109 | * Thread structure | |
110 | */ | |
111 | struct thread_struct { | |
112 | unsigned int acrs[NUM_ACRS]; | |
113 | unsigned long ksp; /* kernel stack pointer */ | |
114 | unsigned long user_timer; /* task cputime in user space */ | |
115 | unsigned long system_timer; /* task cputime in kernel space */ | |
116 | unsigned long sys_call_table; /* system call table address */ | |
117 | mm_segment_t mm_segment; | |
118 | unsigned long gmap_addr; /* address of last gmap fault. */ | |
119 | unsigned int gmap_write_flag; /* gmap fault write indication */ | |
120 | unsigned int gmap_int_code; /* int code of last gmap fault */ | |
121 | unsigned int gmap_pfault; /* signal of a pending guest pfault */ | |
122 | /* Per-thread information related to debugging */ | |
123 | struct per_regs per_user; /* User specified PER registers */ | |
124 | struct per_event per_event; /* Cause of the last PER trap */ | |
125 | unsigned long per_flags; /* Flags to control debug behavior */ | |
126 | unsigned int system_call; /* system call number in signal */ | |
127 | unsigned long last_break; /* last breaking-event-address. */ | |
128 | /* pfault_wait is used to block the process on a pfault event */ | |
129 | unsigned long pfault_wait; | |
130 | struct list_head list; | |
131 | /* cpu runtime instrumentation */ | |
132 | struct runtime_instr_cb *ri_cb; | |
133 | unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ | |
134 | /* | |
135 | * Warning: 'fpu' is dynamically-sized. It *MUST* be at | |
136 | * the end. | |
137 | */ | |
138 | struct fpu fpu; /* FP and VX register save area */ | |
139 | }; | |
140 | ||
141 | /* Flag to disable transactions. */ | |
142 | #define PER_FLAG_NO_TE 1UL | |
143 | /* Flag to enable random transaction aborts. */ | |
144 | #define PER_FLAG_TE_ABORT_RAND 2UL | |
145 | /* Flag to specify random transaction abort mode: | |
146 | * - abort each transaction at a random instruction before TEND if set. | |
147 | * - abort random transactions at a random instruction if cleared. | |
148 | */ | |
149 | #define PER_FLAG_TE_ABORT_RAND_TEND 4UL | |
150 | ||
151 | typedef struct thread_struct thread_struct; | |
152 | ||
153 | /* | |
154 | * Stack layout of a C stack frame. | |
155 | */ | |
156 | #ifndef __PACK_STACK | |
157 | struct stack_frame { | |
158 | unsigned long back_chain; | |
159 | unsigned long empty1[5]; | |
160 | unsigned long gprs[10]; | |
161 | unsigned int empty2[8]; | |
162 | }; | |
163 | #else | |
164 | struct stack_frame { | |
165 | unsigned long empty1[5]; | |
166 | unsigned int empty2[8]; | |
167 | unsigned long gprs[10]; | |
168 | unsigned long back_chain; | |
169 | }; | |
170 | #endif | |
171 | ||
172 | #define ARCH_MIN_TASKALIGN 8 | |
173 | ||
174 | #define INIT_THREAD { \ | |
175 | .ksp = sizeof(init_stack) + (unsigned long) &init_stack, \ | |
176 | .fpu.regs = (void *) init_task.thread.fpu.fprs, \ | |
177 | } | |
178 | ||
179 | /* | |
180 | * Do necessary setup to start up a new thread. | |
181 | */ | |
182 | #define start_thread(regs, new_psw, new_stackp) do { \ | |
183 | regs->psw.mask = PSW_USER_BITS | PSW_MASK_EA | PSW_MASK_BA; \ | |
184 | regs->psw.addr = new_psw; \ | |
185 | regs->gprs[15] = new_stackp; \ | |
186 | execve_tail(); \ | |
187 | } while (0) | |
188 | ||
189 | #define start_thread31(regs, new_psw, new_stackp) do { \ | |
190 | regs->psw.mask = PSW_USER_BITS | PSW_MASK_BA; \ | |
191 | regs->psw.addr = new_psw; \ | |
192 | regs->gprs[15] = new_stackp; \ | |
193 | crst_table_downgrade(current->mm); \ | |
194 | execve_tail(); \ | |
195 | } while (0) | |
196 | ||
197 | /* Forward declaration, a strange C thing */ | |
198 | struct task_struct; | |
199 | struct mm_struct; | |
200 | struct seq_file; | |
201 | ||
202 | typedef int (*dump_trace_func_t)(void *data, unsigned long address, int reliable); | |
203 | void dump_trace(dump_trace_func_t func, void *data, | |
204 | struct task_struct *task, unsigned long sp); | |
205 | ||
206 | void show_cacheinfo(struct seq_file *m); | |
207 | ||
208 | /* Free all resources held by a thread. */ | |
209 | extern void release_thread(struct task_struct *); | |
210 | ||
211 | /* | |
212 | * Return saved PC of a blocked thread. | |
213 | */ | |
214 | extern unsigned long thread_saved_pc(struct task_struct *t); | |
215 | ||
216 | unsigned long get_wchan(struct task_struct *p); | |
217 | #define task_pt_regs(tsk) ((struct pt_regs *) \ | |
218 | (task_stack_page(tsk) + THREAD_SIZE) - 1) | |
219 | #define KSTK_EIP(tsk) (task_pt_regs(tsk)->psw.addr) | |
220 | #define KSTK_ESP(tsk) (task_pt_regs(tsk)->gprs[15]) | |
221 | ||
222 | /* Has task runtime instrumentation enabled ? */ | |
223 | #define is_ri_task(tsk) (!!(tsk)->thread.ri_cb) | |
224 | ||
225 | static inline unsigned long current_stack_pointer(void) | |
226 | { | |
227 | unsigned long sp; | |
228 | ||
229 | asm volatile("la %0,0(15)" : "=a" (sp)); | |
230 | return sp; | |
231 | } | |
232 | ||
233 | static inline unsigned short stap(void) | |
234 | { | |
235 | unsigned short cpu_address; | |
236 | ||
237 | asm volatile("stap %0" : "=m" (cpu_address)); | |
238 | return cpu_address; | |
239 | } | |
240 | ||
241 | /* | |
242 | * Give up the time slice of the virtual PU. | |
243 | */ | |
244 | #define cpu_relax_yield cpu_relax_yield | |
245 | void cpu_relax_yield(void); | |
246 | ||
247 | #define cpu_relax() barrier() | |
248 | ||
249 | #define ECAG_CACHE_ATTRIBUTE 0 | |
250 | #define ECAG_CPU_ATTRIBUTE 1 | |
251 | ||
252 | static inline unsigned long __ecag(unsigned int asi, unsigned char parm) | |
253 | { | |
254 | unsigned long val; | |
255 | ||
256 | asm volatile(".insn rsy,0xeb000000004c,%0,0,0(%1)" /* ecag */ | |
257 | : "=d" (val) : "a" (asi << 8 | parm)); | |
258 | return val; | |
259 | } | |
260 | ||
261 | static inline void psw_set_key(unsigned int key) | |
262 | { | |
263 | asm volatile("spka 0(%0)" : : "d" (key)); | |
264 | } | |
265 | ||
266 | /* | |
267 | * Set PSW to specified value. | |
268 | */ | |
269 | static inline void __load_psw(psw_t psw) | |
270 | { | |
271 | asm volatile("lpswe %0" : : "Q" (psw) : "cc"); | |
272 | } | |
273 | ||
274 | /* | |
275 | * Set PSW mask to specified value, while leaving the | |
276 | * PSW addr pointing to the next instruction. | |
277 | */ | |
278 | static inline void __load_psw_mask(unsigned long mask) | |
279 | { | |
280 | unsigned long addr; | |
281 | psw_t psw; | |
282 | ||
283 | psw.mask = mask; | |
284 | ||
285 | asm volatile( | |
286 | " larl %0,1f\n" | |
287 | " stg %0,%O1+8(%R1)\n" | |
288 | " lpswe %1\n" | |
289 | "1:" | |
290 | : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); | |
291 | } | |
292 | ||
293 | /* | |
294 | * Extract current PSW mask | |
295 | */ | |
296 | static inline unsigned long __extract_psw(void) | |
297 | { | |
298 | unsigned int reg1, reg2; | |
299 | ||
300 | asm volatile("epsw %0,%1" : "=d" (reg1), "=a" (reg2)); | |
301 | return (((unsigned long) reg1) << 32) | ((unsigned long) reg2); | |
302 | } | |
303 | ||
304 | static inline void local_mcck_enable(void) | |
305 | { | |
306 | __load_psw_mask(__extract_psw() | PSW_MASK_MCHECK); | |
307 | } | |
308 | ||
309 | static inline void local_mcck_disable(void) | |
310 | { | |
311 | __load_psw_mask(__extract_psw() & ~PSW_MASK_MCHECK); | |
312 | } | |
313 | ||
314 | /* | |
315 | * Rewind PSW instruction address by specified number of bytes. | |
316 | */ | |
317 | static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc) | |
318 | { | |
319 | unsigned long mask; | |
320 | ||
321 | mask = (psw.mask & PSW_MASK_EA) ? -1UL : | |
322 | (psw.mask & PSW_MASK_BA) ? (1UL << 31) - 1 : | |
323 | (1UL << 24) - 1; | |
324 | return (psw.addr - ilc) & mask; | |
325 | } | |
326 | ||
327 | /* | |
328 | * Function to stop a processor until the next interrupt occurs | |
329 | */ | |
330 | void enabled_wait(void); | |
331 | ||
332 | /* | |
333 | * Function to drop a processor into disabled wait state | |
334 | */ | |
335 | static inline void __noreturn disabled_wait(unsigned long code) | |
336 | { | |
337 | psw_t psw; | |
338 | ||
339 | psw.mask = PSW_MASK_BASE | PSW_MASK_WAIT | PSW_MASK_BA | PSW_MASK_EA; | |
340 | psw.addr = code; | |
341 | __load_psw(psw); | |
342 | while (1); | |
343 | } | |
344 | ||
345 | /* | |
346 | * Basic Machine Check/Program Check Handler. | |
347 | */ | |
348 | ||
349 | extern void s390_base_mcck_handler(void); | |
350 | extern void s390_base_pgm_handler(void); | |
351 | extern void s390_base_ext_handler(void); | |
352 | ||
353 | extern void (*s390_base_mcck_handler_fn)(void); | |
354 | extern void (*s390_base_pgm_handler_fn)(void); | |
355 | extern void (*s390_base_ext_handler_fn)(void); | |
356 | ||
357 | #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL | |
358 | ||
359 | extern int memcpy_real(void *, void *, size_t); | |
360 | extern void memcpy_absolute(void *, void *, size_t); | |
361 | ||
362 | #define mem_assign_absolute(dest, val) { \ | |
363 | __typeof__(dest) __tmp = (val); \ | |
364 | \ | |
365 | BUILD_BUG_ON(sizeof(__tmp) != sizeof(val)); \ | |
366 | memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ | |
367 | } | |
368 | ||
369 | #endif /* __ASSEMBLY__ */ | |
370 | ||
371 | #endif /* __ASM_S390_PROCESSOR_H */ |