| 1 |
|
| 2 | |
| 3 | * S390 version
|
| 4 | * Copyright IBM Corp. 1999
|
| 5 | * Author(s): Hartmut Penner ([email protected]),
|
| 6 | * Martin Schwidefsky ([email protected])
|
| 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 |
|
| 15 | #include <linux/bits.h>
|
| 16 |
|
| 17 | #define CIF_ENABLED_WAIT 5
|
| 18 | #define CIF_MCCK_GUEST 6
|
| 19 | #define CIF_DEDICATED_CPU 7
|
| 20 |
|
| 21 | #define _CIF_ENABLED_WAIT BIT(CIF_ENABLED_WAIT)
|
| 22 | #define _CIF_MCCK_GUEST BIT(CIF_MCCK_GUEST)
|
| 23 | #define _CIF_DEDICATED_CPU BIT(CIF_DEDICATED_CPU)
|
| 24 |
|
| 25 | #define RESTART_FLAG_CTLREGS _AC(1 << 0, U)
|
| 26 |
|
| 27 | #ifndef __ASSEMBLER__
|
| 28 |
|
| 29 | #include <linux/cpumask.h>
|
| 30 | #include <linux/linkage.h>
|
| 31 | #include <linux/irqflags.h>
|
| 32 | #include <linux/instruction_pointer.h>
|
| 33 | #include <linux/bitops.h>
|
| 34 | #include <asm/vdso/processor.h>
|
| 35 | #include <asm/fpu-types.h>
|
| 36 | #include <asm/cpu.h>
|
| 37 | #include <asm/page.h>
|
| 38 | #include <asm/ptrace.h>
|
| 39 | #include <asm/setup.h>
|
| 40 | #include <asm/runtime_instr.h>
|
| 41 | #include <asm/irqflags.h>
|
| 42 | #include <asm/alternative.h>
|
| 43 | #include <asm/fault.h>
|
| 44 |
|
| 45 | struct pcpu {
|
| 46 | unsigned long ec_mask;
|
| 47 | unsigned long ec_clk;
|
| 48 | unsigned long flags;
|
| 49 | signed char state;
|
| 50 | signed char polarization;
|
| 51 | u16 address;
|
| 52 | };
|
| 53 |
|
| 54 | DECLARE_PER_CPU(struct pcpu, pcpu_devices);
|
| 55 |
|
| 56 | typedef long (*sys_call_ptr_t)(struct pt_regs *regs);
|
| 57 |
|
| 58 | static __always_inline struct pcpu *this_pcpu(void)
|
| 59 | {
|
| 60 | return (struct pcpu *)(get_lowcore()->pcpu);
|
| 61 | }
|
| 62 |
|
| 63 | static __always_inline void set_cpu_flag(int flag)
|
| 64 | {
|
| 65 | set_bit(flag, &this_pcpu()->flags);
|
| 66 | }
|
| 67 |
|
| 68 | static __always_inline void clear_cpu_flag(int flag)
|
| 69 | {
|
| 70 | clear_bit(flag, &this_pcpu()->flags);
|
| 71 | }
|
| 72 |
|
| 73 | static __always_inline bool test_cpu_flag(int flag)
|
| 74 | {
|
| 75 | return test_bit(flag, &this_pcpu()->flags);
|
| 76 | }
|
| 77 |
|
| 78 | static __always_inline bool test_and_set_cpu_flag(int flag)
|
| 79 | {
|
| 80 | return test_and_set_bit(flag, &this_pcpu()->flags);
|
| 81 | }
|
| 82 |
|
| 83 | static __always_inline bool test_and_clear_cpu_flag(int flag)
|
| 84 | {
|
| 85 | return test_and_clear_bit(flag, &this_pcpu()->flags);
|
| 86 | }
|
| 87 |
|
| 88 | |
| 89 | * Test CIF flag of another CPU. The caller needs to ensure that
|
| 90 | * CPU hotplug can not happen, e.g. by disabling preemption.
|
| 91 |
|
| 92 | static __always_inline bool test_cpu_flag_of(int flag, int cpu)
|
| 93 | {
|
| 94 | return test_bit(flag, &per_cpu(pcpu_devices, cpu).flags);
|
| 95 | }
|
| 96 |
|
| 97 | static inline void get_cpu_id(struct cpuid *ptr)
|
| 98 | {
|
| 99 | asm volatile("stidp %0" : "=Q" (*ptr));
|
| 100 | }
|
| 101 |
|
| 102 | static __always_inline unsigned long get_cpu_timer(void)
|
| 103 | {
|
| 104 | unsigned long timer;
|
| 105 |
|
| 106 | asm volatile("stpt %[timer]" : [timer] "=Q" (timer));
|
| 107 | return timer;
|
| 108 | }
|
| 109 |
|
| 110 | void s390_adjust_jiffies(void);
|
| 111 | void s390_update_cpu_mhz(void);
|
| 112 | void cpu_detect_mhz_feature(void);
|
| 113 |
|
| 114 | extern const struct seq_operations cpuinfo_op;
|
| 115 | extern void execve_tail(void);
|
| 116 | unsigned long vdso_text_size(void);
|
| 117 | unsigned long vdso_size(void);
|
| 118 |
|
| 119 | #define TASK_SIZE (TASK_SIZE_MAX)
|
| 120 | #define TASK_UNMAPPED_BASE (_REGION2_SIZE >> 1)
|
| 121 | #define TASK_SIZE_MAX (-PAGE_SIZE)
|
| 122 |
|
| 123 | #define VDSO_BASE (STACK_TOP + PAGE_SIZE)
|
| 124 | #define VDSO_LIMIT (_REGION2_SIZE)
|
| 125 | #define STACK_TOP (VDSO_LIMIT - vdso_size() - PAGE_SIZE)
|
| 126 | #define STACK_TOP_MAX (_REGION2_SIZE - vdso_size() - PAGE_SIZE)
|
| 127 |
|
| 128 | #define HAVE_ARCH_PICK_MMAP_LAYOUT
|
| 129 |
|
| 130 | #define __stackleak_poison __stackleak_poison
|
| 131 | static __always_inline void __stackleak_poison(unsigned long erase_low,
|
| 132 | unsigned long erase_high,
|
| 133 | unsigned long poison)
|
| 134 | {
|
| 135 | unsigned long tmp, count;
|
| 136 |
|
| 137 | count = erase_high - erase_low;
|
| 138 | if (!count)
|
| 139 | return;
|
| 140 | asm volatile(
|
| 141 | " cghi %[count],8\n"
|
| 142 | " je 2f\n"
|
| 143 | " aghi %[count],-(8+1)\n"
|
| 144 | " srlg %[tmp],%[count],8\n"
|
| 145 | " ltgr %[tmp],%[tmp]\n"
|
| 146 | " jz 1f\n"
|
| 147 | "0: stg %[poison],0(%[addr])\n"
|
| 148 | " mvc 8(256-8,%[addr]),0(%[addr])\n"
|
| 149 | " la %[addr],256(%[addr])\n"
|
| 150 | " brctg %[tmp],0b\n"
|
| 151 | "1: stg %[poison],0(%[addr])\n"
|
| 152 | " exrl %[count],3f\n"
|
| 153 | " j 4f\n"
|
| 154 | "2: stg %[poison],0(%[addr])\n"
|
| 155 | " j 4f\n"
|
| 156 | "3: mvc 8(1,%[addr]),0(%[addr])\n"
|
| 157 | "4:"
|
| 158 | : [addr] "+&a" (erase_low), [count] "+&a" (count), [tmp] "=&a" (tmp)
|
| 159 | : [poison] "d" (poison)
|
| 160 | : "memory", "cc"
|
| 161 | );
|
| 162 | }
|
| 163 |
|
| 164 | |
| 165 | * Thread structure
|
| 166 |
|
| 167 | struct thread_struct {
|
| 168 | unsigned int acrs[NUM_ACRS];
|
| 169 | unsigned long ksp;
|
| 170 | unsigned long user_timer;
|
| 171 | unsigned long guest_timer;
|
| 172 | unsigned long system_timer;
|
| 173 | unsigned long hardirq_timer;
|
| 174 | unsigned long softirq_timer;
|
| 175 | union teid gmap_teid;
|
| 176 | unsigned int gmap_int_code;
|
| 177 | int ufpu_flags;
|
| 178 | int kfpu_flags;
|
| 179 |
|
| 180 |
|
| 181 | struct per_regs per_user;
|
| 182 | struct per_event per_event;
|
| 183 | unsigned long per_flags;
|
| 184 | unsigned int system_call;
|
| 185 | unsigned long last_break;
|
| 186 |
|
| 187 | unsigned long pfault_wait;
|
| 188 | struct list_head list;
|
| 189 |
|
| 190 | struct runtime_instr_cb *ri_cb;
|
| 191 | struct gs_cb *gs_cb;
|
| 192 | struct gs_cb *gs_bc_cb;
|
| 193 | struct pgm_tdb trap_tdb;
|
| 194 | struct fpu ufpu;
|
| 195 | struct fpu kfpu;
|
| 196 | };
|
| 197 |
|
| 198 |
|
| 199 | #define PER_FLAG_NO_TE 1UL
|
| 200 |
|
| 201 | #define PER_FLAG_TE_ABORT_RAND 2UL
|
| 202 | |
| 203 | * - abort each transaction at a random instruction before TEND if set.
|
| 204 | * - abort random transactions at a random instruction if cleared.
|
| 205 |
|
| 206 | #define PER_FLAG_TE_ABORT_RAND_TEND 4UL
|
| 207 |
|
| 208 | typedef struct thread_struct thread_struct;
|
| 209 |
|
| 210 | #define ARCH_MIN_TASKALIGN 8
|
| 211 |
|
| 212 | #define INIT_THREAD { \
|
| 213 | .ksp = sizeof(init_stack) + (unsigned long) &init_stack, \
|
| 214 | .last_break = 1, \
|
| 215 | }
|
| 216 |
|
| 217 | |
| 218 | * Do necessary setup to start up a new thread.
|
| 219 |
|
| 220 | #define start_thread(regs, new_psw, new_stackp) do { \
|
| 221 | regs->psw.mask = PSW_USER_BITS | PSW_MASK_EA | PSW_MASK_BA; \
|
| 222 | regs->psw.addr = new_psw; \
|
| 223 | regs->gprs[15] = new_stackp; \
|
| 224 | execve_tail(); \
|
| 225 | } while (0)
|
| 226 |
|
| 227 | #define start_thread31(regs, new_psw, new_stackp) do { \
|
| 228 | regs->psw.mask = PSW_USER_BITS | PSW_MASK_BA; \
|
| 229 | regs->psw.addr = new_psw; \
|
| 230 | regs->gprs[15] = new_stackp; \
|
| 231 | execve_tail(); \
|
| 232 | } while (0)
|
| 233 |
|
| 234 | struct task_struct;
|
| 235 | struct mm_struct;
|
| 236 | struct seq_file;
|
| 237 | struct pt_regs;
|
| 238 |
|
| 239 | void show_registers(struct pt_regs *regs);
|
| 240 | void show_cacheinfo(struct seq_file *m);
|
| 241 |
|
| 242 |
|
| 243 | void guarded_storage_release(struct task_struct *tsk);
|
| 244 | void gs_load_bc_cb(struct pt_regs *regs);
|
| 245 |
|
| 246 | unsigned long __get_wchan(struct task_struct *p);
|
| 247 | #define task_pt_regs(tsk) ((struct pt_regs *) \
|
| 248 | (task_stack_page(tsk) + THREAD_SIZE) - 1)
|
| 249 | #define KSTK_EIP(tsk) (task_pt_regs(tsk)->psw.addr)
|
| 250 | #define KSTK_ESP(tsk) (task_pt_regs(tsk)->gprs[15])
|
| 251 |
|
| 252 |
|
| 253 | #define is_ri_task(tsk) (!!(tsk)->thread.ri_cb)
|
| 254 |
|
| 255 |
|
| 256 | #define current_stack_pointer (__current_stack_pointer())
|
| 257 |
|
| 258 | static __always_inline unsigned long __current_stack_pointer(void)
|
| 259 | {
|
| 260 | unsigned long sp;
|
| 261 |
|
| 262 | asm volatile("lgr %0,15" : "=d" (sp));
|
| 263 | return sp;
|
| 264 | }
|
| 265 |
|
| 266 | static __always_inline bool on_thread_stack(void)
|
| 267 | {
|
| 268 | unsigned long ksp = get_lowcore()->kernel_stack;
|
| 269 |
|
| 270 | return !((ksp ^ current_stack_pointer) & ~(THREAD_SIZE - 1));
|
| 271 | }
|
| 272 |
|
| 273 | static __always_inline unsigned short stap(void)
|
| 274 | {
|
| 275 | unsigned short cpu_address;
|
| 276 |
|
| 277 | asm volatile("stap %0" : "=Q" (cpu_address));
|
| 278 | return cpu_address;
|
| 279 | }
|
| 280 |
|
| 281 | #define ECAG_CACHE_ATTRIBUTE 0
|
| 282 | #define ECAG_CPU_ATTRIBUTE 1
|
| 283 |
|
| 284 | static inline unsigned long __ecag(unsigned int asi, unsigned char parm)
|
| 285 | {
|
| 286 | unsigned long val;
|
| 287 |
|
| 288 | asm volatile("ecag %0,0,0(%1)" : "=d" (val) : "a" (asi << 8 | parm));
|
| 289 | return val;
|
| 290 | }
|
| 291 |
|
| 292 | static inline void psw_set_key(unsigned int key)
|
| 293 | {
|
| 294 | asm volatile("spka 0(%0)" : : "d" (key));
|
| 295 | }
|
| 296 |
|
| 297 | |
| 298 | * Set PSW to specified value.
|
| 299 |
|
| 300 | static inline void __load_psw(psw_t psw)
|
| 301 | {
|
| 302 | asm volatile("lpswe %0" : : "Q" (psw) : "cc");
|
| 303 | }
|
| 304 |
|
| 305 | |
| 306 | * Set PSW mask to specified value, while leaving the
|
| 307 | * PSW addr pointing to the next instruction.
|
| 308 |
|
| 309 | static __always_inline void __load_psw_mask(unsigned long mask)
|
| 310 | {
|
| 311 | psw_t psw __uninitialized;
|
| 312 | unsigned long addr;
|
| 313 |
|
| 314 | psw.mask = mask;
|
| 315 |
|
| 316 | asm volatile(
|
| 317 | " larl %0,1f\n"
|
| 318 | " stg %0,%1\n"
|
| 319 | " lpswe %2\n"
|
| 320 | "1:"
|
| 321 | : "=&d" (addr), "=Q" (psw.addr) : "Q" (psw) : "memory", "cc");
|
| 322 | }
|
| 323 |
|
| 324 | |
| 325 | * Extract current PSW mask
|
| 326 |
|
| 327 | static inline unsigned long __extract_psw(void)
|
| 328 | {
|
| 329 | unsigned int reg1, reg2;
|
| 330 |
|
| 331 | asm volatile("epsw %0,%1" : "=d" (reg1), "=a" (reg2));
|
| 332 | return (((unsigned long) reg1) << 32) | ((unsigned long) reg2);
|
| 333 | }
|
| 334 |
|
| 335 | static inline unsigned long __local_mcck_save(void)
|
| 336 | {
|
| 337 | unsigned long mask = __extract_psw();
|
| 338 |
|
| 339 | __load_psw_mask(mask & ~PSW_MASK_MCHECK);
|
| 340 | return mask & PSW_MASK_MCHECK;
|
| 341 | }
|
| 342 |
|
| 343 | #define local_mcck_save(mflags) \
|
| 344 | do { \
|
| 345 | typecheck(unsigned long, mflags); \
|
| 346 | mflags = __local_mcck_save(); \
|
| 347 | } while (0)
|
| 348 |
|
| 349 | static inline void local_mcck_restore(unsigned long mflags)
|
| 350 | {
|
| 351 | unsigned long mask = __extract_psw();
|
| 352 |
|
| 353 | mask &= ~PSW_MASK_MCHECK;
|
| 354 | __load_psw_mask(mask | mflags);
|
| 355 | }
|
| 356 |
|
| 357 | static inline void local_mcck_disable(void)
|
| 358 | {
|
| 359 | __local_mcck_save();
|
| 360 | }
|
| 361 |
|
| 362 | static inline void local_mcck_enable(void)
|
| 363 | {
|
| 364 | __load_psw_mask(__extract_psw() | PSW_MASK_MCHECK);
|
| 365 | }
|
| 366 |
|
| 367 | |
| 368 | * Rewind PSW instruction address by specified number of bytes.
|
| 369 |
|
| 370 | static inline unsigned long __rewind_psw(psw_t psw, long ilen)
|
| 371 | {
|
| 372 | unsigned long mask;
|
| 373 |
|
| 374 | mask = (psw.mask & PSW_MASK_EA) ? -1UL :
|
| 375 | (psw.mask & PSW_MASK_BA) ? (1UL << 31) - 1 :
|
| 376 | (1UL << 24) - 1;
|
| 377 | return (psw.addr - ilen) & mask;
|
| 378 | }
|
| 379 |
|
| 380 | static inline unsigned long __forward_psw(psw_t psw, long ilen)
|
| 381 | {
|
| 382 | return __rewind_psw(psw, -ilen);
|
| 383 | }
|
| 384 |
|
| 385 | |
| 386 | * Function to drop a processor into disabled wait state
|
| 387 |
|
| 388 | static __always_inline void __noreturn disabled_wait(void)
|
| 389 | {
|
| 390 | psw_t psw;
|
| 391 |
|
| 392 | psw.mask = PSW_MASK_BASE | PSW_MASK_WAIT | PSW_MASK_BA | PSW_MASK_EA;
|
| 393 | psw.addr = _THIS_IP_;
|
| 394 | __load_psw(psw);
|
| 395 | while (1);
|
| 396 | }
|
| 397 |
|
| 398 | #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL
|
| 399 |
|
| 400 | static __always_inline bool regs_irqs_disabled(struct pt_regs *regs)
|
| 401 | {
|
| 402 | return arch_irqs_disabled_flags(regs->psw.mask);
|
| 403 | }
|
| 404 |
|
| 405 | static __always_inline void bpon(void)
|
| 406 | {
|
| 407 | asm_inline volatile(
|
| 408 | ALTERNATIVE(" nop\n",
|
| 409 | " .insn rrf,0xb2e80000,0,0,13,0\n",
|
| 410 | ALT_SPEC(82))
|
| 411 | );
|
| 412 | }
|
| 413 |
|
| 414 | #endif
|
| 415 |
|
| 416 | #endif
|