ia64/xen-unstable

changeset 14476:522a1cd17b6d

[XEN] Implement faster int 0x80 handling for compat mode guests.

Using the GPF handler to spot the software interrupt and pass it back
to the guest increases the base syscall time by a factor of 2.7
compared with 32on32 using direct trap to ring 1. (0.3270->0.8680
microseconds, measured with lmbench lat_syscall).

Since the 64 bit IDT can only contain 64 bit segment selectors we
cannot trap directly to compat mode ring 1. However implementing a
dedicated 64 bit ring 0 trap handler allows us to avoid much of the
GPF handler overhead and reduces the overhead to 1.7 times
(0.3270->0.5497 microseconds).

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
author Ian Campbell <ian.campbell@xensource.com>
date Tue Mar 20 14:33:15 2007 +0000 (2007-03-20)
parents cabf9e221cd5
children 129bc1eda8d0
files xen/arch/x86/x86_64/asm-offsets.c xen/arch/x86/x86_64/compat/entry.S xen/arch/x86/x86_64/compat/traps.c xen/arch/x86/x86_64/entry.S xen/arch/x86/x86_64/traps.c xen/include/asm-x86/domain.h xen/include/asm-x86/processor.h
line diff
     1.1 --- a/xen/arch/x86/x86_64/asm-offsets.c	Tue Mar 20 11:28:45 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_64/asm-offsets.c	Tue Mar 20 14:33:15 2007 +0000
     1.3 @@ -59,6 +59,7 @@ void __dummy__(void)
     1.4      OFFSET(VCPU_domain, struct vcpu, domain);
     1.5      OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info);
     1.6      OFFSET(VCPU_trap_bounce, struct vcpu, arch.trap_bounce);
     1.7 +    OFFSET(VCPU_int80_bounce, struct vcpu, arch.int80_bounce);
     1.8      OFFSET(VCPU_thread_flags, struct vcpu, arch.flags);
     1.9      OFFSET(VCPU_event_addr, struct vcpu,
    1.10             arch.guest_context.event_callback_eip);
     2.1 --- a/xen/arch/x86/x86_64/compat/entry.S	Tue Mar 20 11:28:45 2007 +0000
     2.2 +++ b/xen/arch/x86/x86_64/compat/entry.S	Tue Mar 20 14:33:15 2007 +0000
     2.3 @@ -187,6 +187,10 @@ ENTRY(compat_post_handle_exception)
     2.4          call  compat_create_bounce_frame
     2.5          jmp   compat_test_all_events
     2.6  
     2.7 +ENTRY(compat_int80_direct_trap)
     2.8 +        call  compat_create_bounce_frame
     2.9 +        jmp   compat_restore_all_guest
    2.10 +
    2.11  /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK:            */
    2.12  /*   {[ERRCODE,] EIP, CS, EFLAGS, [ESP, SS]}                             */
    2.13  /* %rdx: trap_bounce, %rbx: struct vcpu                                  */
     3.1 --- a/xen/arch/x86/x86_64/compat/traps.c	Tue Mar 20 11:28:45 2007 +0000
     3.2 +++ b/xen/arch/x86/x86_64/compat/traps.c	Tue Mar 20 14:33:15 2007 +0000
     3.3 @@ -1,6 +1,7 @@
     3.4  #ifdef CONFIG_COMPAT
     3.5  
     3.6  #include <xen/event.h>
     3.7 +#include <asm/regs.h>
     3.8  #include <compat/callback.h>
     3.9  #include <compat/arch-x86_32.h>
    3.10  
    3.11 @@ -291,6 +292,9 @@ int compat_set_trap_table(XEN_GUEST_HAND
    3.12  
    3.13          XLAT_trap_info(dst + cur.vector, &cur);
    3.14  
    3.15 +        if ( cur.vector == 0x80 )
    3.16 +            init_int80_direct_trap(current);
    3.17 +
    3.18          guest_handle_add_offset(traps, 1);
    3.19      }
    3.20  
     4.1 --- a/xen/arch/x86/x86_64/entry.S	Tue Mar 20 11:28:45 2007 +0000
     4.2 +++ b/xen/arch/x86/x86_64/entry.S	Tue Mar 20 14:33:15 2007 +0000
     4.3 @@ -222,6 +222,35 @@ bad_hypercall:
     4.4          movq $-ENOSYS,UREGS_rax(%rsp)
     4.5          jmp  test_all_events
     4.6  
     4.7 +ENTRY(int80_direct_trap)
     4.8 +        pushq $0
     4.9 +        SAVE_ALL
    4.10 +
    4.11 +        GET_CURRENT(%rbx)
    4.12 +
    4.13 +        /* Check that the callback is non-null. */
    4.14 +        leaq  VCPU_int80_bounce(%rbx),%rdx
    4.15 +        cmp   $0, TRAPBOUNCE_flags(%rdx)
    4.16 +        jz    int80_slow_path
    4.17 +
    4.18 +        movq  VCPU_domain(%rbx),%rax
    4.19 +        btl   $_DOMF_compat,DOMAIN_domain_flags(%rax)
    4.20 +        jc    compat_int80_direct_trap
    4.21 +
    4.22 +        call  create_bounce_frame
    4.23 +        jmp   restore_all_guest
    4.24 +
    4.25 +int80_slow_path:
    4.26 +        /* 
    4.27 +         * Setup entry vector and error code as if this was a GPF caused by an
    4.28 +         * IDT entry with DPL==0.
    4.29 +         */
    4.30 +        movl  $((0x80 << 3) | 0x2),UREGS_error_code(%rsp)
    4.31 +        movl  $TRAP_gp_fault,UREGS_entry_vector(%rsp)
    4.32 +        /* A GPF wouldn't have incremented the instruction pointer. */
    4.33 +        sub   $2,UREGS_rip(%rsp)
    4.34 +        jmp   handle_exception_saved
    4.35 +
    4.36  /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS STACK:                     */
    4.37  /*   { RCX, R11, [DS-GS,] [CR2,] [ERRCODE,] RIP, CS, RFLAGS, RSP, SS }   */
    4.38  /* %rdx: trap_bounce, %rbx: struct vcpu                           */
    4.39 @@ -359,6 +388,7 @@ ENTRY(ret_from_intr)
    4.40  /* No special register assumptions. */
    4.41  ENTRY(handle_exception)
    4.42          SAVE_ALL
    4.43 +handle_exception_saved:
    4.44          testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%rsp)
    4.45          jz    exception_with_ints_disabled
    4.46          sti
     5.1 --- a/xen/arch/x86/x86_64/traps.c	Tue Mar 20 11:28:45 2007 +0000
     5.2 +++ b/xen/arch/x86/x86_64/traps.c	Tue Mar 20 14:33:15 2007 +0000
     5.3 @@ -247,6 +247,7 @@ unsigned long do_iret(void)
     5.4  
     5.5  asmlinkage void syscall_enter(void);
     5.6  asmlinkage void compat_hypercall(void);
     5.7 +asmlinkage void int80_direct_trap(void);
     5.8  void __init percpu_traps_init(void)
     5.9  {
    5.10      char *stack_bottom, *stack;
    5.11 @@ -262,6 +263,7 @@ void __init percpu_traps_init(void)
    5.12  #ifdef CONFIG_COMPAT
    5.13          /* The hypercall entry vector is only accessible from ring 1. */
    5.14          _set_gate(idt_table+HYPERCALL_VECTOR, 15, 1, &compat_hypercall);
    5.15 +        _set_gate(idt_table+0x80, 15, 3, &int80_direct_trap);
    5.16  #endif
    5.17      }
    5.18  
    5.19 @@ -346,6 +348,22 @@ void __init percpu_traps_init(void)
    5.20      wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U);
    5.21  }
    5.22  
    5.23 +void init_int80_direct_trap(struct vcpu *v)
    5.24 +{
    5.25 +    struct trap_info *ti = &v->arch.guest_context.trap_ctxt[0x80];
    5.26 +    struct trap_bounce *tb = &v->arch.int80_bounce;
    5.27 +
    5.28 +    if ( !guest_gate_selector_okay(v->domain, ti->cs) )
    5.29 +         return;
    5.30 +
    5.31 +    tb->flags = TBF_EXCEPTION;
    5.32 +    tb->cs    = ti->cs;
    5.33 +    tb->eip   = ti->address;
    5.34 +
    5.35 +    if ( null_trap_bounce(v, tb) )
    5.36 +        tb->flags = 0;
    5.37 +}
    5.38 +
    5.39  static long register_guest_callback(struct callback_register *reg)
    5.40  {
    5.41      long ret = 0;
     6.1 --- a/xen/include/asm-x86/domain.h	Tue Mar 20 11:28:45 2007 +0000
     6.2 +++ b/xen/include/asm-x86/domain.h	Tue Mar 20 14:33:15 2007 +0000
     6.3 @@ -248,6 +248,9 @@ struct arch_vcpu
     6.4  #ifdef CONFIG_X86_32
     6.5      struct desc_struct int80_desc;
     6.6  #endif
     6.7 +#ifdef CONFIG_X86_64
     6.8 +    struct trap_bounce int80_bounce;
     6.9 +#endif
    6.10  
    6.11      /* Virtual Machine Extensions */
    6.12      struct hvm_vcpu hvm_vcpu;
     7.1 --- a/xen/include/asm-x86/processor.h	Tue Mar 20 11:28:45 2007 +0000
     7.2 +++ b/xen/include/asm-x86/processor.h	Tue Mar 20 14:33:15 2007 +0000
     7.3 @@ -455,16 +455,16 @@ extern idt_entry_t *idt_tables[];
     7.4  
     7.5  extern struct tss_struct init_tss[NR_CPUS];
     7.6  
     7.7 -#ifdef CONFIG_X86_32
     7.8 +extern void init_int80_direct_trap(struct vcpu *v);
     7.9  
    7.10 -extern void init_int80_direct_trap(struct vcpu *v);
    7.11 +#if defined(CONFIG_X86_32)
    7.12 +
    7.13  #define set_int80_direct_trap(_ed)                  \
    7.14      (memcpy(idt_tables[(_ed)->processor] + 0x80,    \
    7.15              &((_ed)->arch.int80_desc), 8))
    7.16  
    7.17  #else
    7.18  
    7.19 -#define init_int80_direct_trap(_ed) ((void)0)
    7.20  #define set_int80_direct_trap(_ed)  ((void)0)
    7.21  
    7.22  #endif