From 4bbe43e22229050e3151aadef304e73ee92bfe67 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 23 Apr 2024 11:32:25 +0200 Subject: [PATCH] x86: support cpu exceptions --- arch.mk | 1 + include/x86/common.h | 1 + include/x86/exceptions.h | 32 ++++++ src/x86/exceptions.c | 216 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+) create mode 100644 include/x86/exceptions.h create mode 100644 src/x86/exceptions.c diff --git a/arch.mk b/arch.mk index 76b7f0e7..a5123918 100644 --- a/arch.mk +++ b/arch.mk @@ -734,6 +734,7 @@ ifeq ("${FSP}", "1") OBJS += src/x86/gpt.o OBJS += src/x86/mptable.o OBJS += src/stage1.o + OBJS += src/x86/exceptions.o UPDATE_OBJS := src/update_disk.o ifeq ($(64BIT),1) LDFLAGS += -m elf_x86_64 --oformat elf64-x86-64 diff --git a/include/x86/common.h b/include/x86/common.h index ba5aa3fd..78ed9159 100644 --- a/include/x86/common.h +++ b/include/x86/common.h @@ -67,4 +67,5 @@ void cpuid(uint32_t eax_param, int cpuid_is_1gb_page_supported(); void switch_to_long_mode(uint64_t *entry, uint32_t page_table); void x86_log_memory_load(uint32_t start, uint32_t end, const char *name); +void hlt(); #endif /* COMMON_H */ diff --git a/include/x86/exceptions.h b/include/x86/exceptions.h new file mode 100644 index 00000000..71f4e7f0 --- /dev/null +++ b/include/x86/exceptions.h @@ -0,0 +1,32 @@ +/* exceptions.h + * + * Copyright (C) 2023 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef EXCEPTIONS_H +#define EXCEPTIONS_H + +#include + +int setup_interrupt_gate(int vnum, uintptr_t handler); +int setup_interrupts(); +void deinit_interrupts(); +void wfi(); + +#endif /* EXCEPTIONS_H */ diff --git a/src/x86/exceptions.c b/src/x86/exceptions.c new file mode 100644 index 00000000..603e4fdb --- /dev/null +++ b/src/x86/exceptions.c @@ -0,0 +1,216 @@ +/* exceptions.c + * + * Copyright (C) 2023 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ + +#include +#include +#include + +#define EXCEPTION_NUM 35 +#define INTERRUPT_GATE_TYPE (0xe) +#define SEGMENT_SELECTOR (0x18) +#define TYPE_FLAG (INTERRUPT_GATE_TYPE << 8 | 1 << 15) + +#define LAPIC_DIV_CONF_REG 0xfee003e0 +#define LAPIC_INITIAL_CNT 0xfee00380 +#define LAPIC_CURRENT_CNT 0xfee00390 +#define LAPIC_LVT_TIMER_REG 0xfee00320 +#define LAPIC_EOI 0xfee000b0 +#define LAPIC_SVR 0xfee000f0 +#define LAPIC_SVR_ENABLE (1 << 8) +#define LAPIC_DIV_CONF_128 (1 << 1 | 1 << 3) +#define TIMER_SPURIOUS_NUMBER (33) +#define TIMER_VECTOR_NUMBER (34) +#define TIMER_CNT 0xffffff +#define IA32_APIC_BASE_MSR (0x1b) +#define IA32_APIC_BASE_MSR_ENABLE (0x800) + +#define DEBUG_EXCEPTIONS +#if defined(DEBUG_EXCEPTIONS) +#include +#define EXCEPTIONS_DEBUG_PRINTF(...) wolfBoot_printf(__VA_ARGS__) +#else +#define EXCEPTIONS_DEBUG_PRINTF(...) do {} while(0) +#endif + +struct interrupt_gate { + uint16_t offset_0_15; + uint16_t seg_sel; + uint16_t type_flags; + uint16_t offset_31_16; + uint32_t offset_63_32; + uint32_t reserved; +} __attribute__((packed)); + +struct idt_descriptor { + uint16_t limit; + uint64_t base; +} __attribute__((packed)); + +static struct interrupt_gate idt_table[EXCEPTION_NUM]; +static struct idt_descriptor idt_descriptor; + +#define EXCEPTION_TRAMPOLINE(X) \ + __attribute__((naked)) void exception_trampoline_##X() { \ + asm volatile("cli\r\n" \ + "mov %0, %%rdi\r\n" \ + "sti\r\n" \ + "call common_exception_handler\r\n" \ + "iretq\r\n" \ + : \ + : ""(X)); \ + } + +static void common_exception_handler(uint64_t vector_number) +{ + EXCEPTIONS_DEBUG_PRINTF("CPU exception: %d\r\n", (int)vector_number); +} + +EXCEPTION_TRAMPOLINE(0); +EXCEPTION_TRAMPOLINE(1); +EXCEPTION_TRAMPOLINE(2); +EXCEPTION_TRAMPOLINE(3); +EXCEPTION_TRAMPOLINE(4); +EXCEPTION_TRAMPOLINE(5); +EXCEPTION_TRAMPOLINE(6); +EXCEPTION_TRAMPOLINE(7); +EXCEPTION_TRAMPOLINE(8); +EXCEPTION_TRAMPOLINE(9); +EXCEPTION_TRAMPOLINE(10); +EXCEPTION_TRAMPOLINE(11); +EXCEPTION_TRAMPOLINE(12) +EXCEPTION_TRAMPOLINE(13); +EXCEPTION_TRAMPOLINE(14); +EXCEPTION_TRAMPOLINE(15); +EXCEPTION_TRAMPOLINE(16); +EXCEPTION_TRAMPOLINE(17); +EXCEPTION_TRAMPOLINE(18); +EXCEPTION_TRAMPOLINE(19); +EXCEPTION_TRAMPOLINE(20); +EXCEPTION_TRAMPOLINE(21); +EXCEPTION_TRAMPOLINE(22); +EXCEPTION_TRAMPOLINE(23); +EXCEPTION_TRAMPOLINE(24); +EXCEPTION_TRAMPOLINE(25); +EXCEPTION_TRAMPOLINE(26); +EXCEPTION_TRAMPOLINE(27); +EXCEPTION_TRAMPOLINE(28); +EXCEPTION_TRAMPOLINE(29); +EXCEPTION_TRAMPOLINE(30); +EXCEPTION_TRAMPOLINE(31); +EXCEPTION_TRAMPOLINE(32); +/* lapic spurious vector */ +EXCEPTION_TRAMPOLINE(33); + +int setup_interrupt_gate(int vnum, uintptr_t handler) +{ + struct interrupt_gate *ig; + + ig = &idt_table[vnum]; + ig->offset_0_15 = (uint16_t)(handler & 0xffff); + ig->offset_31_16 = (uint16_t)((handler >> 16) & 0xffff); + ig->offset_63_32 = (uint32_t)((handler) >> 32); + ig->type_flags = TYPE_FLAG; + ig->seg_sel = SEGMENT_SELECTOR; + ig->reserved = 0x0; +} + +static void _timer_handler() +{ + EXCEPTIONS_DEBUG_PRINTF("In the timer handler\r\n"); +} + +static void __attribute__((__naked__)) timer_handler() { + asm volatile("cli\r\n" + "call _timer_handler\r\n" + "sti\r\n" + "mov %0, %%eax\r\n" + "movl $0, (%%eax)\r\n" + "iretq\r\n"::""(LAPIC_EOI)); +} + +static void setup_apic_timer() +{ + mmio_write32(LAPIC_SVR, (LAPIC_SVR_ENABLE)); + mmio_write32(LAPIC_DIV_CONF_REG, LAPIC_DIV_CONF_128); + setup_interrupt_gate(TIMER_VECTOR_NUMBER, (uintptr_t)timer_handler); + mmio_write32(LAPIC_LVT_TIMER_REG, TIMER_VECTOR_NUMBER); +} + +int setup_interrupts() +{ + setup_interrupt_gate(0,(uintptr_t) exception_trampoline_0); + setup_interrupt_gate(1,(uintptr_t) exception_trampoline_1); + setup_interrupt_gate(2,(uintptr_t) exception_trampoline_2); + setup_interrupt_gate(3,(uintptr_t) exception_trampoline_3); + setup_interrupt_gate(4,(uintptr_t) exception_trampoline_4); + setup_interrupt_gate(5,(uintptr_t) exception_trampoline_5); + setup_interrupt_gate(6,(uintptr_t) exception_trampoline_6); + setup_interrupt_gate(7,(uintptr_t) exception_trampoline_7); + setup_interrupt_gate(8,(uintptr_t) exception_trampoline_8); + setup_interrupt_gate(9,(uintptr_t) exception_trampoline_9); + setup_interrupt_gate(10,(uintptr_t) exception_trampoline_10); + setup_interrupt_gate(11,(uintptr_t) exception_trampoline_11); + setup_interrupt_gate(12,(uintptr_t) exception_trampoline_12); + setup_interrupt_gate(13,(uintptr_t) exception_trampoline_13); + setup_interrupt_gate(14,(uintptr_t) exception_trampoline_14); + setup_interrupt_gate(15,(uintptr_t) exception_trampoline_15); + setup_interrupt_gate(16,(uintptr_t) exception_trampoline_16); + setup_interrupt_gate(17,(uintptr_t) exception_trampoline_17); + setup_interrupt_gate(18,(uintptr_t) exception_trampoline_18); + setup_interrupt_gate(19,(uintptr_t) exception_trampoline_19); + setup_interrupt_gate(20,(uintptr_t) exception_trampoline_20); + setup_interrupt_gate(21,(uintptr_t) exception_trampoline_21); + setup_interrupt_gate(22,(uintptr_t) exception_trampoline_22); + setup_interrupt_gate(23,(uintptr_t) exception_trampoline_23); + setup_interrupt_gate(24,(uintptr_t) exception_trampoline_24); + setup_interrupt_gate(25,(uintptr_t) exception_trampoline_25); + setup_interrupt_gate(26,(uintptr_t) exception_trampoline_26); + setup_interrupt_gate(27,(uintptr_t) exception_trampoline_27); + setup_interrupt_gate(28,(uintptr_t) exception_trampoline_28); + setup_interrupt_gate(29,(uintptr_t) exception_trampoline_29); + setup_interrupt_gate(30,(uintptr_t) exception_trampoline_30); + setup_interrupt_gate(31,(uintptr_t) exception_trampoline_31); + + setup_apic_timer(); + idt_descriptor.base = (uintptr_t)&idt_table; + idt_descriptor.limit = sizeof(idt_table) -1; + + asm ("lidt %0\r\n" : : "m"(idt_descriptor)); + asm ("sti\r\n"); + + return 0; +} + +void deinit_interrupts() +{ + idt_descriptor.base = (uintptr_t)NULL; + idt_descriptor.limit = 0xffff; + asm ("cli\r\n"); + asm ("lidt %0\r\n" : : "m"(idt_descriptor)); +} + +void wfi() +{ + setup_apic_timer(); + mmio_write32(LAPIC_INITIAL_CNT, TIMER_CNT); + hlt(); +}