1 /*
2  * Copyright (c) 2013-2014 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Kernel fatal error handler
10  */
11 
12 #include <zephyr/kernel.h>
13 #include <kernel_internal.h>
14 #include <zephyr/drivers/interrupt_controller/sysapic.h>
15 #include <zephyr/arch/x86/ia32/segmentation.h>
16 #include <zephyr/arch/syscall.h>
17 #include <ia32/exception.h>
18 #include <inttypes.h>
19 #include <zephyr/arch/common/exc_handle.h>
20 #include <zephyr/logging/log.h>
21 #include <x86_mmu.h>
22 #include <zephyr/kernel/mm.h>
23 
24 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
25 
26 #ifdef CONFIG_DEBUG_COREDUMP
27 unsigned int z_x86_exception_vector;
28 #endif
29 
z_debug_fatal_hook(const struct arch_esf * esf)30 __weak void z_debug_fatal_hook(const struct arch_esf *esf) { ARG_UNUSED(esf); }
31 
32 __pinned_func
z_x86_spurious_irq(const struct arch_esf * esf)33 void z_x86_spurious_irq(const struct arch_esf *esf)
34 {
35 	int vector = z_irq_controller_isr_vector_get();
36 
37 	if (vector >= 0) {
38 		LOG_ERR("IRQ vector: %d", vector);
39 	}
40 
41 	z_x86_fatal_error(K_ERR_SPURIOUS_IRQ, esf);
42 }
43 
44 __pinned_func
arch_syscall_oops(void * ssf)45 void arch_syscall_oops(void *ssf)
46 {
47 	struct _x86_syscall_stack_frame *ssf_ptr =
48 		(struct _x86_syscall_stack_frame *)ssf;
49 	struct arch_esf oops = {
50 		.eip = ssf_ptr->eip,
51 		.cs = ssf_ptr->cs,
52 		.eflags = ssf_ptr->eflags
53 	};
54 
55 	if (oops.cs == USER_CODE_SEG) {
56 		oops.esp = ssf_ptr->esp;
57 	}
58 
59 	z_x86_fatal_error(K_ERR_KERNEL_OOPS, &oops);
60 }
61 
62 extern void (*_kernel_oops_handler)(void);
63 NANO_CPU_INT_REGISTER(_kernel_oops_handler, NANO_SOFT_IRQ,
64 		      Z_X86_OOPS_VECTOR / 16, Z_X86_OOPS_VECTOR, 3);
65 
66 #if CONFIG_EXCEPTION_DEBUG
67 __pinned_func
generic_exc_handle(unsigned int vector,const struct arch_esf * pEsf)68 FUNC_NORETURN static void generic_exc_handle(unsigned int vector,
69 					     const struct arch_esf *pEsf)
70 {
71 #ifdef CONFIG_DEBUG_COREDUMP
72 	z_x86_exception_vector = vector;
73 #endif
74 
75 	z_x86_unhandled_cpu_exception(vector, pEsf);
76 }
77 
78 #define _EXC_FUNC(vector) \
79 __pinned_func \
80 FUNC_NORETURN __used static void handle_exc_##vector(const struct arch_esf *pEsf) \
81 { \
82 	generic_exc_handle(vector, pEsf); \
83 }
84 
85 #define Z_EXC_FUNC_CODE(vector, dpl) \
86 	_EXC_FUNC(vector) \
87 	_EXCEPTION_CONNECT_CODE(handle_exc_##vector, vector, dpl)
88 
89 #define Z_EXC_FUNC_NOCODE(vector, dpl)	\
90 	_EXC_FUNC(vector) \
91 	_EXCEPTION_CONNECT_NOCODE(handle_exc_##vector, vector, dpl)
92 
93 /* Necessary indirection to ensure 'vector' is expanded before we expand
94  * the handle_exc_##vector
95  */
96 #define EXC_FUNC_NOCODE(vector, dpl)		\
97 	Z_EXC_FUNC_NOCODE(vector, dpl)
98 
99 #define EXC_FUNC_CODE(vector, dpl)		\
100 	Z_EXC_FUNC_CODE(vector, dpl)
101 
102 EXC_FUNC_NOCODE(IV_DIVIDE_ERROR, 0);
103 EXC_FUNC_NOCODE(IV_NON_MASKABLE_INTERRUPT, 0);
104 EXC_FUNC_NOCODE(IV_OVERFLOW, 0);
105 EXC_FUNC_NOCODE(IV_BOUND_RANGE, 0);
106 EXC_FUNC_NOCODE(IV_INVALID_OPCODE, 0);
107 EXC_FUNC_NOCODE(IV_DEVICE_NOT_AVAILABLE, 0);
108 #ifndef CONFIG_X86_ENABLE_TSS
109 EXC_FUNC_NOCODE(IV_DOUBLE_FAULT, 0);
110 #endif
111 EXC_FUNC_CODE(IV_INVALID_TSS, 0);
112 EXC_FUNC_CODE(IV_SEGMENT_NOT_PRESENT, 0);
113 EXC_FUNC_CODE(IV_STACK_FAULT, 0);
114 EXC_FUNC_CODE(IV_GENERAL_PROTECTION, 0);
115 EXC_FUNC_NOCODE(IV_X87_FPU_FP_ERROR, 0);
116 EXC_FUNC_CODE(IV_ALIGNMENT_CHECK, 0);
117 EXC_FUNC_NOCODE(IV_MACHINE_CHECK, 0);
118 #endif
119 
120 _EXCEPTION_CONNECT_CODE(z_x86_page_fault_handler, IV_PAGE_FAULT, 0);
121 
122 #ifdef CONFIG_X86_ENABLE_TSS
123 static __pinned_noinit volatile struct arch_esf _df_esf;
124 
125 /* Very tiny stack; just enough for the bogus error code pushed by the CPU
126  * and a frame pointer push by the compiler. All df_handler_top does is
127  * shuffle some data around with 'mov' statements and then 'iret'.
128  */
129 static __pinned_noinit char _df_stack[8];
130 
131 static FUNC_NORETURN __used void df_handler_top(void);
132 
133 #ifdef CONFIG_X86_KPTI
134 extern char z_trampoline_stack_end[];
135 #endif
136 
137 Z_GENERIC_SECTION(.tss)
138 struct task_state_segment _main_tss = {
139 	.ss0 = DATA_SEG,
140 #ifdef CONFIG_X86_KPTI
141 	/* Stack to land on when we get a soft/hard IRQ in user mode.
142 	 * In a special kernel page that, unlike all other kernel pages,
143 	 * is marked present in the user page table.
144 	 */
145 	.esp0 = (uint32_t)&z_trampoline_stack_end
146 #endif
147 };
148 
149 /* Special TSS for handling double-faults with a known good stack */
150 Z_GENERIC_SECTION(.tss)
151 struct task_state_segment _df_tss = {
152 	.esp = (uint32_t)(_df_stack + sizeof(_df_stack)),
153 	.cs = CODE_SEG,
154 	.ds = DATA_SEG,
155 	.es = DATA_SEG,
156 	.ss = DATA_SEG,
157 	.eip = (uint32_t)df_handler_top,
158 	.cr3 = (uint32_t)
159 		K_MEM_PHYS_ADDR(POINTER_TO_UINT(&z_x86_kernel_ptables[0]))
160 };
161 
162 __pinned_func
df_handler_bottom(void)163 static __used void df_handler_bottom(void)
164 {
165 	/* We're back in the main hardware task on the interrupt stack */
166 	unsigned int reason = K_ERR_CPU_EXCEPTION;
167 
168 	/* Restore the top half so it is runnable again */
169 	_df_tss.esp = (uint32_t)(_df_stack + sizeof(_df_stack));
170 	_df_tss.eip = (uint32_t)df_handler_top;
171 
172 	LOG_ERR("Double Fault");
173 #ifdef CONFIG_THREAD_STACK_INFO
174 	/* To comply with MISRA 13.2 rule necessary to exclude code that depends
175 	 * on the order of evaluation of function arguments.
176 	 * Create 2 variables to store volatile data from the structure _df_esf
177 	 */
178 	uint32_t df_esf_esp = _df_esf.esp;
179 	uint16_t df_esf_cs = _df_esf.cs;
180 
181 	if (z_x86_check_stack_bounds(df_esf_esp, 0, df_esf_cs)) {
182 		reason = K_ERR_STACK_CHK_FAIL;
183 	}
184 #endif
185 	z_x86_fatal_error(reason, (struct arch_esf *)&_df_esf);
186 }
187 
188 __pinned_func
df_handler_top(void)189 static FUNC_NORETURN __used void df_handler_top(void)
190 {
191 	/* State of the system when the double-fault forced a task switch
192 	 * will be in _main_tss. Set up a struct arch_esf and copy system state into
193 	 * it
194 	 */
195 	_df_esf.esp = _main_tss.esp;
196 	_df_esf.ebp = _main_tss.ebp;
197 	_df_esf.ebx = _main_tss.ebx;
198 	_df_esf.esi = _main_tss.esi;
199 	_df_esf.edi = _main_tss.edi;
200 	_df_esf.edx = _main_tss.edx;
201 	_df_esf.eax = _main_tss.eax;
202 	_df_esf.ecx = _main_tss.ecx;
203 	_df_esf.errorCode = 0;
204 	_df_esf.eip = _main_tss.eip;
205 	_df_esf.cs = _main_tss.cs;
206 	_df_esf.eflags = _main_tss.eflags;
207 
208 	/* Restore the main IA task to a runnable state */
209 	_main_tss.esp = (uint32_t)(K_KERNEL_STACK_BUFFER(
210 		z_interrupt_stacks[0]) + CONFIG_ISR_STACK_SIZE);
211 	_main_tss.cs = CODE_SEG;
212 	_main_tss.ds = DATA_SEG;
213 	_main_tss.es = DATA_SEG;
214 	_main_tss.ss = DATA_SEG;
215 	_main_tss.eip = (uint32_t)df_handler_bottom;
216 	_main_tss.cr3 = k_mem_phys_addr(z_x86_kernel_ptables);
217 	_main_tss.eflags = 0U;
218 
219 	/* NT bit is set in EFLAGS so we will task switch back to _main_tss
220 	 * and run df_handler_bottom
221 	 */
222 	__asm__ volatile ("iret");
223 	CODE_UNREACHABLE;
224 }
225 
226 /* Configure a task gate descriptor in the IDT for the double fault
227  * exception
228  */
229 _X86_IDT_TSS_REGISTER(DF_TSS, -1, -1, IV_DOUBLE_FAULT, 0);
230 
231 #endif /* CONFIG_X86_ENABLE_TSS */
232