libpayload: configs: Add new config.featuretest to broaden CI
[coreboot.git] / payloads / libpayload / arch / x86 / exception.c
blob9811be3c93132b9c1a7d00a6820f02ec55a07c47
1 /*
3 * Copyright 2013 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <arch/exception.h>
30 #include <exception.h>
31 #include <libpayload.h>
32 #include <stdint.h>
33 #include <arch/apic.h>
35 #define IF_FLAG (1 << 9)
37 #if CONFIG(LP_ARCH_X86_64)
38 #define REGISTER_FMT "0x%016zx"
39 #else
40 #define REGISTER_FMT "0x%08zx"
41 #endif
43 u8 exception_stack[0x400] __aligned(16);
45 static interrupt_handler handlers[256];
47 static const char *names[EXC_COUNT] = {
48 [EXC_DE] = "Divide by Zero",
49 [EXC_DB] = "Debug",
50 [EXC_NMI] = "Non-Maskable-Interrupt",
51 [EXC_BP] = "Breakpoint",
52 [EXC_OF] = "Overflow",
53 [EXC_BR] = "Bound Range",
54 [EXC_UD] = "Invalid Opcode",
55 [EXC_NM] = "Device Not Available",
56 [EXC_DF] = "Double Fault",
57 [EXC_TS] = "Invalid TSS",
58 [EXC_NP] = "Segment Not Present",
59 [EXC_SS] = "Stack Fault",
60 [EXC_GP] = "General Protection Fault",
61 [EXC_PF] = "Page Fault",
62 [EXC_MF] = "x87 Floating Point",
63 [EXC_AC] = "Alignment Check",
64 [EXC_MC] = "Machine Check",
65 [EXC_XF] = "SIMD Floating Point",
66 [EXC_SX] = "Security",
69 static void print_segment_error_code(u32 code)
71 printf("%#x - descriptor %#x in the ", code, (code >> 3) & 0x1FFF);
72 if (code & (0x1 << 1)) {
73 printf("IDT");
74 } else {
75 if (code & 0x04)
76 printf("LDT");
77 else
78 printf("GDT");
80 if (code & (0x1 << 0))
81 printf(", external to the CPU");
82 else
83 printf(", internal to the CPU");
86 static void print_page_fault_error_code(u32 code)
88 printf("%#x -", code);
89 if (code & (0x1 << 0))
90 printf(" page protection");
91 else
92 printf(" page not present");
93 if (code & (0x1 << 1))
94 printf(", write");
95 else
96 printf(", read");
97 if (code & (0x1 << 2))
98 printf(", user");
99 else
100 printf(", supervisor");
101 if (code & (0x1 << 3))
102 printf(", reserved bits set");
103 if (code & (0x1 << 4))
104 printf(", instruction fetch");
107 static void print_raw_error_code(u32 code)
109 printf("%#x", code);
112 static void dump_stack(uintptr_t addr, size_t bytes)
114 int i, j;
115 const int line = 8;
116 uint32_t *ptr = (uint32_t *)((uintptr_t)addr & ~(line * sizeof(*ptr) - 1));
118 printf("Dumping stack:\n");
119 for (i = bytes / sizeof(*ptr); i >= 0; i -= line) {
120 printf("%p: ", ptr + i);
121 for (j = i; j < i + line; j++) {
122 if ((uintptr_t)(ptr + j) >= addr && (uintptr_t)(ptr + j) < addr + bytes)
123 printf("%08x ", *(ptr + j));
125 printf("\n");
129 static void dump_exception_state(void)
131 printf("%s Exception\n", names[exception_state->vector]);
133 printf("Error code: ");
134 switch (exception_state->vector) {
135 case EXC_PF:
136 print_page_fault_error_code(exception_state->error_code);
137 break;
138 case EXC_TS:
139 case EXC_NP:
140 case EXC_SS:
141 case EXC_GP:
142 print_segment_error_code(exception_state->error_code);
143 break;
144 case EXC_DF:
145 case EXC_AC:
146 case EXC_SX:
147 print_raw_error_code(exception_state->error_code);
148 break;
149 default:
150 printf("n/a");
151 break;
153 printf("\n");
154 printf("REG_IP: " REGISTER_FMT "\n", exception_state->regs.reg_ip);
155 printf("REG_FLAGS: " REGISTER_FMT "\n", exception_state->regs.reg_flags);
156 printf("REG_AX: " REGISTER_FMT "\n", exception_state->regs.reg_ax);
157 printf("REG_BX: " REGISTER_FMT "\n", exception_state->regs.reg_bx);
158 printf("REG_CX: " REGISTER_FMT "\n", exception_state->regs.reg_cx);
159 printf("REG_DX: " REGISTER_FMT "\n", exception_state->regs.reg_dx);
160 printf("REG_SP: " REGISTER_FMT "\n", exception_state->regs.reg_sp);
161 printf("REG_BP: " REGISTER_FMT "\n", exception_state->regs.reg_bp);
162 printf("REG_SI: " REGISTER_FMT "\n", exception_state->regs.reg_si);
163 printf("REG_DI: " REGISTER_FMT "\n", exception_state->regs.reg_di);
164 #if CONFIG(LP_ARCH_X86_64)
165 printf("REG_R8: 0x%016zx\n", exception_state->regs.reg_r8);
166 printf("REG_R9: 0x%016zx\n", exception_state->regs.reg_r9);
167 printf("REG_R10: 0x%016zx\n", exception_state->regs.reg_r10);
168 printf("REG_R11: 0x%016zx\n", exception_state->regs.reg_r11);
169 printf("REG_R12: 0x%016zx\n", exception_state->regs.reg_r12);
170 printf("REG_R13: 0x%016zx\n", exception_state->regs.reg_r13);
171 printf("REG_R14: 0x%016zx\n", exception_state->regs.reg_r14);
172 printf("REG_R15: 0x%016zx\n", exception_state->regs.reg_r15);
173 #endif
174 printf("CS: 0x%04x\n", exception_state->regs.cs);
175 printf("DS: 0x%04x\n", exception_state->regs.ds);
176 printf("ES: 0x%04x\n", exception_state->regs.es);
177 printf("SS: 0x%04x\n", exception_state->regs.ss);
178 printf("FS: 0x%04x\n", exception_state->regs.fs);
179 printf("GS: 0x%04x\n", exception_state->regs.gs);
182 void exception_dispatch(void)
184 die_if(exception_state->vector >= ARRAY_SIZE(handlers),
185 "Invalid vector %zu\n", exception_state->vector);
187 u8 vec = exception_state->vector;
189 if (handlers[vec]) {
190 handlers[vec](vec);
191 goto success;
192 } else if (vec >= EXC_COUNT
193 && CONFIG(LP_IGNORE_UNKNOWN_INTERRUPTS)) {
194 goto success;
195 } else if (vec >= EXC_COUNT
196 && CONFIG(LP_LOG_UNKNOWN_INTERRUPTS)) {
197 printf("Ignoring interrupt vector %u\n", vec);
198 goto success;
201 die_if(vec >= EXC_COUNT || !names[vec], "Bad exception vector %u\n",
202 vec);
204 dump_exception_state();
205 dump_stack(exception_state->regs.reg_sp, 512);
206 /* We don't call apic_eoi because we don't want to ack the interrupt and
207 allow another interrupt to wake the processor. */
208 halt();
209 return;
211 success:
212 if (CONFIG(LP_ENABLE_APIC))
213 apic_eoi(vec);
216 void exception_init(void)
218 exception_stack_end = exception_stack + ARRAY_SIZE(exception_stack);
219 exception_init_asm();
222 void set_interrupt_handler(u8 vector, interrupt_handler handler)
224 handlers[vector] = handler;
227 #if CONFIG(LP_ARCH_X86_64)
228 static uint64_t eflags(void)
230 uint64_t eflags;
231 asm volatile(
232 "pushfq\n\t"
233 "popq %0\n\t"
234 : "=rm" (eflags));
235 return eflags;
237 #else
238 static uint32_t eflags(void)
240 uint32_t eflags;
241 asm volatile(
242 "pushf\n\t"
243 "pop %0\n\t"
244 : "=rm" (eflags));
245 return eflags;
247 #endif
249 void enable_interrupts(void)
251 asm volatile (
252 "sti\n"
253 : : : "cc"
256 void disable_interrupts(void)
258 asm volatile (
259 "cli\n"
260 : : : "cc"
264 int interrupts_enabled(void)
266 return !!(eflags() & IF_FLAG);