xen: get rid of paravirt op adjust_exception_frame
Subsystems (4)
Juergen Gross
maintainerPATCH v2 1/1 xen: get rid of paravirt op adjust_exception_frame
When running as Xen pv-guest the exception frame on the stack contains %r11 and %rcx additional to the other data pushed by the processor.
Instead of having a paravirt op being called for each exception type prepend the Xen specific code to each exception entry. When running as Xen pv-guest just use the exception entry with prepended instructions, otherwise use the entry without the Xen specific code.
--- arch/x86/entry/entry_64.S | 22 ++------------ arch/x86/entry/entry_64_compat.S | 1 - arch/x86/include/asm/desc.h | 16 ++++++++++ arch/x86/include/asm/paravirt.h | 5 --- arch/x86/include/asm/paravirt_types.h | 4 --- arch/x86/include/asm/proto.h | 3 ++ arch/x86/include/asm/traps.h | 51 +++++++++++++++++++++++++++++-- arch/x86/kernel/asm-offsets_64.c | 1 - arch/x86/kernel/paravirt.c | 3 -- arch/x86/kernel/traps.c | 57 ++++++++++++++++++----------------- arch/x86/xen/enlighten_pv.c | 16 +++++----- arch/x86/xen/irq.c | 3 -- arch/x86/xen/xen-asm_64.S | 45 ++++++++++++++++++++++++--- arch/x86/xen/xen-ops.h | 1 - 14 files changed, 147 insertions(+), 81 deletions(-)
arch/x86/entry/entry_64.S +3 -19
@@ -745,7 +745,6 @@ ENTRY(\sym) .endif ASM_CLAC - PARAVIRT_ADJUST_EXCEPTION_FRAME .ifeq \has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */
@@ -901,7 +900,7 @@ ENTRY(do_softirq_own_stack) END(do_softirq_own_stack) #ifdef CONFIG_XEN -idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 +idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0 /* * A note on the "critical region" in our callback handler.
@@ -967,8 +966,6 @@ ENTRY(xen_failsafe_callback) movq 8(%rsp), %r11 addq $0x30, %rsp pushq $0 /* RIP */ - pushq %r11 - pushq %rcx jmp general_protection 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ movq (%rsp), %rcx
@@ -997,9 +994,8 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN -idtentry xen_debug do_debug has_error_code=0 -idtentry xen_int3 do_int3 has_error_code=0 -idtentry xen_stack_segment do_stack_segment has_error_code=1 +idtentry xendebug do_debug has_error_code=0 +idtentry xenint3 do_int3 has_error_code=0 #endif idtentry general_protection do_general_protection has_error_code=1
@@ -1161,18 +1157,6 @@ END(error_exit) /* Runs on exception stack */ ENTRY(nmi) /* - * Fix up the exception frame if we're on Xen. - * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most - * one value to the stack on native, so it may clobber the rdx - * scratch slot, but it won't clobber any of the important - * slots past it. - * - * Xen is a different story, because the Xen frame itself overlaps - * the "NMI executing" variable. - */ - PARAVIRT_ADJUST_EXCEPTION_FRAME - - /* * We allow breakpoints in NMIs. If a breakpoint occurs, then * the iretq it performs will take us out of NMI context. * This means that we can have nested NMIs where the next
arch/x86/entry/entry_64_compat.S +0 -1
@@ -294,7 +294,6 @@ ENTRY(entry_INT80_compat) /* * Interrupts are off on entry. */ - PARAVIRT_ADJUST_EXCEPTION_FRAME ASM_CLAC /* Do this early to minimize exposure */ SWAPGS
arch/x86/include/asm/desc.h +16 -0
@@ -9,6 +9,8 @@#include <linux/smp.h> #include <linux/percpu.h> +#include <xen/xen.h> +static inline void fill_ldt (struct desc_struct *desc,const struct user_desc *info) { desc->limit0 = info->limit &0x0ffff ;
@@ -83,6 +85,12 @@ static inline phys_addr_t get_cpu_gdt_paddr(unsigned int cpu)return per_cpu_ptr_to_phys (get_cpu_gdt_rw (cpu)); } +#if defined(CONFIG_X86_64 ) && defined(CONFIG_XEN_PV ) +#define pv_trap_entry (name) (void *)(xen_pv_domain() ? xen_ ## name : name) +#else +#define pv_trap_entry (name) (void *)(name) +#endif +#ifdef CONFIG_X86_64 static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
@@ -482,6 +490,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr, 0, 0, __KERNEL_CS); \ } while (0) +#define set_intr_gate_pv (n, addr) \ + do { \ + set_intr_gate_notrace(n, pv_trap_entry(addr)); \ + _trace_set_gate(n, GATE_INTERRUPT, \ + pv_trap_entry(trace_##addr), \ + 0, 0, __KERNEL_CS); \ + } while (0) +extern int first_system_vector;/* used_vectors is BITMAP for irq is not managed by percpu vector_irq */ extern unsigned long used_vectors[];
arch/x86/include/asm/paravirt.h +0 -5
@@ -960,11 +960,6 @@ extern void default_banner(void);#define GET_CR2_INTO_RAX \ call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2) -#define PARAVIRT_ADJUST_EXCEPTION_FRAME \ - PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \ - CLBR_NONE, \ - call PARA_INDIRECT(pv_irq_ops+PV_IRQ_adjust_exception_frame)) -#define USERGS_SYSRET64 \ PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ CLBR_NONE, \
arch/x86/include/asm/paravirt_types.h +0 -4
@@ -195,10 +195,6 @@ struct pv_irq_ops {void (*safe_halt)(void );void (*halt)(void ); - -#ifdef CONFIG_X86_64 -void (*adjust_exception_frame)(void ); -#endif } __no_randomize_layout;struct pv_mmu_ops {
arch/x86/include/asm/proto.h +3 -0
@@ -24,6 +24,9 @@ void entry_SYSENTER_compat(void);void __end_entry_SYSENTER_compat (void );void entry_SYSCALL_compat (void );void entry_INT80_compat (void ); +#if defined(CONFIG_X86_64 ) && defined(CONFIG_XEN_PV ) +void xen_entry_INT80_compat (void ); +#endif #endif void x86_configure_nx (void );
arch/x86/include/asm/traps.h +48 -3
69 lines not on this page · raw message
arch/x86/kernel/asm-offsets_64.c +0 -1
@@ -20,7 +20,6 @@ static char syscalls_ia32[] = {int main (void ) {#ifdef CONFIG_PARAVIRT -OFFSET (PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame);OFFSET (PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);OFFSET (PV_CPU_swapgs, pv_cpu_ops, swapgs);BLANK ();
arch/x86/kernel/paravirt.c +0 -3
@@ -319,9 +319,6 @@ __visible struct pv_irq_ops pv_irq_ops = { .irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable), .safe_halt = native_safe_halt, .halt = native_halt, -#ifdef CONFIG_X86_64 - .adjust_exception_frame = paravirt_nop, -#endif }; __visible struct pv_cpu_ops pv_cpu_ops = {
arch/x86/kernel/traps.c +30 -27
109 lines not on this page · raw message
arch/x86/xen/enlighten_pv.c +7 -9
@@ -598,24 +598,22 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,* so we should never see them. Warn if * there's an unexpected IST-using fault handler. */ -if (addr == (unsigned long )debug) - addr = (unsigned long )xen_debug; -else if (addr == (unsigned long )int3) - addr = (unsigned long )xen_int3; -else if (addr == (unsigned long )stack_segment) - addr = (unsigned long )xen_stack_segment; -else if (addr == (unsigned long )double_fault) { +if (addr == (unsigned long )xen_debug) + addr = (unsigned long )xen_xendebug; +else if (addr == (unsigned long )xen_int3) + addr = (unsigned long )xen_xenint3; +else if (addr == (unsigned long )xen_double_fault) {/* Don't need to handle these */ return 0 ; #ifdef CONFIG_X86_MCE - }else if (addr == (unsigned long )machine_check) { + }else if (addr == (unsigned long )xen_machine_check) {/* * when xen hypervisor inject vMCE to guest, * use native mce handler to handle it */ ;#endif - }else if (addr == (unsigned long )nmi) + }else if (addr == (unsigned long )xen_nmi)/* * Use the native version as well. */
arch/x86/xen/irq.c +0 -3
@@ -123,9 +123,6 @@ static const struct pv_irq_ops xen_irq_ops __initconst = { .safe_halt = xen_safe_halt, .halt = xen_halt, -#ifdef CONFIG_X86_64 - .adjust_exception_frame = xen_adjust_exception_frame, -#endif };void __init xen_init_irq_ops (void )
arch/x86/xen/xen-asm_64.S +40 -5
51 lines not on this page · raw message
arch/x86/xen/xen-ops.h +0 -1
@@ -145,7 +145,6 @@ DECL_ASM(void, xen_restore_fl_direct, unsigned long); __visible void xen_iret(void); __visible void xen_sysret32(void); __visible void xen_sysret64(void); -__visible void xen_adjust_exception_frame(void);extern int xen_panic_handler_init (void );
Signature · 1 line
2.12.3
Quoted 71 lines · Juergen Gross
When running as Xen pv-guest the exception frame on the stack contains %r11 and %rcx additional to the other data pushed by the processor.
Instead of having a paravirt op being called for each exception type prepend the Xen specific code to each exception entry. When running as Xen pv-guest just use the exception entry with prepended instructions, otherwise use the entry without the Xen specific code.
Signed-off-by Juergen Gross <[email protected]>--- arch/x86/entry/entry_64.S | 22 ++------------ arch/x86/entry/entry_64_compat.S | 1 - arch/x86/include/asm/desc.h | 16 ++++++++++ arch/x86/include/asm/paravirt.h | 5 --- arch/x86/include/asm/paravirt_types.h | 4 --- arch/x86/include/asm/proto.h | 3 ++ arch/x86/include/asm/traps.h | 51 +++++++++++++++++++++++++++++-- arch/x86/kernel/asm-offsets_64.c | 1 - arch/x86/kernel/paravirt.c | 3 -- arch/x86/kernel/traps.c | 57 ++++++++++++++++++----------------- arch/x86/xen/enlighten_pv.c | 16 +++++----- arch/x86/xen/irq.c | 3 -- arch/x86/xen/xen-asm_64.S | 45 ++++++++++++++++++++++++--- arch/x86/xen/xen-ops.h | 1 - 14 files changed, 147 insertions(+), 81 deletions(-)arch/x86/entry/entry_64.S +3
-7@@ -745,7 +745,6 @@ ENTRY(\sym) .endif ASM_CLAC - PARAVIRT_ADJUST_EXCEPTION_FRAME .ifeq \has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */@@ -901,7 +900,7 @@ ENTRY(do_softirq_own_stack) END(do_softirq_own_stack) #ifdef CONFIG_XEN -idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 +idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0 /* * A note on the "critical region" in our callback handler.@@ -967,8 +966,6 @@ ENTRY(xen_failsafe_callback) movq 8(%rsp), %r11 addq $0x30, %rsp pushq $0 /* RIP */ - pushq %r11 - pushq %rcx jmp general_protection 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ movq (%rsp), %rcx@@ -997,9 +994,8 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN -idtentry xen_debug do_debug has_error_code=0 -idtentry xen_int3 do_int3 has_error_code=0 -idtentry xen_stack_segment do_stack_segment has_error_code=1 +idtentry xendebug do_debug has_error_code=0 +idtentry xenint3 do_int3 has_error_code=0 #endif idtentry general_protection do_general_protection has_error_code=1@@ -1161,18 +1157,6 @@ END(error_exit) /* Runs on exception stack */ ENTRY(nmi)
arch/x86/entry/entry_64.S END(error_exit) · line 1172
Quoted 10 lines
arch/x86/entry/entry_64.S +0
-9/* - * Fix up the exception frame if we're on Xen. - * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most - * one value to the stack on native, so it may clobber the rdx - * scratch slot, but it won't clobber any of the important - * slots past it. - * - * Xen is a different story, because the Xen frame itself overlaps - * the "NMI executing" variable. - */
Based on Andrew Cooper's email, it sounds like this function is just straight-up broken on Xen PV. Maybe change the comment to "XXX:
broken on Xen PV" or similar.
arch/x86/entry/entry_64.S END(error_exit)
Quoted 6 lines
arch/x86/entry/entry_64.S +6
-0+#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) +#define pv_trap_entry(name) (void *)(xen_pv_domain() ? xen_ ## name : name) +#else +#define pv_trap_entry(name) (void *)(name) +#endif +
Seems reasonable to me.
Quoted 4 lines
#ifdef
CONFIG_X86_64static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
arch/x86/entry/entry_64.S static inline void _set_gate(int gate, unsigned type, void *addr, · line 499
Quoted 10 lines
arch/x86/entry/entry_64.S +7
-0@@ -482,6 +490,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr, 0, 0, __KERNEL_CS); \ } while (0) +#define set_intr_gate_pv(n, addr) \ + do { \ + set_intr_gate_notrace(n, pv_trap_entry(addr)); \ + _trace_set_gate(n, GATE_INTERRUPT, \ + pv_trap_entry(trace_##addr), \ + 0, 0, __KERNEL_CS); \ + } while (0)
Any reason this can't be set_intr_gate((n), pv_trap_entry(addr))? Or does that get preprocessed wrong?
arch/x86/include/asm/traps.h asmlinkage void divide_error(void); · line 17
Quoted 13 lines
arch/x86/include/asm/traps.h +2
-3@@ -13,9 +13,8 @@ asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); asmlinkage void int3(void); -asmlinkage void xen_debug(void); -asmlinkage void xen_int3(void); -asmlinkage void xen_stack_segment(void); +asmlinkage void xendebug(void); +asmlinkage void xenint3(void);
What are xendebug and xenint3 for? Are they because they don't use IST on Xen?
Quoted 6 lines
arch/x86/include/asm/traps.h +0
-0__visible struct pv_cpu_ops pv_cpu_ops = {arch/x86/kernel/traps.c +0
-0
arch/x86/kernel/traps.c void __init early_trap_init(void) · line 953
Quoted 9 lines
arch/x86/kernel/traps.c +1
-1@@ -946,15 +946,15 @@ void __init early_trap_init(void)* early stage. DEBUG_STACK will be equipped after cpu_init() in * trap_init(). * -* We don't need to set trace_idt_table like set_intr_gate(), +* We don't need to set trace_idt_table like set_intr_gate_pv(), * since we don't have trace_debug and it will be reset to * 'debug' in trap_init() by set_intr_gate_ist(). */ set_intr_gate_notrace (X86_TRAP_DB , debug);
This is confusing IMO. Maybe just drop the comment change? But how does this work at all on Xen?
Quoted 6 lines
arch/x86/kernel/traps.c +0
-6-set_intr_gate (X86_TRAP_OLD_MF , coprocessor_segment_overrun); -set_intr_gate (X86_TRAP_TS , invalid_TSS); -set_intr_gate (X86_TRAP_NP , segment_not_present); -set_intr_gate (X86_TRAP_SS , stack_segment); -set_intr_gate (X86_TRAP_GP , general_protection); -set_intr_gate (X86_TRAP_SPURIOUS , spurious_interrupt_bug);
arch/x86/kernel/traps.c void __init trap_init(void) · line 1001
Quoted 10 lines
arch/x86/kernel/traps.c +8
-2-set_intr_gate (X86_TRAP_MF , coprocessor_error); -set_intr_gate (X86_TRAP_AC , alignment_check); +set_intr_gate_pv (X86_TRAP_OLD_MF , coprocessor_segment_overrun); +set_intr_gate_pv (X86_TRAP_TS , invalid_TSS); +set_intr_gate_pv (X86_TRAP_NP , segment_not_present); +set_intr_gate_pv (X86_TRAP_SS , stack_segment); +set_intr_gate_pv (X86_TRAP_GP , general_protection); +set_intr_gate_pv (X86_TRAP_SPURIOUS , spurious_interrupt_bug); +set_intr_gate_pv (X86_TRAP_MF , coprocessor_error); +set_intr_gate_pv (X86_TRAP_AC , alignment_check);
Hmm. I'm okay with this, but I'm wondering whether it might be nice to try to have a pv op that changes what IDT writes do and remaps the function pointer. Like...
Quoted 12 lines
arch/x86/xen/enlighten_pv.c +0
-4@@ -598,24 +598,22 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,* so we should never see them. Warn if * there's an unexpected IST-using fault handler. */ -if (addr == (unsigned long )debug) - addr = (unsigned long )xen_debug; -else if (addr == (unsigned long )int3) - addr = (unsigned long )xen_int3;
arch/x86/xen/enlighten_pv.c static int cvt_gate_to_trap(int vector, const gate_desc *val, · line 607
Quoted 10 lines
arch/x86/xen/enlighten_pv.c +5
-3-else if (addr == (unsigned long )stack_segment) - addr = (unsigned long )xen_stack_segment; -else if (addr == (unsigned long )double_fault) { +if (addr == (unsigned long )xen_debug) + addr = (unsigned long )xen_xendebug; +else if (addr == (unsigned long )xen_int3) + addr = (unsigned long )xen_xenint3; +else if (addr == (unsigned long )xen_double_fault) {/* Don't need to handle these */ return 0 ;
...this? Can't this list just be extended to handle all of the pv entries instead of using the macro magic?
Quoted 43 lines
arch/x86/xen/xen-asm_64.S +30
-5@@ -22,11 +22,46 @@ #include "xen-asm.h" -ENTRY(xen_adjust_exception_frame) - mov 8+0(%rsp), %rcx - mov 8+8(%rsp), %r11 - ret $16 -ENDPROC(xen_adjust_exception_frame) +.macro xen_pv_trap name +ENTRY(xen_\name) + pop %rcx + pop %r11 + jmp \name +END(xen_\name) +.endm + +xen_pv_trap divide_error +xen_pv_trap debug +xen_pv_trap xendebug +xen_pv_trap int3 +xen_pv_trap xenint3 +xen_pv_trap nmi +xen_pv_trap overflow +xen_pv_trap bounds +xen_pv_trap invalid_op +xen_pv_trap device_not_available +xen_pv_trap double_fault +xen_pv_trap coprocessor_segment_overrun +xen_pv_trap invalid_TSS +xen_pv_trap segment_not_present +xen_pv_trap stack_segment +xen_pv_trap general_protection +xen_pv_trap page_fault +xen_pv_trap async_page_fault +xen_pv_trap spurious_interrupt_bug +xen_pv_trap coprocessor_error +xen_pv_trap alignment_check +#ifdef CONFIG_X86_MCE
arch/x86/xen/xen-asm_64.S line 64
Quoted 10 lines
arch/x86/xen/xen-asm_64.S +10
-0+xen_pv_trap machine_check +#endif /* CONFIG_X86_MCE */ +xen_pv_trap simd_coprocessor_error +#ifdef CONFIG_IA32_EMULATION +xen_pv_trap entry_INT80_compat +#endif +#ifdef CONFIG_TRACING +xen_pv_trap trace_page_fault +#endif +xen_pv_trap hypervisor_callback
I like this.
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make a xen_nmi that's actually correct (should be trivial)
#1 is here:
Can you test it and, if you like it, either add it to your series or ack it? If you have extra spare cycles, you could try to do #2 and #3, too :) For #2, it might actually make sense to rig up the Xen sysenter entry to redirect to entry_SYSCALL_compat or even an entirely new entry point -- SYSENTER is really weird.
--Andy
Quoted 9 lines · Andy Lutomirski
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
If the
/* Zero-extending 32-bit regs, do not remove */
movl %eax, %eax
comments are to be believed, then the entry logic needs reordering slightly to:
GLOBAL(entry_*_compat_after_hwframe)
movl %eax, %eax /* Zero-extending 32-bit regs, do not remove */
pushq %rax /* pt_regs->orig_ax */
~Andrew
(It is unfortunate this can't be simplified to pushq %eax)
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Quoted 16 lines · Andrew Cooper
Quoted 9 lines · Andy Lutomirski
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
If the
/* Zero-extending 32-bit regs, do not remove */
movl %eax, %eax
Quoted 6 lines
comments are to be believed, then the entry logic needs reordering slightly to:
GLOBAL(entry_*_compat_after_hwframe)
movl %eax, %eax /* Zero-extending 32-bit regs, do not remove */
pushq %rax /*pt_regs->orig_ax*/
D'oh, right. Juergen, want to make that change?
Juergen Gross
maintainerQuoted 17 lines · Andy Lutomirski
Quoted 16 lines · Andrew Cooper
Quoted 9 lines · Andy Lutomirski
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
If the
/* Zero-extending 32-bit regs, do not remove */
movl %eax, %eax
Quoted 8 lines
Quoted 6 lines
comments are to be believed, then the entry logic needs reordering slightly to:
GLOBAL(entry_*_compat_after_hwframe)
movl %eax, %eax /* Zero-extending 32-bit regs, do not remove */
pushq %rax /*pt_regs->orig_ax*/D'oh, right. Juergen, want to make that change?
Hmm, I'd prefer you sending an update which I could test and ack then.
Juergen
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Juergen Gross
maintainerQuoted 17 lines · Andy Lutomirski
Quoted 16 lines · Andrew Cooper
Quoted 9 lines · Andy Lutomirski
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
If the
/* Zero-extending 32-bit regs, do not remove */
movl %eax, %eax
Quoted 8 lines
Quoted 6 lines
comments are to be believed, then the entry logic needs reordering slightly to:
GLOBAL(entry_*_compat_after_hwframe)
movl %eax, %eax /* Zero-extending 32-bit regs, do not remove */
pushq %rax /*pt_regs->orig_ax*/D'oh, right. Juergen, want to make that change?
Hmm, I'd prefer you sending an update which I could test and ack then.
Juergen
Quoted 16 lines · Andrew Cooper
Quoted 9 lines · Andy Lutomirski
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
If the
/* Zero-extending 32-bit regs, do not remove */
movl %eax, %eax
Quoted 6 lines
comments are to be believed, then the entry logic needs reordering slightly to:
GLOBAL(entry_*_compat_after_hwframe)
movl %eax, %eax /* Zero-extending 32-bit regs, do not remove */
pushq %rax /*pt_regs->orig_ax*/
D'oh, right. Juergen, want to make that change?
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Juergen Gross
maintainerQuoted 78 lines · Andy Lutomirski
Quoted 77 lines · Juergen Gross
When running as Xen pv-guest the exception frame on the stack contains %r11 and %rcx additional to the other data pushed by the processor.
Instead of having a paravirt op being called for each exception type prepend the Xen specific code to each exception entry. When running as Xen pv-guest just use the exception entry with prepended instructions, otherwise use the entry without the Xen specific code.
Signed-off-by Juergen Gross <[email protected]>--- arch/x86/entry/entry_64.S | 22 ++------------ arch/x86/entry/entry_64_compat.S | 1 - arch/x86/include/asm/desc.h | 16 ++++++++++ arch/x86/include/asm/paravirt.h | 5 --- arch/x86/include/asm/paravirt_types.h | 4 --- arch/x86/include/asm/proto.h | 3 ++ arch/x86/include/asm/traps.h | 51 +++++++++++++++++++++++++++++-- arch/x86/kernel/asm-offsets_64.c | 1 - arch/x86/kernel/paravirt.c | 3 -- arch/x86/kernel/traps.c | 57 ++++++++++++++++++----------------- arch/x86/xen/enlighten_pv.c | 16 +++++----- arch/x86/xen/irq.c | 3 -- arch/x86/xen/xen-asm_64.S | 45 ++++++++++++++++++++++++--- arch/x86/xen/xen-ops.h | 1 - 14 files changed, 147 insertions(+), 81 deletions(-)arch/x86/entry/entry_64.S +3
-12@@ -745,7 +745,6 @@ ENTRY(\sym) .endif ASM_CLAC - PARAVIRT_ADJUST_EXCEPTION_FRAME .ifeq \has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */@@ -901,7 +900,7 @@ ENTRY(do_softirq_own_stack) END(do_softirq_own_stack) #ifdef CONFIG_XEN -idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 +idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0 /* * A note on the "critical region" in our callback handler.@@ -967,8 +966,6 @@ ENTRY(xen_failsafe_callback) movq 8(%rsp), %r11 addq $0x30, %rsp pushq $0 /* RIP */ - pushq %r11 - pushq %rcx jmp general_protection 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ movq (%rsp), %rcx@@ -997,9 +994,8 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN -idtentry xen_debug do_debug has_error_code=0 -idtentry xen_int3 do_int3 has_error_code=0 -idtentry xen_stack_segment do_stack_segment has_error_code=1 +idtentry xendebug do_debug has_error_code=0 +idtentry xenint3 do_int3 has_error_code=0 #endif idtentry general_protection do_general_protection has_error_code=1@@ -1161,18 +1157,6 @@ END(error_exit) /* Runs on exception stack */ ENTRY(nmi) /* - * Fix up the exception frame if we're on Xen. - * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most - * one value to the stack on native, so it may clobber the rdx - * scratch slot, but it won't clobber any of the important - * slots past it.
Quoted 8 lines
arch/x86/entry/entry_64.S END(error_exit) · line 1172
Quoted 4 lines
arch/x86/entry/entry_64.S +0
-4- * - * Xen is a different story, because the Xen frame itself overlaps - * the "NMI executing" variable. - */Based on Andrew Cooper's email, it sounds like this function is just straight-up broken on Xen PV. Maybe change the comment to "XXX:
broken on Xen PV" or similar.
Fine with me.
Quoted 17 lines
arch/x86/entry/entry_64.S END(error_exit)
Quoted 7 lines
arch/x86/entry/entry_64.S +6
-0+#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) +#define pv_trap_entry(name) (void *)(xen_pv_domain() ? xen_ ## name : name) +#else +#define pv_trap_entry(name) (void *)(name) +#endif +Seems reasonable to me.
Quoted 7 lines
#ifdef
CONFIG_X86_64static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
arch/x86/entry/entry_64.S +0
-0@@ -482,6 +490,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr, 0, 0, __KERNEL_CS); \ } while (0)
Quoted 10 lines
arch/x86/entry/entry_64.S static inline void _set_gate(int gate, unsigned type, void *addr, · line 499
Quoted 7 lines
arch/x86/entry/entry_64.S +7
-0+#define set_intr_gate_pv(n, addr) \ + do { \ + set_intr_gate_notrace(n, pv_trap_entry(addr)); \ + _trace_set_gate(n, GATE_INTERRUPT, \ + pv_trap_entry(trace_##addr), \ + 0, 0, __KERNEL_CS); \ + } while (0)Any reason this can't be
set_intr_gate((n), pv_trap_entry(addr))? Or does that get preprocessed wrong?
trace_##addr won't look like anything the compiler will accept with addr being "(void *)(xen_pv_domain() ? xen_foo : foo)". :-)
Quoted 7 lines
Quoted 7 lines
arch/x86/include/asm/traps.h +0
-0@@ -13,9 +13,8 @@ asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void);
Quoted 8 lines
arch/x86/include/asm/traps.h asmlinkage void divide_error(void); · line 17
Quoted 6 lines
arch/x86/include/asm/traps.h +2
-3asmlinkage void int3(void); -asmlinkage void xen_debug(void); -asmlinkage void xen_int3(void); -asmlinkage void xen_stack_segment(void); +asmlinkage void xendebug(void); +asmlinkage void xenint3(void);What are xendebug and xenint3 for? Are they because they don't use IST on Xen?
I believe so.
Quoted 10 lines
Quoted 10 lines
arch/x86/include/asm/traps.h +0
-0__visible struct pv_cpu_ops pv_cpu_ops = {arch/x86/kernel/traps.c +0
-1@@ -946,15 +946,15 @@ void __init early_trap_init(void)* early stage. DEBUG_STACK will be equipped after cpu_init() in * trap_init(). * -* We don't need to set trace_idt_table like set_intr_gate(),
Quoted 8 lines
arch/x86/kernel/traps.c void __init early_trap_init(void) · line 953
Quoted 5 lines
arch/x86/kernel/traps.c +1
-0+* We don't need to set trace_idt_table like set_intr_gate_pv(), * since we don't have trace_debug and it will be reset to * 'debug' in trap_init() by set_intr_gate_ist(). */ set_intr_gate_notrace (X86_TRAP_DB , debug);This is confusing IMO. Maybe just drop the comment change? But how does this work at all on Xen?
TBH: I don't whether it works on Xen. The changes I did here were just mechanical ones.
Quoted 38 lines
Quoted 6 lines
arch/x86/kernel/traps.c +0
-6-set_intr_gate (X86_TRAP_OLD_MF , coprocessor_segment_overrun); -set_intr_gate (X86_TRAP_TS , invalid_TSS); -set_intr_gate (X86_TRAP_NP , segment_not_present); -set_intr_gate (X86_TRAP_SS , stack_segment); -set_intr_gate (X86_TRAP_GP , general_protection); -set_intr_gate (X86_TRAP_SPURIOUS , spurious_interrupt_bug);arch/x86/kernel/traps.c void __init trap_init(void) · line 1001
Quoted 10 lines
arch/x86/kernel/traps.c +8
-2-set_intr_gate (X86_TRAP_MF , coprocessor_error); -set_intr_gate (X86_TRAP_AC , alignment_check); +set_intr_gate_pv (X86_TRAP_OLD_MF , coprocessor_segment_overrun); +set_intr_gate_pv (X86_TRAP_TS , invalid_TSS); +set_intr_gate_pv (X86_TRAP_NP , segment_not_present); +set_intr_gate_pv (X86_TRAP_SS , stack_segment); +set_intr_gate_pv (X86_TRAP_GP , general_protection); +set_intr_gate_pv (X86_TRAP_SPURIOUS , spurious_interrupt_bug); +set_intr_gate_pv (X86_TRAP_MF , coprocessor_error); +set_intr_gate_pv (X86_TRAP_AC , alignment_check);Hmm. I'm okay with this, but I'm wondering whether it might be nice to try to have a pv op that changes what IDT writes do and remaps the function pointer. Like...
Quoted 17 lines
arch/x86/xen/enlighten_pv.c +2
-7@@ -598,24 +598,22 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,* so we should never see them. Warn if * there's an unexpected IST-using fault handler. */ -if (addr == (unsigned long )debug) - addr = (unsigned long )xen_debug; -else if (addr == (unsigned long )int3) - addr = (unsigned long )xen_int3; -else if (addr == (unsigned long )stack_segment) - addr = (unsigned long )xen_stack_segment; -else if (addr == (unsigned long )double_fault) { +if (addr == (unsigned long )xen_debug) + addr = (unsigned long )xen_xendebug;
Quoted 8 lines
arch/x86/xen/enlighten_pv.c static int cvt_gate_to_trap(int vector, const gate_desc *val, · line 607
Quoted 5 lines
arch/x86/xen/enlighten_pv.c +3
-0+else if (addr == (unsigned long )xen_int3) + addr = (unsigned long )xen_xenint3; +else if (addr == (unsigned long )xen_double_fault) {/* Don't need to handle these */ return 0 ;...this? Can't this list just be extended to handle all of the pv entries instead of using the macro magic?
I'll have a try.
Quoted 65 lines
Quoted 44 lines
arch/x86/xen/xen-asm_64.S +30
-5@@ -22,11 +22,46 @@ #include "xen-asm.h" -ENTRY(xen_adjust_exception_frame) - mov 8+0(%rsp), %rcx - mov 8+8(%rsp), %r11 - ret $16 -ENDPROC(xen_adjust_exception_frame) +.macro xen_pv_trap name +ENTRY(xen_\name) + pop %rcx + pop %r11 + jmp \name +END(xen_\name) +.endm + +xen_pv_trap divide_error +xen_pv_trap debug +xen_pv_trap xendebug +xen_pv_trap int3 +xen_pv_trap xenint3 +xen_pv_trap nmi +xen_pv_trap overflow +xen_pv_trap bounds +xen_pv_trap invalid_op +xen_pv_trap device_not_available +xen_pv_trap double_fault +xen_pv_trap coprocessor_segment_overrun +xen_pv_trap invalid_TSS +xen_pv_trap segment_not_present +xen_pv_trap stack_segment +xen_pv_trap general_protection +xen_pv_trap page_fault +xen_pv_trap async_page_fault +xen_pv_trap spurious_interrupt_bug +xen_pv_trap coprocessor_error +xen_pv_trap alignment_check +#ifdef CONFIG_X86_MCEarch/x86/xen/xen-asm_64.S line 64
Quoted 10 lines
arch/x86/xen/xen-asm_64.S +10
-0+xen_pv_trap machine_check +#endif /* CONFIG_X86_MCE */ +xen_pv_trap simd_coprocessor_error +#ifdef CONFIG_IA32_EMULATION +xen_pv_trap entry_INT80_compat +#endif +#ifdef CONFIG_TRACING +xen_pv_trap trace_page_fault +#endif +xen_pv_trap hypervisor_callbackI like this.
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
Quoted 7 lines
Can you test it and, if you like it, either add it to your series or ack it? If you have extra spare cycles, you could try to do #2 and #3, too :) For #2, it might actually make sense to rig up the Xen sysenter entry to redirect to
entry_SYSCALL_compator even an entirely new entry point -- SYSENTER is really weird.
I'll look into it.
Juergen
Juergen Gross
maintainerQuoted 78 lines · Andy Lutomirski
Quoted 77 lines · Juergen Gross
When running as Xen pv-guest the exception frame on the stack contains %r11 and %rcx additional to the other data pushed by the processor.
Instead of having a paravirt op being called for each exception type prepend the Xen specific code to each exception entry. When running as Xen pv-guest just use the exception entry with prepended instructions, otherwise use the entry without the Xen specific code.
Signed-off-by Juergen Gross <[email protected]>--- arch/x86/entry/entry_64.S | 22 ++------------ arch/x86/entry/entry_64_compat.S | 1 - arch/x86/include/asm/desc.h | 16 ++++++++++ arch/x86/include/asm/paravirt.h | 5 --- arch/x86/include/asm/paravirt_types.h | 4 --- arch/x86/include/asm/proto.h | 3 ++ arch/x86/include/asm/traps.h | 51 +++++++++++++++++++++++++++++-- arch/x86/kernel/asm-offsets_64.c | 1 - arch/x86/kernel/paravirt.c | 3 -- arch/x86/kernel/traps.c | 57 ++++++++++++++++++----------------- arch/x86/xen/enlighten_pv.c | 16 +++++----- arch/x86/xen/irq.c | 3 -- arch/x86/xen/xen-asm_64.S | 45 ++++++++++++++++++++++++--- arch/x86/xen/xen-ops.h | 1 - 14 files changed, 147 insertions(+), 81 deletions(-)arch/x86/entry/entry_64.S +3
-12@@ -745,7 +745,6 @@ ENTRY(\sym) .endif ASM_CLAC - PARAVIRT_ADJUST_EXCEPTION_FRAME .ifeq \has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */@@ -901,7 +900,7 @@ ENTRY(do_softirq_own_stack) END(do_softirq_own_stack) #ifdef CONFIG_XEN -idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 +idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0 /* * A note on the "critical region" in our callback handler.@@ -967,8 +966,6 @@ ENTRY(xen_failsafe_callback) movq 8(%rsp), %r11 addq $0x30, %rsp pushq $0 /* RIP */ - pushq %r11 - pushq %rcx jmp general_protection 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ movq (%rsp), %rcx@@ -997,9 +994,8 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN -idtentry xen_debug do_debug has_error_code=0 -idtentry xen_int3 do_int3 has_error_code=0 -idtentry xen_stack_segment do_stack_segment has_error_code=1 +idtentry xendebug do_debug has_error_code=0 +idtentry xenint3 do_int3 has_error_code=0 #endif idtentry general_protection do_general_protection has_error_code=1@@ -1161,18 +1157,6 @@ END(error_exit) /* Runs on exception stack */ ENTRY(nmi) /* - * Fix up the exception frame if we're on Xen. - * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most - * one value to the stack on native, so it may clobber the rdx - * scratch slot, but it won't clobber any of the important - * slots past it.
Quoted 8 lines
arch/x86/entry/entry_64.S END(error_exit) · line 1172
Quoted 4 lines
arch/x86/entry/entry_64.S +0
-4- * - * Xen is a different story, because the Xen frame itself overlaps - * the "NMI executing" variable. - */Based on Andrew Cooper's email, it sounds like this function is just straight-up broken on Xen PV. Maybe change the comment to "XXX:
broken on Xen PV" or similar.
Fine with me.
Quoted 17 lines
arch/x86/entry/entry_64.S END(error_exit)
Quoted 7 lines
arch/x86/entry/entry_64.S +6
-0+#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) +#define pv_trap_entry(name) (void *)(xen_pv_domain() ? xen_ ## name : name) +#else +#define pv_trap_entry(name) (void *)(name) +#endif +Seems reasonable to me.
Quoted 7 lines
#ifdef
CONFIG_X86_64static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
arch/x86/entry/entry_64.S +0
-0@@ -482,6 +490,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr, 0, 0, __KERNEL_CS); \ } while (0)
Quoted 10 lines
arch/x86/entry/entry_64.S static inline void _set_gate(int gate, unsigned type, void *addr, · line 499
Quoted 7 lines
arch/x86/entry/entry_64.S +7
-0+#define set_intr_gate_pv(n, addr) \ + do { \ + set_intr_gate_notrace(n, pv_trap_entry(addr)); \ + _trace_set_gate(n, GATE_INTERRUPT, \ + pv_trap_entry(trace_##addr), \ + 0, 0, __KERNEL_CS); \ + } while (0)Any reason this can't be
set_intr_gate((n), pv_trap_entry(addr))? Or does that get preprocessed wrong?
trace_##addr won't look like anything the compiler will accept with addr being "(void *)(xen_pv_domain() ? xen_foo : foo)". :-)
Quoted 7 lines
Quoted 7 lines
arch/x86/include/asm/traps.h +0
-0@@ -13,9 +13,8 @@ asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void);
Quoted 8 lines
arch/x86/include/asm/traps.h asmlinkage void divide_error(void); · line 17
Quoted 6 lines
arch/x86/include/asm/traps.h +2
-3asmlinkage void int3(void); -asmlinkage void xen_debug(void); -asmlinkage void xen_int3(void); -asmlinkage void xen_stack_segment(void); +asmlinkage void xendebug(void); +asmlinkage void xenint3(void);What are xendebug and xenint3 for? Are they because they don't use IST on Xen?
I believe so.
Quoted 10 lines
Quoted 10 lines
arch/x86/include/asm/traps.h +0
-0__visible struct pv_cpu_ops pv_cpu_ops = {arch/x86/kernel/traps.c +0
-1@@ -946,15 +946,15 @@ void __init early_trap_init(void)* early stage. DEBUG_STACK will be equipped after cpu_init() in * trap_init(). * -* We don't need to set trace_idt_table like set_intr_gate(),
Quoted 8 lines
arch/x86/kernel/traps.c void __init early_trap_init(void) · line 953
Quoted 5 lines
arch/x86/kernel/traps.c +1
-0+* We don't need to set trace_idt_table like set_intr_gate_pv(), * since we don't have trace_debug and it will be reset to * 'debug' in trap_init() by set_intr_gate_ist(). */ set_intr_gate_notrace (X86_TRAP_DB , debug);This is confusing IMO. Maybe just drop the comment change? But how does this work at all on Xen?
TBH: I don't whether it works on Xen. The changes I did here were just mechanical ones.
Quoted 38 lines
Quoted 6 lines
arch/x86/kernel/traps.c +0
-6-set_intr_gate (X86_TRAP_OLD_MF , coprocessor_segment_overrun); -set_intr_gate (X86_TRAP_TS , invalid_TSS); -set_intr_gate (X86_TRAP_NP , segment_not_present); -set_intr_gate (X86_TRAP_SS , stack_segment); -set_intr_gate (X86_TRAP_GP , general_protection); -set_intr_gate (X86_TRAP_SPURIOUS , spurious_interrupt_bug);arch/x86/kernel/traps.c void __init trap_init(void) · line 1001
Quoted 10 lines
arch/x86/kernel/traps.c +8
-2-set_intr_gate (X86_TRAP_MF , coprocessor_error); -set_intr_gate (X86_TRAP_AC , alignment_check); +set_intr_gate_pv (X86_TRAP_OLD_MF , coprocessor_segment_overrun); +set_intr_gate_pv (X86_TRAP_TS , invalid_TSS); +set_intr_gate_pv (X86_TRAP_NP , segment_not_present); +set_intr_gate_pv (X86_TRAP_SS , stack_segment); +set_intr_gate_pv (X86_TRAP_GP , general_protection); +set_intr_gate_pv (X86_TRAP_SPURIOUS , spurious_interrupt_bug); +set_intr_gate_pv (X86_TRAP_MF , coprocessor_error); +set_intr_gate_pv (X86_TRAP_AC , alignment_check);Hmm. I'm okay with this, but I'm wondering whether it might be nice to try to have a pv op that changes what IDT writes do and remaps the function pointer. Like...
Quoted 17 lines
arch/x86/xen/enlighten_pv.c +2
-7@@ -598,24 +598,22 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,* so we should never see them. Warn if * there's an unexpected IST-using fault handler. */ -if (addr == (unsigned long )debug) - addr = (unsigned long )xen_debug; -else if (addr == (unsigned long )int3) - addr = (unsigned long )xen_int3; -else if (addr == (unsigned long )stack_segment) - addr = (unsigned long )xen_stack_segment; -else if (addr == (unsigned long )double_fault) { +if (addr == (unsigned long )xen_debug) + addr = (unsigned long )xen_xendebug;
Quoted 8 lines
arch/x86/xen/enlighten_pv.c static int cvt_gate_to_trap(int vector, const gate_desc *val, · line 607
Quoted 5 lines
arch/x86/xen/enlighten_pv.c +3
-0+else if (addr == (unsigned long )xen_int3) + addr = (unsigned long )xen_xenint3; +else if (addr == (unsigned long )xen_double_fault) {/* Don't need to handle these */ return 0 ;...this? Can't this list just be extended to handle all of the pv entries instead of using the macro magic?
I'll have a try.
Quoted 65 lines
Quoted 44 lines
arch/x86/xen/xen-asm_64.S +30
-5@@ -22,11 +22,46 @@ #include "xen-asm.h" -ENTRY(xen_adjust_exception_frame) - mov 8+0(%rsp), %rcx - mov 8+8(%rsp), %r11 - ret $16 -ENDPROC(xen_adjust_exception_frame) +.macro xen_pv_trap name +ENTRY(xen_\name) + pop %rcx + pop %r11 + jmp \name +END(xen_\name) +.endm + +xen_pv_trap divide_error +xen_pv_trap debug +xen_pv_trap xendebug +xen_pv_trap int3 +xen_pv_trap xenint3 +xen_pv_trap nmi +xen_pv_trap overflow +xen_pv_trap bounds +xen_pv_trap invalid_op +xen_pv_trap device_not_available +xen_pv_trap double_fault +xen_pv_trap coprocessor_segment_overrun +xen_pv_trap invalid_TSS +xen_pv_trap segment_not_present +xen_pv_trap stack_segment +xen_pv_trap general_protection +xen_pv_trap page_fault +xen_pv_trap async_page_fault +xen_pv_trap spurious_interrupt_bug +xen_pv_trap coprocessor_error +xen_pv_trap alignment_check +#ifdef CONFIG_X86_MCEarch/x86/xen/xen-asm_64.S line 64
Quoted 10 lines
arch/x86/xen/xen-asm_64.S +10
-0+xen_pv_trap machine_check +#endif /* CONFIG_X86_MCE */ +xen_pv_trap simd_coprocessor_error +#ifdef CONFIG_IA32_EMULATION +xen_pv_trap entry_INT80_compat +#endif +#ifdef CONFIG_TRACING +xen_pv_trap trace_page_fault +#endif +xen_pv_trap hypervisor_callbackI like this.
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make axen_nmithat's actually correct (should be trivial)#1 is here:
Quoted 7 lines
Can you test it and, if you like it, either add it to your series or ack it? If you have extra spare cycles, you could try to do #2 and #3, too :) For #2, it might actually make sense to rig up the Xen sysenter entry to redirect to
entry_SYSCALL_compator even an entirely new entry point -- SYSENTER is really weird.
I'll look into it.
Juergen
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Quoted 71 lines · Juergen Gross
When running as Xen pv-guest the exception frame on the stack contains %r11 and %rcx additional to the other data pushed by the processor.
Instead of having a paravirt op being called for each exception type prepend the Xen specific code to each exception entry. When running as Xen pv-guest just use the exception entry with prepended instructions, otherwise use the entry without the Xen specific code.
Signed-off-by Juergen Gross <[email protected]>--- arch/x86/entry/entry_64.S | 22 ++------------ arch/x86/entry/entry_64_compat.S | 1 - arch/x86/include/asm/desc.h | 16 ++++++++++ arch/x86/include/asm/paravirt.h | 5 --- arch/x86/include/asm/paravirt_types.h | 4 --- arch/x86/include/asm/proto.h | 3 ++ arch/x86/include/asm/traps.h | 51 +++++++++++++++++++++++++++++-- arch/x86/kernel/asm-offsets_64.c | 1 - arch/x86/kernel/paravirt.c | 3 -- arch/x86/kernel/traps.c | 57 ++++++++++++++++++----------------- arch/x86/xen/enlighten_pv.c | 16 +++++----- arch/x86/xen/irq.c | 3 -- arch/x86/xen/xen-asm_64.S | 45 ++++++++++++++++++++++++--- arch/x86/xen/xen-ops.h | 1 - 14 files changed, 147 insertions(+), 81 deletions(-)arch/x86/entry/entry_64.S +3
-7@@ -745,7 +745,6 @@ ENTRY(\sym) .endif ASM_CLAC - PARAVIRT_ADJUST_EXCEPTION_FRAME .ifeq \has_error_code pushq $-1 /* ORIG_RAX: no syscall to restart */@@ -901,7 +900,7 @@ ENTRY(do_softirq_own_stack) END(do_softirq_own_stack) #ifdef CONFIG_XEN -idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 +idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0 /* * A note on the "critical region" in our callback handler.@@ -967,8 +966,6 @@ ENTRY(xen_failsafe_callback) movq 8(%rsp), %r11 addq $0x30, %rsp pushq $0 /* RIP */ - pushq %r11 - pushq %rcx jmp general_protection 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ movq (%rsp), %rcx@@ -997,9 +994,8 @@ idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN -idtentry xen_debug do_debug has_error_code=0 -idtentry xen_int3 do_int3 has_error_code=0 -idtentry xen_stack_segment do_stack_segment has_error_code=1 +idtentry xendebug do_debug has_error_code=0 +idtentry xenint3 do_int3 has_error_code=0 #endif idtentry general_protection do_general_protection has_error_code=1@@ -1161,18 +1157,6 @@ END(error_exit) /* Runs on exception stack */ ENTRY(nmi)
arch/x86/entry/entry_64.S END(error_exit) · line 1172
Quoted 10 lines
arch/x86/entry/entry_64.S +0
-9/* - * Fix up the exception frame if we're on Xen. - * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most - * one value to the stack on native, so it may clobber the rdx - * scratch slot, but it won't clobber any of the important - * slots past it. - * - * Xen is a different story, because the Xen frame itself overlaps - * the "NMI executing" variable. - */
Based on Andrew Cooper's email, it sounds like this function is just straight-up broken on Xen PV. Maybe change the comment to "XXX:
broken on Xen PV" or similar.
arch/x86/entry/entry_64.S END(error_exit)
Quoted 6 lines
arch/x86/entry/entry_64.S +6
-0+#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV) +#define pv_trap_entry(name) (void *)(xen_pv_domain() ? xen_ ## name : name) +#else +#define pv_trap_entry(name) (void *)(name) +#endif +
Seems reasonable to me.
Quoted 4 lines
#ifdef
CONFIG_X86_64static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
arch/x86/entry/entry_64.S static inline void _set_gate(int gate, unsigned type, void *addr, · line 499
Quoted 10 lines
arch/x86/entry/entry_64.S +7
-0@@ -482,6 +490,14 @@ static inline void _set_gate(int gate, unsigned type, void *addr, 0, 0, __KERNEL_CS); \ } while (0) +#define set_intr_gate_pv(n, addr) \ + do { \ + set_intr_gate_notrace(n, pv_trap_entry(addr)); \ + _trace_set_gate(n, GATE_INTERRUPT, \ + pv_trap_entry(trace_##addr), \ + 0, 0, __KERNEL_CS); \ + } while (0)
Any reason this can't be set_intr_gate((n), pv_trap_entry(addr))? Or does that get preprocessed wrong?
arch/x86/include/asm/traps.h asmlinkage void divide_error(void); · line 17
Quoted 13 lines
arch/x86/include/asm/traps.h +2
-3@@ -13,9 +13,8 @@ asmlinkage void divide_error(void); asmlinkage void debug(void); asmlinkage void nmi(void); asmlinkage void int3(void); -asmlinkage void xen_debug(void); -asmlinkage void xen_int3(void); -asmlinkage void xen_stack_segment(void); +asmlinkage void xendebug(void); +asmlinkage void xenint3(void);
What are xendebug and xenint3 for? Are they because they don't use IST on Xen?
Quoted 6 lines
arch/x86/include/asm/traps.h +0
-0__visible struct pv_cpu_ops pv_cpu_ops = {arch/x86/kernel/traps.c +0
-0
arch/x86/kernel/traps.c void __init early_trap_init(void) · line 953
Quoted 9 lines
arch/x86/kernel/traps.c +1
-1@@ -946,15 +946,15 @@ void __init early_trap_init(void)* early stage. DEBUG_STACK will be equipped after cpu_init() in * trap_init(). * -* We don't need to set trace_idt_table like set_intr_gate(), +* We don't need to set trace_idt_table like set_intr_gate_pv(), * since we don't have trace_debug and it will be reset to * 'debug' in trap_init() by set_intr_gate_ist(). */ set_intr_gate_notrace (X86_TRAP_DB , debug);
This is confusing IMO. Maybe just drop the comment change? But how does this work at all on Xen?
Quoted 6 lines
arch/x86/kernel/traps.c +0
-6-set_intr_gate (X86_TRAP_OLD_MF , coprocessor_segment_overrun); -set_intr_gate (X86_TRAP_TS , invalid_TSS); -set_intr_gate (X86_TRAP_NP , segment_not_present); -set_intr_gate (X86_TRAP_SS , stack_segment); -set_intr_gate (X86_TRAP_GP , general_protection); -set_intr_gate (X86_TRAP_SPURIOUS , spurious_interrupt_bug);
arch/x86/kernel/traps.c void __init trap_init(void) · line 1001
Quoted 10 lines
arch/x86/kernel/traps.c +8
-2-set_intr_gate (X86_TRAP_MF , coprocessor_error); -set_intr_gate (X86_TRAP_AC , alignment_check); +set_intr_gate_pv (X86_TRAP_OLD_MF , coprocessor_segment_overrun); +set_intr_gate_pv (X86_TRAP_TS , invalid_TSS); +set_intr_gate_pv (X86_TRAP_NP , segment_not_present); +set_intr_gate_pv (X86_TRAP_SS , stack_segment); +set_intr_gate_pv (X86_TRAP_GP , general_protection); +set_intr_gate_pv (X86_TRAP_SPURIOUS , spurious_interrupt_bug); +set_intr_gate_pv (X86_TRAP_MF , coprocessor_error); +set_intr_gate_pv (X86_TRAP_AC , alignment_check);
Hmm. I'm okay with this, but I'm wondering whether it might be nice to try to have a pv op that changes what IDT writes do and remaps the function pointer. Like...
Quoted 12 lines
arch/x86/xen/enlighten_pv.c +0
-4@@ -598,24 +598,22 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,* so we should never see them. Warn if * there's an unexpected IST-using fault handler. */ -if (addr == (unsigned long )debug) - addr = (unsigned long )xen_debug; -else if (addr == (unsigned long )int3) - addr = (unsigned long )xen_int3;
arch/x86/xen/enlighten_pv.c static int cvt_gate_to_trap(int vector, const gate_desc *val, · line 607
Quoted 10 lines
arch/x86/xen/enlighten_pv.c +5
-3-else if (addr == (unsigned long )stack_segment) - addr = (unsigned long )xen_stack_segment; -else if (addr == (unsigned long )double_fault) { +if (addr == (unsigned long )xen_debug) + addr = (unsigned long )xen_xendebug; +else if (addr == (unsigned long )xen_int3) + addr = (unsigned long )xen_xenint3; +else if (addr == (unsigned long )xen_double_fault) {/* Don't need to handle these */ return 0 ;
...this? Can't this list just be extended to handle all of the pv entries instead of using the macro magic?
Quoted 43 lines
arch/x86/xen/xen-asm_64.S +30
-5@@ -22,11 +22,46 @@ #include "xen-asm.h" -ENTRY(xen_adjust_exception_frame) - mov 8+0(%rsp), %rcx - mov 8+8(%rsp), %r11 - ret $16 -ENDPROC(xen_adjust_exception_frame) +.macro xen_pv_trap name +ENTRY(xen_\name) + pop %rcx + pop %r11 + jmp \name +END(xen_\name) +.endm + +xen_pv_trap divide_error +xen_pv_trap debug +xen_pv_trap xendebug +xen_pv_trap int3 +xen_pv_trap xenint3 +xen_pv_trap nmi +xen_pv_trap overflow +xen_pv_trap bounds +xen_pv_trap invalid_op +xen_pv_trap device_not_available +xen_pv_trap double_fault +xen_pv_trap coprocessor_segment_overrun +xen_pv_trap invalid_TSS +xen_pv_trap segment_not_present +xen_pv_trap stack_segment +xen_pv_trap general_protection +xen_pv_trap page_fault +xen_pv_trap async_page_fault +xen_pv_trap spurious_interrupt_bug +xen_pv_trap coprocessor_error +xen_pv_trap alignment_check +#ifdef CONFIG_X86_MCE
arch/x86/xen/xen-asm_64.S line 64
Quoted 10 lines
arch/x86/xen/xen-asm_64.S +10
-0+xen_pv_trap machine_check +#endif /* CONFIG_X86_MCE */ +xen_pv_trap simd_coprocessor_error +#ifdef CONFIG_IA32_EMULATION +xen_pv_trap entry_INT80_compat +#endif +#ifdef CONFIG_TRACING +xen_pv_trap trace_page_fault +#endif +xen_pv_trap hypervisor_callback
I like this.
Also, IMO it would be nice to fully finish the job. Remaining steps are:
1. Unsuck the SYSCALL entries on Xen PV.
2. Unsuck the SYENTER entry on Xen PV.
3. Make a xen_nmi that's actually correct (should be trivial)
#1 is here:
Can you test it and, if you like it, either add it to your series or ack it? If you have extra spare cycles, you could try to do #2 and #3, too :) For #2, it might actually make sense to rig up the Xen sysenter entry to redirect to entry_SYSCALL_compat or even an entirely new entry point -- SYSENTER is really weird.
--Andy
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel