x86: support cpu exceptions

pull/443/head
Marco Oliverio 2024-04-23 11:32:25 +02:00
parent 0833c4b1bf
commit 4bbe43e222
4 changed files with 250 additions and 0 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 <stdint.h>
int setup_interrupt_gate(int vnum, uintptr_t handler);
int setup_interrupts();
void deinit_interrupts();
void wfi();
#endif /* EXCEPTIONS_H */

View File

@ -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 <x86/common.h>
#include <x86/exceptions.h>
#include <stdint.h>
#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 <printf.h>
#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();
}