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
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
29 #include <arch/exception.h>
30 #include <exception.h>
31 #include <libpayload.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"
40 #define REGISTER_FMT "0x%08zx"
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",
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)) {
80 if (code
& (0x1 << 0))
81 printf(", external to the CPU");
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");
92 printf(" page not present");
93 if (code
& (0x1 << 1))
97 if (code
& (0x1 << 2))
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
)
112 static void dump_stack(uintptr_t addr
, size_t bytes
)
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
));
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
) {
136 print_page_fault_error_code(exception_state
->error_code
);
142 print_segment_error_code(exception_state
->error_code
);
147 print_raw_error_code(exception_state
->error_code
);
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
);
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
;
192 } else if (vec
>= EXC_COUNT
193 && CONFIG(LP_IGNORE_UNKNOWN_INTERRUPTS
)) {
195 } else if (vec
>= EXC_COUNT
196 && CONFIG(LP_LOG_UNKNOWN_INTERRUPTS
)) {
197 printf("Ignoring interrupt vector %u\n", vec
);
201 die_if(vec
>= EXC_COUNT
|| !names
[vec
], "Bad exception vector %u\n",
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. */
212 if (CONFIG(LP_ENABLE_APIC
))
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)
238 static uint32_t eflags(void)
249 void enable_interrupts(void)
256 void disable_interrupts(void)
264 int interrupts_enabled(void)
266 return !!(eflags() & IF_FLAG
);