1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 #ifndef _ASM_POWERPC_INTERRUPT_H 3 #define _ASM_POWERPC_INTERRUPT_H 4 5 /* BookE/4xx */ 6 #define INTERRUPT_CRITICAL_INPUT 0x100 7 8 /* BookE */ 9 #define INTERRUPT_DEBUG 0xd00 10 #ifdef CONFIG_BOOKE 11 #define INTERRUPT_PERFMON 0x260 12 #define INTERRUPT_DOORBELL 0x280 13 #endif 14 15 /* BookS/4xx/8xx */ 16 #define INTERRUPT_MACHINE_CHECK 0x200 17 18 /* BookS/8xx */ 19 #define INTERRUPT_SYSTEM_RESET 0x100 20 21 /* BookS */ 22 #define INTERRUPT_DATA_SEGMENT 0x380 23 #define INTERRUPT_INST_SEGMENT 0x480 24 #define INTERRUPT_TRACE 0xd00 25 #define INTERRUPT_H_DATA_STORAGE 0xe00 26 #define INTERRUPT_HMI 0xe60 27 #define INTERRUPT_H_FAC_UNAVAIL 0xf80 28 #ifdef CONFIG_PPC_BOOK3S 29 #define INTERRUPT_DOORBELL 0xa00 30 #define INTERRUPT_PERFMON 0xf00 31 #define INTERRUPT_ALTIVEC_UNAVAIL 0xf20 32 #endif 33 34 /* BookE/BookS/4xx/8xx */ 35 #define INTERRUPT_DATA_STORAGE 0x300 36 #define INTERRUPT_INST_STORAGE 0x400 37 #define INTERRUPT_EXTERNAL 0x500 38 #define INTERRUPT_ALIGNMENT 0x600 39 #define INTERRUPT_PROGRAM 0x700 40 #define INTERRUPT_SYSCALL 0xc00 41 #define INTERRUPT_TRACE 0xd00 42 43 /* BookE/BookS/44x */ 44 #define INTERRUPT_FP_UNAVAIL 0x800 45 46 /* BookE/BookS/44x/8xx */ 47 #define INTERRUPT_DECREMENTER 0x900 48 49 #ifndef INTERRUPT_PERFMON 50 #define INTERRUPT_PERFMON 0x0 51 #endif 52 53 /* 8xx */ 54 #define INTERRUPT_SOFT_EMU_8xx 0x1000 55 #define INTERRUPT_INST_TLB_MISS_8xx 0x1100 56 #define INTERRUPT_DATA_TLB_MISS_8xx 0x1200 57 #define INTERRUPT_INST_TLB_ERROR_8xx 0x1300 58 #define INTERRUPT_DATA_TLB_ERROR_8xx 0x1400 59 #define INTERRUPT_DATA_BREAKPOINT_8xx 0x1c00 60 #define INTERRUPT_INST_BREAKPOINT_8xx 0x1d00 61 62 /* 603 */ 63 #define INTERRUPT_INST_TLB_MISS_603 0x1000 64 #define INTERRUPT_DATA_LOAD_TLB_MISS_603 0x1100 65 #define INTERRUPT_DATA_STORE_TLB_MISS_603 0x1200 66 67 #ifndef __ASSEMBLER__ 68 69 #include <linux/sched/debug.h> /* for show_regs */ 70 #include <linux/irq-entry-common.h> 71 72 #include <asm/kprobes.h> 73 #include <asm/runlatch.h> 74 75 #ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG 76 /* 77 * WARN/BUG is handled with a program interrupt so minimise checks here to 78 * avoid recursion and maximise the chance of getting the first oops handled. 79 */ 80 #define INT_SOFT_MASK_BUG_ON(regs, cond) \ 81 do { \ 82 if ((user_mode(regs) || (TRAP(regs) != INTERRUPT_PROGRAM))) \ 83 BUG_ON(cond); \ 84 } while (0) 85 #else 86 #define INT_SOFT_MASK_BUG_ON(regs, cond) 87 #endif 88 89 /* 90 * Don't use noinstr here like x86, but rather add NOKPROBE_SYMBOL to each 91 * function definition. The reason for this is the noinstr section is placed 92 * after the main text section, i.e., very far away from the interrupt entry 93 * asm. That creates problems with fitting linker stubs when building large 94 * kernels. 95 */ 96 #define interrupt_handler __visible noinline notrace __no_kcsan __no_sanitize_address 97 98 /** 99 * DECLARE_INTERRUPT_HANDLER_RAW - Declare raw interrupt handler function 100 * @func: Function name of the entry point 101 * @returns: Returns a value back to asm caller 102 */ 103 #define DECLARE_INTERRUPT_HANDLER_RAW(func) \ 104 __visible long func(struct pt_regs *regs) 105 106 /** 107 * DEFINE_INTERRUPT_HANDLER_RAW - Define raw interrupt handler function 108 * @func: Function name of the entry point 109 * @returns: Returns a value back to asm caller 110 * 111 * @func is called from ASM entry code. 112 * 113 * This is a plain function which does no tracing, reconciling, etc. 114 * The macro is written so it acts as function definition. Append the 115 * body with a pair of curly brackets. 116 * 117 * raw interrupt handlers must not enable or disable interrupts, or 118 * schedule, tracing and instrumentation (ftrace, lockdep, etc) would 119 * not be advisable either, although may be possible in a pinch, the 120 * trace will look odd at least. 121 * 122 * A raw handler may call one of the other interrupt handler functions 123 * to be converted into that interrupt context without these restrictions. 124 * 125 * On PPC64, _RAW handlers may return with fast_interrupt_return. 126 * 127 * Specific handlers may have additional restrictions. 128 */ 129 #define DEFINE_INTERRUPT_HANDLER_RAW(func) \ 130 static __always_inline __no_sanitize_address __no_kcsan long \ 131 ____##func(struct pt_regs *regs); \ 132 \ 133 interrupt_handler long func(struct pt_regs *regs) \ 134 { \ 135 long ret; \ 136 \ 137 __hard_RI_enable(); \ 138 \ 139 ret = ____##func (regs); \ 140 \ 141 return ret; \ 142 } \ 143 NOKPROBE_SYMBOL(func); \ 144 \ 145 static __always_inline __no_sanitize_address __no_kcsan long \ 146 ____##func(struct pt_regs *regs) 147 148 /** 149 * DECLARE_INTERRUPT_HANDLER - Declare synchronous interrupt handler function 150 * @func: Function name of the entry point 151 */ 152 #define DECLARE_INTERRUPT_HANDLER(func) \ 153 __visible void func(struct pt_regs *regs) 154 155 /** 156 * DEFINE_INTERRUPT_HANDLER - Define synchronous interrupt handler function 157 * @func: Function name of the entry point 158 * 159 * @func is called from ASM entry code. 160 * 161 * The macro is written so it acts as function definition. Append the 162 * body with a pair of curly brackets. 163 */ 164 #define DEFINE_INTERRUPT_HANDLER(func) \ 165 static __always_inline void ____##func(struct pt_regs *regs); \ 166 \ 167 interrupt_handler void func(struct pt_regs *regs) \ 168 { \ 169 irqentry_state_t state; \ 170 arch_interrupt_enter_prepare(regs); \ 171 state = irqentry_enter(regs); \ 172 instrumentation_begin(); \ 173 ____##func (regs); \ 174 instrumentation_end(); \ 175 arch_interrupt_exit_prepare(regs); \ 176 irqentry_exit(regs, state); \ 177 } \ 178 NOKPROBE_SYMBOL(func); \ 179 \ 180 static __always_inline void ____##func(struct pt_regs *regs) 181 182 /** 183 * DECLARE_INTERRUPT_HANDLER_RET - Declare synchronous interrupt handler function 184 * @func: Function name of the entry point 185 * @returns: Returns a value back to asm caller 186 */ 187 #define DECLARE_INTERRUPT_HANDLER_RET(func) \ 188 __visible long func(struct pt_regs *regs) 189 190 /** 191 * DEFINE_INTERRUPT_HANDLER_RET - Define synchronous interrupt handler function 192 * @func: Function name of the entry point 193 * @returns: Returns a value back to asm caller 194 * 195 * @func is called from ASM entry code. 196 * 197 * The macro is written so it acts as function definition. Append the 198 * body with a pair of curly brackets. 199 */ 200 #define DEFINE_INTERRUPT_HANDLER_RET(func) \ 201 static __always_inline long ____##func(struct pt_regs *regs); \ 202 \ 203 interrupt_handler long func(struct pt_regs *regs) \ 204 { \ 205 long ret; \ 206 irqentry_state_t state; \ 207 \ 208 arch_interrupt_enter_prepare(regs); \ 209 state = irqentry_enter(regs); \ 210 instrumentation_begin(); \ 211 ret = ____##func (regs); \ 212 instrumentation_end(); \ 213 arch_interrupt_exit_prepare(regs); \ 214 irqentry_exit(regs, state); \ 215 \ 216 return ret; \ 217 } \ 218 NOKPROBE_SYMBOL(func); \ 219 \ 220 static __always_inline long ____##func(struct pt_regs *regs) 221 222 /** 223 * DECLARE_INTERRUPT_HANDLER_ASYNC - Declare asynchronous interrupt handler function 224 * @func: Function name of the entry point 225 */ 226 #define DECLARE_INTERRUPT_HANDLER_ASYNC(func) \ 227 __visible void func(struct pt_regs *regs) 228 229 /** 230 * DEFINE_INTERRUPT_HANDLER_ASYNC - Define asynchronous interrupt handler function 231 * @func: Function name of the entry point 232 * 233 * @func is called from ASM entry code. 234 * 235 * The macro is written so it acts as function definition. Append the 236 * body with a pair of curly brackets. 237 */ 238 #define DEFINE_INTERRUPT_HANDLER_ASYNC(func) \ 239 static __always_inline void ____##func(struct pt_regs *regs); \ 240 \ 241 interrupt_handler void func(struct pt_regs *regs) \ 242 { \ 243 irqentry_state_t state; \ 244 arch_interrupt_async_enter_prepare(regs); \ 245 state = irqentry_enter(regs); \ 246 instrumentation_begin(); \ 247 irq_enter_rcu(); \ 248 ____##func (regs); \ 249 irq_exit_rcu(); \ 250 instrumentation_end(); \ 251 arch_interrupt_async_exit_prepare(regs); \ 252 irqentry_exit(regs, state); \ 253 } \ 254 NOKPROBE_SYMBOL(func); \ 255 \ 256 static __always_inline void ____##func(struct pt_regs *regs) 257 258 /** 259 * DECLARE_INTERRUPT_HANDLER_NMI - Declare NMI interrupt handler function 260 * @func: Function name of the entry point 261 * @returns: Returns a value back to asm caller 262 */ 263 #define DECLARE_INTERRUPT_HANDLER_NMI(func) \ 264 __visible long func(struct pt_regs *regs) 265 266 /** 267 * DEFINE_INTERRUPT_HANDLER_NMI - Define NMI interrupt handler function 268 * @func: Function name of the entry point 269 * @returns: Returns a value back to asm caller 270 * 271 * @func is called from ASM entry code. 272 * 273 * The macro is written so it acts as function definition. Append the 274 * body with a pair of curly brackets. 275 */ 276 #define DEFINE_INTERRUPT_HANDLER_NMI(func) \ 277 static __always_inline __no_sanitize_address __no_kcsan long \ 278 ____##func(struct pt_regs *regs); \ 279 \ 280 interrupt_handler long func(struct pt_regs *regs) \ 281 { \ 282 irqentry_state_t state; \ 283 struct interrupt_nmi_state nmi_state; \ 284 long ret; \ 285 \ 286 arch_interrupt_nmi_enter_prepare(regs, &nmi_state); \ 287 if (mfmsr() & MSR_DR) { \ 288 /* nmi_entry if relocations are on */ \ 289 state = irqentry_nmi_enter(regs); \ 290 } else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && \ 291 firmware_has_feature(FW_FEATURE_LPAR) && \ 292 !radix_enabled()) { \ 293 /* no nmi_entry for a pseries hash guest \ 294 * taking a real mode exception */ \ 295 } else if (IS_ENABLED(CONFIG_KASAN)) { \ 296 /* no nmi_entry for KASAN in real mode */ \ 297 } else if (percpu_first_chunk_is_paged) { \ 298 /* no nmi_entry if percpu first chunk is not embedded */\ 299 } else { \ 300 state = irqentry_nmi_enter(regs); \ 301 } \ 302 ret = ____##func (regs); \ 303 arch_interrupt_nmi_exit_prepare(regs, &nmi_state); \ 304 if (mfmsr() & MSR_DR) { \ 305 /* nmi_exit if relocations are on */ \ 306 irqentry_nmi_exit(regs, state); \ 307 } else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) && \ 308 firmware_has_feature(FW_FEATURE_LPAR) && \ 309 !radix_enabled()) { \ 310 /* no nmi_exit for a pseries hash guest \ 311 * taking a real mode exception */ \ 312 } else if (IS_ENABLED(CONFIG_KASAN)) { \ 313 /* no nmi_exit for KASAN in real mode */ \ 314 } else if (percpu_first_chunk_is_paged) { \ 315 /* no nmi_exit if percpu first chunk is not embedded */ \ 316 } else { \ 317 irqentry_nmi_exit(regs, state); \ 318 } \ 319 \ 320 return ret; \ 321 } \ 322 NOKPROBE_SYMBOL(func); \ 323 \ 324 static __always_inline __no_sanitize_address __no_kcsan long \ 325 ____##func(struct pt_regs *regs) 326 327 328 /* Interrupt handlers */ 329 /* kernel/traps.c */ 330 DECLARE_INTERRUPT_HANDLER_NMI(system_reset_exception); 331 #ifdef CONFIG_PPC_BOOK3S_64 332 DECLARE_INTERRUPT_HANDLER_RAW(machine_check_early_boot); 333 DECLARE_INTERRUPT_HANDLER_ASYNC(machine_check_exception_async); 334 #endif 335 DECLARE_INTERRUPT_HANDLER_NMI(machine_check_exception); 336 DECLARE_INTERRUPT_HANDLER(SMIException); 337 DECLARE_INTERRUPT_HANDLER(handle_hmi_exception); 338 DECLARE_INTERRUPT_HANDLER(unknown_exception); 339 DECLARE_INTERRUPT_HANDLER_ASYNC(unknown_async_exception); 340 DECLARE_INTERRUPT_HANDLER_NMI(unknown_nmi_exception); 341 DECLARE_INTERRUPT_HANDLER(instruction_breakpoint_exception); 342 DECLARE_INTERRUPT_HANDLER(RunModeException); 343 DECLARE_INTERRUPT_HANDLER(single_step_exception); 344 DECLARE_INTERRUPT_HANDLER(program_check_exception); 345 DECLARE_INTERRUPT_HANDLER(emulation_assist_interrupt); 346 DECLARE_INTERRUPT_HANDLER(alignment_exception); 347 DECLARE_INTERRUPT_HANDLER(StackOverflow); 348 DECLARE_INTERRUPT_HANDLER(stack_overflow_exception); 349 DECLARE_INTERRUPT_HANDLER(kernel_fp_unavailable_exception); 350 DECLARE_INTERRUPT_HANDLER(altivec_unavailable_exception); 351 DECLARE_INTERRUPT_HANDLER(vsx_unavailable_exception); 352 DECLARE_INTERRUPT_HANDLER(facility_unavailable_exception); 353 DECLARE_INTERRUPT_HANDLER(fp_unavailable_tm); 354 DECLARE_INTERRUPT_HANDLER(altivec_unavailable_tm); 355 DECLARE_INTERRUPT_HANDLER(vsx_unavailable_tm); 356 DECLARE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi); 357 DECLARE_INTERRUPT_HANDLER_ASYNC(performance_monitor_exception_async); 358 DECLARE_INTERRUPT_HANDLER_RAW(performance_monitor_exception); 359 DECLARE_INTERRUPT_HANDLER(DebugException); 360 DECLARE_INTERRUPT_HANDLER(altivec_assist_exception); 361 DECLARE_INTERRUPT_HANDLER(CacheLockingException); 362 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointException); 363 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointRoundException); 364 DECLARE_INTERRUPT_HANDLER_NMI(WatchdogException); 365 DECLARE_INTERRUPT_HANDLER(kernel_bad_stack); 366 367 /* slb.c */ 368 DECLARE_INTERRUPT_HANDLER_RAW(do_slb_fault); 369 DECLARE_INTERRUPT_HANDLER(do_bad_segment_interrupt); 370 371 /* hash_utils.c */ 372 DECLARE_INTERRUPT_HANDLER(do_hash_fault); 373 374 /* fault.c */ 375 DECLARE_INTERRUPT_HANDLER(do_page_fault); 376 DECLARE_INTERRUPT_HANDLER(do_bad_page_fault_segv); 377 378 /* process.c */ 379 DECLARE_INTERRUPT_HANDLER(do_break); 380 381 /* time.c */ 382 DECLARE_INTERRUPT_HANDLER_ASYNC(timer_interrupt); 383 384 /* mce.c */ 385 DECLARE_INTERRUPT_HANDLER_NMI(machine_check_early); 386 DECLARE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode); 387 388 DECLARE_INTERRUPT_HANDLER_ASYNC(TAUException); 389 390 /* irq.c */ 391 DECLARE_INTERRUPT_HANDLER_ASYNC(do_IRQ); 392 393 void __noreturn unrecoverable_exception(struct pt_regs *regs); 394 395 void replay_system_reset(void); 396 void replay_soft_interrupts(void); 397 398 static inline void interrupt_cond_local_irq_enable(struct pt_regs *regs) 399 { 400 if (!regs_irqs_disabled(regs)) 401 local_irq_enable(); 402 } 403 404 long system_call_exception(struct pt_regs *regs, unsigned long r0); 405 notrace unsigned long syscall_exit_prepare(unsigned long r3, struct pt_regs *regs, long scv); 406 notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs); 407 notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs); 408 #ifdef CONFIG_PPC64 409 unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *regs); 410 unsigned long interrupt_exit_user_restart(struct pt_regs *regs); 411 unsigned long interrupt_exit_kernel_restart(struct pt_regs *regs); 412 #endif 413 414 #endif /* __ASSEMBLER__ */ 415 416 #endif /* _ASM_POWERPC_INTERRUPT_H */ 417