arch/x86: allow idt to be available to link in all stages
Add Kconfig IDT_IN_EVERY_STAGE to optionally specify having the interrupt handling code available to all stages. In order to do this the idt setup is moved to a C module. The vecX entries are made global so that a table of references to all the interrupt vector entry points can be used to dynamically initialize the idt. The ramification for ramstage is that exceptions are initialized later (lib/hardwaremain.c). Not all stages initialize exceptions when this Kconfig variable is selected, but bootblock for the C, stages using assembly_entry.S, and of course ramstage do. Anything left out just needs a call to exception_init() at the right location. BUG=b:72728953 Change-Id: I4146a040e5e43bed7ccc6cb0a7dc2271f1e7b7fa Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: https://review.coreboot.org/25761 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Furquan Shaikh <furquan@google.com>
This commit is contained in:
parent
e74ba1984d
commit
4b032e457f
|
@ -302,3 +302,10 @@ config NUM_CAR_PAGE_TABLE_PAGES
|
|||
depends on PAGING_IN_CACHE_AS_RAM
|
||||
help
|
||||
The number of 4KiB pages that should be pre-allocated for page tables.
|
||||
|
||||
# Provide the interrupt handlers to every stage. Not all
|
||||
# stages may take advantage.
|
||||
config IDT_IN_EVERY_STAGE
|
||||
bool
|
||||
default n
|
||||
depends on ARCH_X86
|
||||
|
|
|
@ -92,6 +92,8 @@ ifeq ($(CONFIG_ARCH_BOOTBLOCK_X86_32)$(CONFIG_ARCH_BOOTBLOCK_X86_64),y)
|
|||
|
||||
bootblock-y += boot.c
|
||||
bootblock-y += cpu_common.c
|
||||
bootblock-$(CONFIG_IDT_IN_EVERY_STAGE) += exception.c
|
||||
bootblock-$(CONFIG_IDT_IN_EVERY_STAGE) += idt.S
|
||||
bootblock-y += memcpy.c
|
||||
bootblock-y += memset.c
|
||||
bootblock-$(CONFIG_COLLECT_TIMESTAMPS_TSC) += timestamp.c
|
||||
|
@ -169,6 +171,8 @@ endif # CONFIG_ARCH_BOOTBLOCK_X86_32 / CONFIG_ARCH_BOOTBLOCK_X86_64
|
|||
ifeq ($(CONFIG_ARCH_VERSTAGE_X86_32)$(CONFIG_ARCH_VERSTAGE_X86_64),y)
|
||||
|
||||
verstage-y += boot.c
|
||||
verstage-$(CONFIG_IDT_IN_EVERY_STAGE) += exception.c
|
||||
verstage-$(CONFIG_IDT_IN_EVERY_STAGE) += idt.S
|
||||
|
||||
verstage-$(CONFIG_ARCH_RAMSTAGE_X86_32) += cpu_common.c
|
||||
verstage-y += memset.c
|
||||
|
@ -206,6 +210,8 @@ romstage-y += cbmem.c
|
|||
romstage-y += cbfs_and_run.c
|
||||
romstage-$(CONFIG_ARCH_RAMSTAGE_X86_32) += cpu_common.c
|
||||
romstage-$(CONFIG_EARLY_EBDA_INIT) += ebda.c
|
||||
romstage-$(CONFIG_IDT_IN_EVERY_STAGE) += exception.c
|
||||
romstage-$(CONFIG_IDT_IN_EVERY_STAGE) += idt.S
|
||||
romstage-y += memcpy.c
|
||||
romstage-y += memmove.c
|
||||
romstage-y += memset.c
|
||||
|
@ -281,6 +287,8 @@ postcar-y += cbfs_and_run.c
|
|||
postcar-y += cbmem.c
|
||||
postcar-y += cpu_common.c
|
||||
postcar-$(CONFIG_EARLY_EBDA_INIT) += ebda.c
|
||||
postcar-$(CONFIG_IDT_IN_EVERY_STAGE) += exception.c
|
||||
postcar-$(CONFIG_IDT_IN_EVERY_STAGE) += idt.S
|
||||
postcar-y += exit_car.S
|
||||
postcar-y += memcpy.c
|
||||
postcar-y += memmove.c
|
||||
|
@ -343,6 +351,8 @@ ramstage-$(CONFIG_COOP_MULTITASKING) += thread_switch.S
|
|||
ramstage-$(CONFIG_COLLECT_TIMESTAMPS_TSC) += timestamp.c
|
||||
ramstage-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.S
|
||||
|
||||
smm-$(CONFIG_IDT_IN_EVERY_STAGE) += exception.c
|
||||
smm-$(CONFIG_IDT_IN_EVERY_STAGE) += idt.S
|
||||
smm-y += memcpy.c
|
||||
smm-y += memmove.c
|
||||
smm-y += memset.c
|
||||
|
|
|
@ -64,6 +64,9 @@ debug_spinloop:
|
|||
#endif
|
||||
|
||||
andl $0xfffffff0, %esp
|
||||
#if IS_ENABLED(CONFIG_IDT_IN_EVERY_STAGE)
|
||||
call exception_init
|
||||
#endif
|
||||
call car_stage_entry
|
||||
|
||||
/* This is here for linking purposes. */
|
||||
|
|
|
@ -81,28 +81,6 @@ _start:
|
|||
push $0
|
||||
push $0
|
||||
|
||||
/* Initialize the Interrupt Descriptor table */
|
||||
leal _idt, %edi
|
||||
leal vec0, %ebx
|
||||
movl $(0x10 << 16), %eax /* cs selector */
|
||||
|
||||
1: movw %bx, %ax
|
||||
movl %ebx, %edx
|
||||
movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */
|
||||
movl %eax, 0(%edi)
|
||||
movl %edx, 4(%edi)
|
||||
addl $6, %ebx
|
||||
addl $8, %edi
|
||||
cmpl $_idt_end, %edi
|
||||
jne 1b
|
||||
|
||||
/* Load the Interrupt descriptor table */
|
||||
#ifndef __x86_64__
|
||||
lidt idtarg
|
||||
#else
|
||||
// FIXME port table to x64 - lidt idtarg
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now we are finished. Memory is up, data is copied and
|
||||
* bss is cleared. Now we call the main routine and
|
||||
|
@ -145,7 +123,7 @@ gdb_stub_breakpoint:
|
|||
jmp int_hand
|
||||
#endif
|
||||
|
||||
.globl gdt, gdt_end, idtarg
|
||||
.globl gdt, gdt_end
|
||||
|
||||
gdtaddr:
|
||||
.word gdt_end - gdt - 1
|
||||
|
@ -227,14 +205,6 @@ gdt:
|
|||
#endif
|
||||
gdt_end:
|
||||
|
||||
idtarg:
|
||||
.word _idt_end - _idt - 1 /* limit */
|
||||
.long _idt
|
||||
.word 0
|
||||
_idt:
|
||||
.fill 20, 8, 0 # idt is uninitialized
|
||||
_idt_end:
|
||||
|
||||
.section ".text._start", "ax", @progbits
|
||||
#ifdef __x86_64__
|
||||
SetCodeSelector:
|
||||
|
|
|
@ -11,8 +11,14 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <arch/early_variables.h>
|
||||
#include <arch/exception.h>
|
||||
#include <commonlib/helpers.h>
|
||||
#include <compiler.h>
|
||||
#include <console/console.h>
|
||||
#include <console/streams.h>
|
||||
#include <rules.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_GDB_STUB)
|
||||
|
@ -518,3 +524,109 @@ void x86_exception(struct eregs *info)
|
|||
die("");
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GATE_P (1 << 15)
|
||||
#define GATE_DPL(x) (((x) & 0x3) << 13)
|
||||
#define GATE_SIZE_16 (0 << 11)
|
||||
#define GATE_SIZE_32 (1 << 11)
|
||||
|
||||
#define IGATE_FLAGS (GATE_P | GATE_DPL(0) | GATE_SIZE_32 | (0x6 << 8))
|
||||
|
||||
struct intr_gate {
|
||||
uint16_t offset_0;
|
||||
uint16_t segsel;
|
||||
uint16_t flags;
|
||||
uint16_t offset_1;
|
||||
#if ENV_X86_64
|
||||
uint32_t offset_2;
|
||||
uint32_t reserved;
|
||||
#endif
|
||||
} __packed;
|
||||
|
||||
/* Even though the vecX symbols are interrupt entry points just treat them
|
||||
like data to more easily get the pointer values in C. Because IDT entries
|
||||
format splits the offset field up one can't use the linker to resolve
|
||||
parts of a relecation on x86 ABI an array of pointers is used to gather
|
||||
the symbols. The IDT is initialized at runtime when exception_init() is
|
||||
called. */
|
||||
extern u8 vec0[], vec1[], vec2[], vec3[], vec4[], vec5[], vec6[], vec7[];
|
||||
extern u8 vec8[], vec9[], vec10[], vec11[], vec12[], vec13[], vec14[], vec15[];
|
||||
extern u8 vec16[], vec17[], vec18[], vec19[];
|
||||
|
||||
static const uintptr_t intr_entries[] = {
|
||||
(uintptr_t)vec0, (uintptr_t)vec1, (uintptr_t)vec2, (uintptr_t)vec3,
|
||||
(uintptr_t)vec4, (uintptr_t)vec5, (uintptr_t)vec6, (uintptr_t)vec7,
|
||||
(uintptr_t)vec8, (uintptr_t)vec9, (uintptr_t)vec10, (uintptr_t)vec11,
|
||||
(uintptr_t)vec12, (uintptr_t)vec13, (uintptr_t)vec14, (uintptr_t)vec15,
|
||||
(uintptr_t)vec16, (uintptr_t)vec17, (uintptr_t)vec18, (uintptr_t)vec19,
|
||||
};
|
||||
|
||||
static struct intr_gate idt[ARRAY_SIZE(intr_entries)] __aligned(8) CAR_GLOBAL;
|
||||
|
||||
static inline uint16_t get_cs(void)
|
||||
{
|
||||
uint16_t segment;
|
||||
|
||||
asm volatile (
|
||||
"mov %%cs, %0\n"
|
||||
: "=r" (segment)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
struct lidtarg {
|
||||
uint16_t limit;
|
||||
#if ENV_X86_32
|
||||
uint32_t base;
|
||||
#else
|
||||
uint64_t base;
|
||||
#endif
|
||||
} __packed;
|
||||
|
||||
/* This global is for src/cpu/x86/lapic/secondary.S usage which is only
|
||||
used during ramstage. */
|
||||
struct lidtarg idtarg;
|
||||
|
||||
static void load_idt(void *table, size_t sz)
|
||||
{
|
||||
struct lidtarg lidtarg = {
|
||||
.limit = sz - 1,
|
||||
.base = (uintptr_t)table,
|
||||
};
|
||||
|
||||
asm volatile (
|
||||
"lidt %0"
|
||||
:
|
||||
: "m" (lidtarg)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
if (ENV_RAMSTAGE)
|
||||
memcpy(&idtarg, &lidtarg, sizeof(idtarg));
|
||||
}
|
||||
|
||||
asmlinkage void exception_init(void)
|
||||
{
|
||||
int i;
|
||||
uint16_t segment;
|
||||
struct intr_gate *gates = car_get_var_ptr(idt);
|
||||
|
||||
segment = get_cs();
|
||||
gates = car_get_var_ptr(idt);
|
||||
|
||||
/* Initialize IDT. */
|
||||
for (i = 0; i < ARRAY_SIZE(idt); i++) {
|
||||
gates[i].offset_0 = intr_entries[i];
|
||||
gates[i].segsel = segment;
|
||||
gates[i].flags = IGATE_FLAGS;
|
||||
gates[i].offset_1 = intr_entries[i] >> 16;
|
||||
#if ENV_X86_64
|
||||
gates[i].offset_2 = intr_entries[i] >> 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
load_idt(gates, sizeof(idt));
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
#else
|
||||
.code32
|
||||
#endif
|
||||
.global vec0
|
||||
.global vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9
|
||||
.global vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17, vec18, vec19
|
||||
vec0:
|
||||
push $0 /* error code */
|
||||
push $0 /* vector */
|
||||
|
|
|
@ -30,6 +30,13 @@
|
|||
#ifndef _ARCH_EXCEPTION_H
|
||||
#define _ARCH_EXCEPTION_H
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <rules.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_IDT_IN_EVERY_STAGE) || ENV_RAMSTAGE
|
||||
asmlinkage void exception_init(void);
|
||||
#else
|
||||
static inline void exception_init(void) { /* not implemented */ }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue