blob: fdab0429021b16ce46864b322d044ae9f63643d1 [file] [log] [blame]
Gabe Blacka7991512013-12-07 04:25:01 -08001/*
Gabe Blacka7991512013-12-07 04:25:01 -08002 *
3 * Copyright 2013 Google Inc.
4 *
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.
15 *
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.
27 */
28
Gabe Black20cdb242013-12-11 00:23:15 -080029#include <arch/exception.h>
Gabe Blacka7991512013-12-07 04:25:01 -080030#include <exception.h>
31#include <libpayload.h>
32#include <stdint.h>
Raul E Rangelac8ebd02018-08-20 11:14:44 -060033#include <arch/apic.h>
Gabe Blacka7991512013-12-07 04:25:01 -080034
Raul E Rangelcf79c832018-08-22 10:03:05 -060035#define IF_FLAG (1 << 9)
36
Subrata Banikafa39102024-05-18 12:26:40 +000037#if CONFIG(LP_ARCH_X86_64)
38#define REGISTER_FMT "0x%016zx"
39#else
40#define REGISTER_FMT "0x%08zx"
41#endif
42
43u8 exception_stack[0x400] __aligned(16);
Gabe Blacka7991512013-12-07 04:25:01 -080044
Raul E Rangel80d5c192018-08-22 10:03:05 -060045static interrupt_handler handlers[256];
46
Julius Werner092cac52014-05-15 19:41:52 -070047static 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",
Gabe Blacka7991512013-12-07 04:25:01 -080067};
68
69static void print_segment_error_code(u32 code)
70{
Raul E Rangela8b4b752018-08-02 15:12:34 -060071 printf("%#x - descriptor %#x in the ", code, (code >> 3) & 0x1FFF);
Gabe Blacka7991512013-12-07 04:25:01 -080072 if (code & (0x1 << 1)) {
73 printf("IDT");
74 } else {
75 if (code & 0x04)
76 printf("LDT");
77 else
78 printf("GDT");
79 }
80 if (code & (0x1 << 0))
81 printf(", external to the CPU");
82 else
83 printf(", internal to the CPU");
84}
85
86static void print_page_fault_error_code(u32 code)
87{
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");
105}
106
107static void print_raw_error_code(u32 code)
108{
109 printf("%#x", code);
110}
111
Gabe Blacka7991512013-12-07 04:25:01 -0800112static void dump_stack(uintptr_t addr, size_t bytes)
113{
114 int i, j;
115 const int line = 8;
116 uint32_t *ptr = (uint32_t *)(addr & ~(line * sizeof(*ptr) - 1));
117
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 printf("%08x ", *(ptr + j));
123 printf("\n");
124 }
125}
126
Julius Werner092cac52014-05-15 19:41:52 -0700127static void dump_exception_state(void)
Gabe Blacka7991512013-12-07 04:25:01 -0800128{
Julius Werner092cac52014-05-15 19:41:52 -0700129 printf("%s Exception\n", names[exception_state->vector]);
Patrick Georgibcf07c32014-12-29 19:34:56 +0100130
Julius Werner092cac52014-05-15 19:41:52 -0700131 printf("Error code: ");
132 switch (exception_state->vector) {
133 case EXC_PF:
134 print_page_fault_error_code(exception_state->error_code);
135 break;
136 case EXC_TS:
137 case EXC_NP:
138 case EXC_SS:
139 case EXC_GP:
140 print_segment_error_code(exception_state->error_code);
141 break;
142 case EXC_DF:
143 case EXC_AC:
144 case EXC_SX:
145 print_raw_error_code(exception_state->error_code);
146 break;
147 default:
148 printf("n/a");
149 break;
Gabe Blacka7991512013-12-07 04:25:01 -0800150 }
Julius Werner092cac52014-05-15 19:41:52 -0700151 printf("\n");
Subrata Banikafa39102024-05-18 12:26:40 +0000152 printf("REG_IP: " REGISTER_FMT "\n", exception_state->regs.reg_ip);
153 printf("REG_FLAGS: " REGISTER_FMT "\n", exception_state->regs.reg_flags);
154 printf("REG_AX: " REGISTER_FMT "\n", exception_state->regs.reg_ax);
155 printf("REG_BX: " REGISTER_FMT "\n", exception_state->regs.reg_bx);
156 printf("REG_CX: " REGISTER_FMT "\n", exception_state->regs.reg_cx);
157 printf("REG_DX: " REGISTER_FMT "\n", exception_state->regs.reg_dx);
158 printf("REG_SP: " REGISTER_FMT "\n", exception_state->regs.reg_sp);
159 printf("REG_BP: " REGISTER_FMT "\n", exception_state->regs.reg_bp);
160 printf("REG_SI: " REGISTER_FMT "\n", exception_state->regs.reg_si);
161 printf("REG_DI: " REGISTER_FMT "\n", exception_state->regs.reg_di);
162#if CONFIG(LP_ARCH_X86_64)
163 printf("REG_R8: 0x%016zx\n", exception_state->regs.reg_r8);
164 printf("REG_R9: 0x%016zx\n", exception_state->regs.reg_r9);
Subrata Banik04202d12024-06-11 14:41:48 +0000165 printf("REG_R10: 0x%016zx\n", exception_state->regs.reg_r10);
166 printf("REG_R11: 0x%016zx\n", exception_state->regs.reg_r11);
167 printf("REG_R12: 0x%016zx\n", exception_state->regs.reg_r12);
168 printf("REG_R13: 0x%016zx\n", exception_state->regs.reg_r13);
169 printf("REG_R14: 0x%016zx\n", exception_state->regs.reg_r14);
170 printf("REG_R15: 0x%016zx\n", exception_state->regs.reg_r15);
Subrata Banikafa39102024-05-18 12:26:40 +0000171#endif
Julius Werner092cac52014-05-15 19:41:52 -0700172 printf("CS: 0x%04x\n", exception_state->regs.cs);
Julius Werner092cac52014-05-15 19:41:52 -0700173 printf("DS: 0x%04x\n", exception_state->regs.ds);
174 printf("ES: 0x%04x\n", exception_state->regs.es);
175 printf("SS: 0x%04x\n", exception_state->regs.ss);
176 printf("FS: 0x%04x\n", exception_state->regs.fs);
177 printf("GS: 0x%04x\n", exception_state->regs.gs);
Gabe Blacka7991512013-12-07 04:25:01 -0800178}
179
Gabe Black20cdb242013-12-11 00:23:15 -0800180void exception_dispatch(void)
181{
Raul E Rangelb025de02018-10-01 14:34:31 -0600182 die_if(exception_state->vector >= ARRAY_SIZE(handlers),
Subrata Banikafa39102024-05-18 12:26:40 +0000183 "Invalid vector %zu\n", exception_state->vector);
Raul E Rangel80d5c192018-08-22 10:03:05 -0600184
Raul E Rangelb025de02018-10-01 14:34:31 -0600185 u8 vec = exception_state->vector;
Raul E Rangel80d5c192018-08-22 10:03:05 -0600186
187 if (handlers[vec]) {
188 handlers[vec](vec);
Raul E Rangel59e923d2018-10-02 09:45:06 -0600189 goto success;
190 } else if (vec >= EXC_COUNT
Julius Wernereab2a292019-03-05 16:55:15 -0800191 && CONFIG(LP_IGNORE_UNKNOWN_INTERRUPTS)) {
Raul E Rangel59e923d2018-10-02 09:45:06 -0600192 goto success;
193 } else if (vec >= EXC_COUNT
Julius Wernereab2a292019-03-05 16:55:15 -0800194 && CONFIG(LP_LOG_UNKNOWN_INTERRUPTS)) {
Raul E Rangel59e923d2018-10-02 09:45:06 -0600195 printf("Ignoring interrupt vector %u\n", vec);
196 goto success;
Raul E Rangel80d5c192018-08-22 10:03:05 -0600197 }
198
199 die_if(vec >= EXC_COUNT || !names[vec], "Bad exception vector %u\n",
200 vec);
Gabe Black20cdb242013-12-11 00:23:15 -0800201
Julius Werner092cac52014-05-15 19:41:52 -0700202 dump_exception_state();
Subrata Banikafa39102024-05-18 12:26:40 +0000203 dump_stack(exception_state->regs.reg_sp, 512);
Raul E Rangel59e923d2018-10-02 09:45:06 -0600204 /* We don't call apic_eoi because we don't want to ack the interrupt and
205 allow another interrupt to wake the processor. */
Julius Werner092cac52014-05-15 19:41:52 -0700206 halt();
Raul E Rangel59e923d2018-10-02 09:45:06 -0600207 return;
208
209success:
Julius Wernereab2a292019-03-05 16:55:15 -0800210 if (CONFIG(LP_ENABLE_APIC))
Raul E Rangel59e923d2018-10-02 09:45:06 -0600211 apic_eoi(vec);
Gabe Black20cdb242013-12-11 00:23:15 -0800212}
213
Gabe Blacka7991512013-12-07 04:25:01 -0800214void exception_init(void)
215{
Subrata Banikafa39102024-05-18 12:26:40 +0000216 /* TODO: Add exception init code for x64, currently only supporting 32-bit code */
217 if (CONFIG(LP_ARCH_X86_64))
218 return;
219
Julius Werner092cac52014-05-15 19:41:52 -0700220 exception_stack_end = exception_stack + ARRAY_SIZE(exception_stack);
Gabe Blacka7991512013-12-07 04:25:01 -0800221 exception_init_asm();
222}
Gabe Black20cdb242013-12-11 00:23:15 -0800223
Raul E Rangel80d5c192018-08-22 10:03:05 -0600224void set_interrupt_handler(u8 vector, interrupt_handler handler)
225{
226 handlers[vector] = handler;
227}
228
Subrata Banikafa39102024-05-18 12:26:40 +0000229#if CONFIG(LP_ARCH_X86_64)
230static uint64_t eflags(void)
231{
232 uint64_t eflags;
233 asm volatile(
234 "pushfq\n\t"
235 "popq %0\n\t"
236 : "=rm" (eflags));
237 return eflags;
238}
239#else
Raul E Rangelcf79c832018-08-22 10:03:05 -0600240static uint32_t eflags(void)
241{
242 uint32_t eflags;
243 asm volatile(
244 "pushf\n\t"
245 "pop %0\n\t"
246 : "=rm" (eflags));
247 return eflags;
248}
Subrata Banikafa39102024-05-18 12:26:40 +0000249#endif
Raul E Rangelcf79c832018-08-22 10:03:05 -0600250
251void enable_interrupts(void)
252{
253 asm volatile (
254 "sti\n"
255 : : : "cc"
256 );
257}
258void disable_interrupts(void)
259{
260 asm volatile (
261 "cli\n"
262 : : : "cc"
263 );
264}
265
266int interrupts_enabled(void)
267{
268 return !!(eflags() & IF_FLAG);
269}