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