entry_fred.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * The FRED specific kernel/user entry functions which are invoked from
  4. * assembly code and dispatch to the associated handlers.
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/kdebug.h>
  8. #include <linux/nospec.h>
  9. #include <asm/desc.h>
  10. #include <asm/fred.h>
  11. #include <asm/idtentry.h>
  12. #include <asm/syscall.h>
  13. #include <asm/trapnr.h>
  14. #include <asm/traps.h>
  15. /* FRED EVENT_TYPE_OTHER vector numbers */
  16. #define FRED_SYSCALL 1
  17. #define FRED_SYSENTER 2
  18. static noinstr void fred_bad_type(struct pt_regs *regs, unsigned long error_code)
  19. {
  20. irqentry_state_t irq_state = irqentry_nmi_enter(regs);
  21. instrumentation_begin();
  22. /* Panic on events from a high stack level */
  23. if (regs->fred_cs.sl > 0) {
  24. pr_emerg("PANIC: invalid or fatal FRED event; event type %u "
  25. "vector %u error 0x%lx aux 0x%lx at %04x:%016lx\n",
  26. regs->fred_ss.type, regs->fred_ss.vector, error_code,
  27. fred_event_data(regs), regs->cs, regs->ip);
  28. die("invalid or fatal FRED event", regs, error_code);
  29. panic("invalid or fatal FRED event");
  30. } else {
  31. unsigned long flags = oops_begin();
  32. int sig = SIGKILL;
  33. pr_alert("BUG: invalid or fatal FRED event; event type %u "
  34. "vector %u error 0x%lx aux 0x%lx at %04x:%016lx\n",
  35. regs->fred_ss.type, regs->fred_ss.vector, error_code,
  36. fred_event_data(regs), regs->cs, regs->ip);
  37. if (__die("Invalid or fatal FRED event", regs, error_code))
  38. sig = 0;
  39. oops_end(flags, regs, sig);
  40. }
  41. instrumentation_end();
  42. irqentry_nmi_exit(regs, irq_state);
  43. }
  44. static noinstr void fred_intx(struct pt_regs *regs)
  45. {
  46. switch (regs->fred_ss.vector) {
  47. /* Opcode 0xcd, 0x3, NOT INT3 (opcode 0xcc) */
  48. case X86_TRAP_BP:
  49. return exc_int3(regs);
  50. /* Opcode 0xcd, 0x4, NOT INTO (opcode 0xce) */
  51. case X86_TRAP_OF:
  52. return exc_overflow(regs);
  53. #ifdef CONFIG_IA32_EMULATION
  54. /* INT80 */
  55. case IA32_SYSCALL_VECTOR:
  56. if (ia32_enabled())
  57. return fred_int80_emulation(regs);
  58. fallthrough;
  59. #endif
  60. default:
  61. return exc_general_protection(regs, 0);
  62. }
  63. }
  64. static __always_inline void fred_other(struct pt_regs *regs)
  65. {
  66. /* The compiler can fold these conditions into a single test */
  67. if (likely(regs->fred_ss.vector == FRED_SYSCALL && regs->fred_ss.lm)) {
  68. regs->orig_ax = regs->ax;
  69. regs->ax = -ENOSYS;
  70. do_syscall_64(regs, regs->orig_ax);
  71. return;
  72. } else if (ia32_enabled() &&
  73. likely(regs->fred_ss.vector == FRED_SYSENTER && !regs->fred_ss.lm)) {
  74. regs->orig_ax = regs->ax;
  75. regs->ax = -ENOSYS;
  76. do_fast_syscall_32(regs);
  77. return;
  78. } else {
  79. exc_invalid_op(regs);
  80. return;
  81. }
  82. }
  83. #define SYSVEC(_vector, _function) [_vector - FIRST_SYSTEM_VECTOR] = fred_sysvec_##_function
  84. static idtentry_t sysvec_table[NR_SYSTEM_VECTORS] __ro_after_init = {
  85. SYSVEC(ERROR_APIC_VECTOR, error_interrupt),
  86. SYSVEC(SPURIOUS_APIC_VECTOR, spurious_apic_interrupt),
  87. SYSVEC(LOCAL_TIMER_VECTOR, apic_timer_interrupt),
  88. SYSVEC(X86_PLATFORM_IPI_VECTOR, x86_platform_ipi),
  89. SYSVEC(RESCHEDULE_VECTOR, reschedule_ipi),
  90. SYSVEC(CALL_FUNCTION_SINGLE_VECTOR, call_function_single),
  91. SYSVEC(CALL_FUNCTION_VECTOR, call_function),
  92. SYSVEC(REBOOT_VECTOR, reboot),
  93. SYSVEC(THRESHOLD_APIC_VECTOR, threshold),
  94. SYSVEC(DEFERRED_ERROR_VECTOR, deferred_error),
  95. SYSVEC(THERMAL_APIC_VECTOR, thermal),
  96. SYSVEC(IRQ_WORK_VECTOR, irq_work),
  97. SYSVEC(POSTED_INTR_VECTOR, kvm_posted_intr_ipi),
  98. SYSVEC(POSTED_INTR_WAKEUP_VECTOR, kvm_posted_intr_wakeup_ipi),
  99. SYSVEC(POSTED_INTR_NESTED_VECTOR, kvm_posted_intr_nested_ipi),
  100. SYSVEC(POSTED_MSI_NOTIFICATION_VECTOR, posted_msi_notification),
  101. };
  102. static bool fred_setup_done __initdata;
  103. void __init fred_install_sysvec(unsigned int sysvec, idtentry_t handler)
  104. {
  105. if (WARN_ON_ONCE(sysvec < FIRST_SYSTEM_VECTOR))
  106. return;
  107. if (WARN_ON_ONCE(fred_setup_done))
  108. return;
  109. if (!WARN_ON_ONCE(sysvec_table[sysvec - FIRST_SYSTEM_VECTOR]))
  110. sysvec_table[sysvec - FIRST_SYSTEM_VECTOR] = handler;
  111. }
  112. static noinstr void fred_handle_spurious_interrupt(struct pt_regs *regs)
  113. {
  114. spurious_interrupt(regs, regs->fred_ss.vector);
  115. }
  116. void __init fred_complete_exception_setup(void)
  117. {
  118. unsigned int vector;
  119. for (vector = 0; vector < FIRST_EXTERNAL_VECTOR; vector++)
  120. set_bit(vector, system_vectors);
  121. for (vector = 0; vector < NR_SYSTEM_VECTORS; vector++) {
  122. if (sysvec_table[vector])
  123. set_bit(vector + FIRST_SYSTEM_VECTOR, system_vectors);
  124. else
  125. sysvec_table[vector] = fred_handle_spurious_interrupt;
  126. }
  127. fred_setup_done = true;
  128. }
  129. static noinstr void fred_extint(struct pt_regs *regs)
  130. {
  131. unsigned int vector = regs->fred_ss.vector;
  132. unsigned int index = array_index_nospec(vector - FIRST_SYSTEM_VECTOR,
  133. NR_SYSTEM_VECTORS);
  134. if (WARN_ON_ONCE(vector < FIRST_EXTERNAL_VECTOR))
  135. return;
  136. if (likely(vector >= FIRST_SYSTEM_VECTOR)) {
  137. irqentry_state_t state = irqentry_enter(regs);
  138. instrumentation_begin();
  139. sysvec_table[index](regs);
  140. instrumentation_end();
  141. irqentry_exit(regs, state);
  142. } else {
  143. common_interrupt(regs, vector);
  144. }
  145. }
  146. static noinstr void fred_hwexc(struct pt_regs *regs, unsigned long error_code)
  147. {
  148. /* Optimize for #PF. That's the only exception which matters performance wise */
  149. if (likely(regs->fred_ss.vector == X86_TRAP_PF))
  150. return exc_page_fault(regs, error_code);
  151. switch (regs->fred_ss.vector) {
  152. case X86_TRAP_DE: return exc_divide_error(regs);
  153. case X86_TRAP_DB: return fred_exc_debug(regs);
  154. case X86_TRAP_BR: return exc_bounds(regs);
  155. case X86_TRAP_UD: return exc_invalid_op(regs);
  156. case X86_TRAP_NM: return exc_device_not_available(regs);
  157. case X86_TRAP_DF: return exc_double_fault(regs, error_code);
  158. case X86_TRAP_TS: return exc_invalid_tss(regs, error_code);
  159. case X86_TRAP_NP: return exc_segment_not_present(regs, error_code);
  160. case X86_TRAP_SS: return exc_stack_segment(regs, error_code);
  161. case X86_TRAP_GP: return exc_general_protection(regs, error_code);
  162. case X86_TRAP_MF: return exc_coprocessor_error(regs);
  163. case X86_TRAP_AC: return exc_alignment_check(regs, error_code);
  164. case X86_TRAP_XF: return exc_simd_coprocessor_error(regs);
  165. #ifdef CONFIG_X86_MCE
  166. case X86_TRAP_MC: return fred_exc_machine_check(regs);
  167. #endif
  168. #ifdef CONFIG_INTEL_TDX_GUEST
  169. case X86_TRAP_VE: return exc_virtualization_exception(regs);
  170. #endif
  171. #ifdef CONFIG_X86_CET
  172. case X86_TRAP_CP: return exc_control_protection(regs, error_code);
  173. #endif
  174. default: return fred_bad_type(regs, error_code);
  175. }
  176. }
  177. static noinstr void fred_swexc(struct pt_regs *regs, unsigned long error_code)
  178. {
  179. switch (regs->fred_ss.vector) {
  180. case X86_TRAP_BP: return exc_int3(regs);
  181. case X86_TRAP_OF: return exc_overflow(regs);
  182. default: return fred_bad_type(regs, error_code);
  183. }
  184. }
  185. __visible noinstr void fred_entry_from_user(struct pt_regs *regs)
  186. {
  187. unsigned long error_code = regs->orig_ax;
  188. /* Invalidate orig_ax so that syscall_get_nr() works correctly */
  189. regs->orig_ax = -1;
  190. switch (regs->fred_ss.type) {
  191. case EVENT_TYPE_EXTINT:
  192. return fred_extint(regs);
  193. case EVENT_TYPE_NMI:
  194. if (likely(regs->fred_ss.vector == X86_TRAP_NMI))
  195. return fred_exc_nmi(regs);
  196. break;
  197. case EVENT_TYPE_HWEXC:
  198. return fred_hwexc(regs, error_code);
  199. case EVENT_TYPE_SWINT:
  200. return fred_intx(regs);
  201. case EVENT_TYPE_PRIV_SWEXC:
  202. if (likely(regs->fred_ss.vector == X86_TRAP_DB))
  203. return fred_exc_debug(regs);
  204. break;
  205. case EVENT_TYPE_SWEXC:
  206. return fred_swexc(regs, error_code);
  207. case EVENT_TYPE_OTHER:
  208. return fred_other(regs);
  209. default: break;
  210. }
  211. return fred_bad_type(regs, error_code);
  212. }
  213. __visible noinstr void fred_entry_from_kernel(struct pt_regs *regs)
  214. {
  215. unsigned long error_code = regs->orig_ax;
  216. /* Invalidate orig_ax so that syscall_get_nr() works correctly */
  217. regs->orig_ax = -1;
  218. switch (regs->fred_ss.type) {
  219. case EVENT_TYPE_EXTINT:
  220. return fred_extint(regs);
  221. case EVENT_TYPE_NMI:
  222. if (likely(regs->fred_ss.vector == X86_TRAP_NMI))
  223. return fred_exc_nmi(regs);
  224. break;
  225. case EVENT_TYPE_HWEXC:
  226. return fred_hwexc(regs, error_code);
  227. case EVENT_TYPE_PRIV_SWEXC:
  228. if (likely(regs->fred_ss.vector == X86_TRAP_DB))
  229. return fred_exc_debug(regs);
  230. break;
  231. case EVENT_TYPE_SWEXC:
  232. return fred_swexc(regs, error_code);
  233. default: break;
  234. }
  235. return fred_bad_type(regs, error_code);
  236. }
  237. #if IS_ENABLED(CONFIG_KVM_INTEL)
  238. __visible noinstr void __fred_entry_from_kvm(struct pt_regs *regs)
  239. {
  240. switch (regs->fred_ss.type) {
  241. case EVENT_TYPE_EXTINT:
  242. return fred_extint(regs);
  243. case EVENT_TYPE_NMI:
  244. return fred_exc_nmi(regs);
  245. default:
  246. WARN_ON_ONCE(1);
  247. }
  248. }
  249. #endif