Message ID | 20250224160509.1117847-7-andrew.cooper3@citrix.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | x86/IDT: Generate the IDT at build time | expand |
On 24.02.2025 17:05, Andrew Cooper wrote: > --- /dev/null > +++ b/xen/arch/x86/include/asm/gen-idt.h > @@ -0,0 +1,121 @@ > +/* > + * 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. > + */ Doesn't this need something for Eclair to spot the deliberate absence of a header guard? > +#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) Would this better be #ifdef CONFIG_PV32 GEN(0x04, entry_OF, DPL3, manual) #else GEN(0x04, entry_0x04, DPL0, autogen) #endif ? (Not necessarily in this patch, but in principle.) > --- /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))); Not sure if Eclair gets to see this at all, but maybe better parenthesize sym also in the latter instance? As to the final semicolon - ideally this would be on the use sites of GEN(), for things to look more C-ish. Yet I won't insist, as gen-idt.h ends up looking sufficiently uniform for this to not be a major concern. > --- 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 Just to mention it: I've come across a number of issues with the not-really- standard relocation types needed to express the linker-generated-symbol references here. For the purpose here I think we're okay. > + .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. Yet only because we still don't put INT3 after the JMPs to guard against SLS. (I keep carrying an ugly patch doing so.) > + */ > +.macro gen_entry 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 \vec, \sym > + .endif > + > + write_idte \sym, \dpl > +.endm > +#define GEN(v, s, d, a) gen vec=v, sym=s, dpl=d auto=a; > +#include <asm/gen-idt.h> > +#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 Again something certainly not for this patch, and probably also not for this series: In principle, with the BSP IDT fully generated at build time, it ought to be possible to move to .rodata.page_aligned. Jan
On 26/02/2025 12:39 pm, Jan Beulich wrote: > On 24.02.2025 17:05, Andrew Cooper wrote: >> --- /dev/null >> +++ b/xen/arch/x86/include/asm/gen-idt.h >> @@ -0,0 +1,121 @@ >> +/* >> + * 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. >> + */ > Doesn't this need something for Eclair to spot the deliberate absence of a > header guard? Eclair doesn't complain, although I'm not entirely sure why. >> +#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) > Would this better be > > #ifdef CONFIG_PV32 > GEN(0x04, entry_OF, DPL3, manual) > #else > GEN(0x04, entry_0x04, DPL0, autogen) > #endif > > ? (Not necessarily in this patch, but in principle.) No. INTO can still be used in compatibility mode segment. Furthermore, for any exception we know about, we want a manual one to avoid the error-code realignment logic where possible. > >> --- /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))); > Not sure if Eclair gets to see this at all, but maybe better parenthesize > sym also in the latter instance? Oh, yes. > As to the final semicolon - ideally this would be on the use sites of GEN(), > for things to look more C-ish. Yet I won't insist, as gen-idt.h ends up > looking sufficiently uniform for this to not be a major concern. I'm afraid it's necessary (and too in entry stubs). It's the GEN16() macro, which expands 16x GEN() on the same line. I could drop the GEN16() macro and do everything longhand, but I suspect you'd like that even less. ~Andrew
On 26.02.2025 14:37, Andrew Cooper wrote: > On 26/02/2025 12:39 pm, Jan Beulich wrote: >> On 24.02.2025 17:05, Andrew Cooper wrote: >>> --- /dev/null >>> +++ b/xen/arch/x86/include/asm/gen-idt.h >>> @@ -0,0 +1,121 @@ >>> +/* >>> + * 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. >>> + */ >> Doesn't this need something for Eclair to spot the deliberate absence of a >> header guard? > > Eclair doesn't complain, although I'm not entirely sure why. > >>> +#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) >> Would this better be >> >> #ifdef CONFIG_PV32 >> GEN(0x04, entry_OF, DPL3, manual) >> #else >> GEN(0x04, entry_0x04, DPL0, autogen) >> #endif >> >> ? (Not necessarily in this patch, but in principle.) > > No. INTO can still be used in compatibility mode segment. Oh, of course. > Furthermore, for any exception we know about, we want a manual one to > avoid the error-code realignment logic where possible. Why would that not apply to Co-processor Segment Overrun then? >>> --- /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))); >> Not sure if Eclair gets to see this at all, but maybe better parenthesize >> sym also in the latter instance? > > Oh, yes. > >> As to the final semicolon - ideally this would be on the use sites of GEN(), >> for things to look more C-ish. Yet I won't insist, as gen-idt.h ends up >> looking sufficiently uniform for this to not be a major concern. > > I'm afraid it's necessary (and too in entry stubs). > > It's the GEN16() macro, which expands 16x GEN() on the same line. Right, as said - the semicolons would need putting after every GEN() invocation, including in GEN16() (with the final one likely excluded, for the semicolon then to appear on its use site). > I could drop the GEN16() macro and do everything longhand, but I suspect > you'd like that even less. Indeed. Jan
On 26/02/2025 2:14 pm, Jan Beulich wrote: > On 26.02.2025 14:37, Andrew Cooper wrote: >> On 26/02/2025 12:39 pm, Jan Beulich wrote: >>> On 24.02.2025 17:05, Andrew Cooper wrote: >>>> --- /dev/null >>>> +++ b/xen/arch/x86/include/asm/gen-idt.h >>>> @@ -0,0 +1,121 @@ >>>> +/* >>>> + * 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. >>>> + */ >>> Doesn't this need something for Eclair to spot the deliberate absence of a >>> header guard? >> Eclair doesn't complain, although I'm not entirely sure why. >> >>>> +#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) >>> Would this better be >>> >>> #ifdef CONFIG_PV32 >>> GEN(0x04, entry_OF, DPL3, manual) >>> #else >>> GEN(0x04, entry_0x04, DPL0, autogen) >>> #endif >>> >>> ? (Not necessarily in this patch, but in principle.) >> No. INTO can still be used in compatibility mode segment. > Oh, of course. > >> Furthermore, for any exception we know about, we want a manual one to >> avoid the error-code realignment logic where possible. > Why would that not apply to Co-processor Segment Overrun then? It kinda does apply. We've never ever had CSO handler (hence why it was autogen'd the first time I tried making this more robust), and you didn't like my patch to autogen the exception entries. The CSO handler (and SPV) are the only two we can be pretty confident will never trigger on today's hardware, yet you also didn't like my suggestion of having them Not Present. >>>> --- /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))); >>> Not sure if Eclair gets to see this at all, but maybe better parenthesize >>> sym also in the latter instance? >> Oh, yes. >> >>> As to the final semicolon - ideally this would be on the use sites of GEN(), >>> for things to look more C-ish. Yet I won't insist, as gen-idt.h ends up >>> looking sufficiently uniform for this to not be a major concern. >> I'm afraid it's necessary (and too in entry stubs). >> >> It's the GEN16() macro, which expands 16x GEN() on the same line. > Right, as said - the semicolons would need putting after every GEN() invocation, > including in GEN16() (with the final one likely excluded, for the semicolon then > to appear on its use site). Ah, I see what you mean. I'll see if I can make it work. ~Andrew
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 000000000000..a345af0ec774 --- /dev/null +++ b/xen/arch/x86/include/asm/gen-idt.h @@ -0,0 +1,121 @@ +/* + * 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 000000000000..997cec0c4de1 --- /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 <asm/gen-idt.h> + +#undef GEN + +#endif /* X86_IDT_GEN_LDS_H */ diff --git a/xen/arch/x86/traps-init.c b/xen/arch/x86/traps-init.c index ae600526cbe3..3ee28319584d 100644 --- a/xen/arch/x86/traps-init.c +++ b/xen/arch/x86/traps-init.c @@ -3,9 +3,5 @@ * Configuration of event handling for all CPUs. */ #include <asm/idt.h> -#include <asm/page.h> - -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 d866e626257b..313711a01184 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 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 \vec, \sym + .endif + + write_idte \sym, \dpl +.endm +#define GEN(v, s, d, a) gen vec=v, sym=s, dpl=d auto=a; +#include <asm/gen-idt.h> +#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 42217eaf2485..d4dd6434c466 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 <xen/xen.lds.h> + +#include <asm/gen-idt.lds.h> #include <asm/page.h> #include <asm/trampoline.h>
... rather than dynamically at boot time. Aside from less runtime overhead, this approach is less fragile than the preexisting autogen stubs mechanism. We can manage this with some linker calculations. See patch comments for full details. For simplicity, we create a new set of entry stubs here, and clean up the old ones in the subsequent patch. bsp_idt[] needs to move from .bss to .data. No functional change yet; the boot path still (re)writes bsp_idt[] at this juncture. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> --- CC: Jan Beulich <JBeulich@suse.com> CC: Roger Pau Monné <roger.pau@citrix.com> There's something differnet about LLD vs LD. Without the ABSOLUTE() in gen-idt.lds.h, LD is fine but LLD puts out symbols in the form: x86_IDT_entry_0xff_ADDR1|0000000000002fb0| t | NOTYPE| | |.text x86_IDT_entry_0xff_ADDR2|0000000000004020| a | NOTYPE| | |*ABS* which causes a slew of errors making symbols for xen-syms: .xen-syms.0.S:20:8: error: out of range literal value .long 0x15a0 - (((((((261 >> 8) * 0xffff000000000000) | (261 << 39))) + ((1 << 39) / 2)) + (64 << 30)) + (1 << 30)) ^ owing to half the symbols being t rather than a. Moreover, this is reliable for the full FreeBSD builds, but interminttent on randconfig. I haven't figured out which other option is having an effect. Forcing them all to absolute works in both toolchains. --- xen/arch/x86/include/asm/gen-idt.h | 121 +++++++++++++++++++++++++ xen/arch/x86/include/asm/gen-idt.lds.h | 27 ++++++ xen/arch/x86/traps-init.c | 4 - xen/arch/x86/x86_64/entry.S | 76 ++++++++++++++++ xen/arch/x86/xen.lds.S | 2 + 5 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 xen/arch/x86/include/asm/gen-idt.h create mode 100644 xen/arch/x86/include/asm/gen-idt.lds.h