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