diff --git a/xen/arch/x86/include/asm/gen-idt.h b/xen/arch/x86/include/asm/gen-idt.h new file mode 100644 index 0000000000..9c8810edf9 --- /dev/null +++ b/xen/arch/x86/include/asm/gen-idt.h @@ -0,0 +1,122 @@ +/* This file is intended to be included multiple times. */ +/* + * Generator for IDT entries. + * + * Caller to provide GEN(vector, symbol, dpl, autogen) macro + * + * Symbols are 'entry_0xYY' if there is no better name available. Regular + * handlers set autogen=1, while manual (autogen=0) require the symbol to be + * implemented somewhere else. + */ + +#define DPL0 0 +#define DPL1 1 +#define DPL3 3 + +#define manual 0 +#define autogen 1 + +#define GEN16(i) \ + GEN(0x ## i ## 0, entry_0x ## i ## 0, DPL0, autogen); \ + GEN(0x ## i ## 1, entry_0x ## i ## 1, DPL0, autogen); \ + GEN(0x ## i ## 2, entry_0x ## i ## 2, DPL0, autogen); \ + GEN(0x ## i ## 3, entry_0x ## i ## 3, DPL0, autogen); \ + GEN(0x ## i ## 4, entry_0x ## i ## 4, DPL0, autogen); \ + GEN(0x ## i ## 5, entry_0x ## i ## 5, DPL0, autogen); \ + GEN(0x ## i ## 6, entry_0x ## i ## 6, DPL0, autogen); \ + GEN(0x ## i ## 7, entry_0x ## i ## 7, DPL0, autogen); \ + GEN(0x ## i ## 8, entry_0x ## i ## 8, DPL0, autogen); \ + GEN(0x ## i ## 9, entry_0x ## i ## 9, DPL0, autogen); \ + GEN(0x ## i ## a, entry_0x ## i ## a, DPL0, autogen); \ + GEN(0x ## i ## b, entry_0x ## i ## b, DPL0, autogen); \ + GEN(0x ## i ## c, entry_0x ## i ## c, DPL0, autogen); \ + GEN(0x ## i ## d, entry_0x ## i ## d, DPL0, autogen); \ + GEN(0x ## i ## e, entry_0x ## i ## e, DPL0, autogen); \ + GEN(0x ## i ## f, entry_0x ## i ## f, DPL0, autogen) + + +GEN(0x00, entry_DE, DPL0, manual); +GEN(0x01, entry_DB, DPL0, manual); +GEN(0x02, entry_NMI, DPL0, manual); +GEN(0x03, entry_BP, DPL3, manual); +GEN(0x04, entry_OF, DPL3, manual); +GEN(0x05, entry_BR, DPL0, manual); +GEN(0x06, entry_UD, DPL0, manual); +GEN(0x07, entry_NM, DPL0, manual); +GEN(0x08, entry_DF, DPL0, manual); +GEN(0x09, entry_0x09, DPL0, autogen); /* Coprocessor Segment Overrun */ +GEN(0x0a, entry_TS, DPL0, manual); +GEN(0x0b, entry_NP, DPL0, manual); +GEN(0x0c, entry_SS, DPL0, manual); +GEN(0x0d, entry_GP, DPL0, manual); +GEN(0x0e, early_page_fault, DPL0, manual); +GEN(0x0f, entry_0x0f, DPL0, autogen); /* PIC Spurious Interrupt Vector */ + +GEN(0x10, entry_MF, DPL0, manual); +GEN(0x11, entry_AC, DPL0, manual); +GEN(0x12, entry_MC, DPL0, manual); +GEN(0x13, entry_XM, DPL0, manual); +GEN(0x14, entry_VE, DPL0, autogen); +GEN(0x15, entry_CP, DPL0, manual); +GEN(0x16, entry_0x16, DPL0, autogen); +GEN(0x17, entry_0x17, DPL0, autogen); +GEN(0x18, entry_0x18, DPL0, autogen); +GEN(0x19, entry_0x19, DPL0, autogen); +GEN(0x1a, entry_0x1a, DPL0, autogen); +GEN(0x1b, entry_0x1b, DPL0, autogen); +GEN(0x1c, entry_HV, DPL0, autogen); +GEN(0x1d, entry_VC, DPL0, autogen); +GEN(0x1e, entry_SX, DPL0, autogen); +GEN(0x1f, entry_0x1f, DPL0, autogen); + +GEN16(2); +GEN16(3); +GEN16(4); +GEN16(5); +GEN16(6); +GEN16(7); + +#ifdef CONFIG_PV +GEN(0x80, entry_int80, DPL0, manual); +#else +GEN(0x80, entry_0x80, DPL0, autogen); +#endif + +GEN(0x81, entry_0x81, DPL0, autogen); + +#ifdef CONFIG_PV32 +GEN(0x82, entry_int82, DPL1, manual); +#else +GEN(0x82, entry_0x82, DPL0, autogen); +#endif + +GEN(0x83, entry_0x83, DPL0, autogen); +GEN(0x84, entry_0x84, DPL0, autogen); +GEN(0x85, entry_0x85, DPL0, autogen); +GEN(0x86, entry_0x86, DPL0, autogen); +GEN(0x87, entry_0x87, DPL0, autogen); +GEN(0x88, entry_0x88, DPL0, autogen); +GEN(0x89, entry_0x89, DPL0, autogen); +GEN(0x8a, entry_0x8a, DPL0, autogen); +GEN(0x8b, entry_0x8b, DPL0, autogen); +GEN(0x8c, entry_0x8c, DPL0, autogen); +GEN(0x8d, entry_0x8d, DPL0, autogen); +GEN(0x8e, entry_0x8e, DPL0, autogen); +GEN(0x8f, entry_0x8f, DPL0, autogen); + +GEN16(9); +GEN16(a); +GEN16(b); +GEN16(c); +GEN16(d); +GEN16(e); +GEN16(f); + +#undef autogen +#undef manual + +#undef DPL3 +#undef DPL1 +#undef DPL0 + +#undef GEN16 diff --git a/xen/arch/x86/include/asm/gen-idt.lds.h b/xen/arch/x86/include/asm/gen-idt.lds.h new file mode 100644 index 0000000000..a11ef7dd1c --- /dev/null +++ b/xen/arch/x86/include/asm/gen-idt.lds.h @@ -0,0 +1,27 @@ +/* + * Linker file fragment to help format the IDT correctly + * + * The IDT, having grown compatibly since the 16 bit days, has the entrypoint + * address field split into 3. x86 ELF lacks the @lo/@hi/etc relocation forms + * commonly found in other architectures for accessing a part of a resolved + * symbol address. + * + * However, the linker can perform the necessary calculations and provide them + * under new symbol names. We use this to generate the low and next 16 bits + * of the address for each handler. + * + * The upper 32 bits are always a constant as Xen's .text/data/rodata sits in + * a single aligned 1G range, so do not need calculating in this manner. + */ +#ifndef X86_IDT_GEN_LDS_H +#define X86_IDT_GEN_LDS_H + +#define GEN(vec, sym, dpl, auto) \ + PROVIDE_HIDDEN(IDT_ ## sym ## _ADDR1 = ABSOLUTE(((sym) & 0xffff))); \ + PROVIDE_HIDDEN(IDT_ ## sym ## _ADDR2 = ABSOLUTE((((sym) >> 16) & 0xffff))) + +#include + +#undef GEN + +#endif /* X86_IDT_GEN_LDS_H */ diff --git a/xen/arch/x86/traps-setup.c b/xen/arch/x86/traps-setup.c index ae600526cb..3ee2831958 100644 --- a/xen/arch/x86/traps-setup.c +++ b/xen/arch/x86/traps-setup.c @@ -3,9 +3,5 @@ * Configuration of event handling for all CPUs. */ #include -#include - -idt_entry_t __section(".bss.page_aligned") __aligned(PAGE_SIZE) - bsp_idt[X86_IDT_VECTORS]; DEFINE_PER_CPU_READ_MOSTLY(idt_entry_t *, idt); diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index d866e62625..84d0c29530 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -1229,6 +1229,82 @@ FUNC(trap_nop, 0) iretq END(trap_nop) +/* + * Automatically generated entrypoints, and IDT + */ + + .pushsection .data.page_aligned, "aw", @progbits +DATA(bsp_idt, PAGE_SIZE) + .popsection + +/* + * Write an IDT Entry. The linker provides us new _ADDR1/2 symbols calculated + * from \sym. + */ +.macro write_idte sym, dpl + .pushsection .data.page_aligned, "aw", @progbits + .word IDT_\sym\()_ADDR1 + .word __HYPERVISOR_CS + .word 0x8e00 | (\dpl << 13) /* Present, DPL, Interrupt Gate */ + .word IDT_\sym\()_ADDR2 + .long __XEN_VIRT_START >> 32 + .long 0 + .popsection +.endm + +/* + * Write an automatically generated stub. Vectors in the exception range keep + * the stack properly aligned by judging whether the CPU pushed an error code + * or not. + * + * Alignment is forced to 16 because that's the size of the interrupt stub + * with CET active. + */ +.macro gen_entry_stub vec, sym + +FUNC(\sym, 16) + ENDBR64 + + .if \vec < 0x20 /* Exception. */ + + test $8, %spl /* 64bit exception frames are 16 byte aligned, but the word */ + jz 1f /* size is 8 bytes. Check whether the processor gave us an */ + pushq $0 /* error code, and insert an empty one if not. */ +1: movb $\vec, EFRAME_entry_vector(%rsp) + jmp handle_exception + + .else /* Interrupt. */ + + pushq $0 + movb $\vec, EFRAME_entry_vector(%rsp) + jmp common_interrupt + + .endif +END(\sym) +.endm + +/* + * Generator. Write an entrypoint if necessary, and record an IDT entry. + */ +.macro gen vec, sym, dpl, auto + + .if \auto + gen_entry_stub \vec, \sym + .endif + + write_idte \sym, \dpl +.endm +#define GEN(v, s, d, a) gen vec=v, sym=s, dpl=d auto=a +#include +#undef GEN + + .pushsection .data.page_aligned, "aw", @progbits +END(bsp_idt) + .if . - bsp_idt != PAGE_SIZE + .error "Bad bsp_idt size, should be PAGE_SIZE" + .endif + .popsection + /* Table of automatically generated entry points. One per vector. */ .pushsection .init.rodata, "a", @progbits DATA(autogen_entrypoints, 8) diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 42217eaf24..d4dd6434c4 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -8,6 +8,8 @@ # define DECL_SECTION_WITH_LADDR #endif #include + +#include #include #include