Reintroduce TBF_FAILSAFE and update pv_create_exception_frame() to cope with the additional data segment registers.
load_segments() now fills in trap_bounce, and lets the general return-to-guest path inject the exception. Bloat-o-meter reports: add/remove: 0/0 grow/shrink: 1/1 up/down: 123/-2522 (-2399) function old new delta pv_create_exception_frame 1088 1211 +123 context_switch 3565 1043 -2522 which I suspect is largely due to the quantity of code hidden behind put_user(). Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com> --- CC: Jan Beulich <jbeul...@suse.com> --- xen/arch/x86/domain.c | 100 +++------------------------------------- xen/arch/x86/pv/traps.c | 31 ++++++++++--- xen/include/asm-x86/processor.h | 1 + 3 files changed, 33 insertions(+), 99 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 7b301e3..c533e05 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1275,100 +1275,14 @@ static void load_segments(struct vcpu *n) if ( unlikely(!all_segs_okay) ) { - struct pv_vcpu *pv = &n->arch.pv_vcpu; - struct cpu_user_regs *regs = guest_cpu_user_regs(); - unsigned long *rsp = - (unsigned long *)(((n->arch.flags & TF_kernel_mode) - ? regs->rsp : pv->kernel_sp) & ~0xf); - unsigned long cs_and_mask, rflags; - - /* Fold upcall mask and architectural IOPL into RFLAGS.IF. */ - rflags = regs->rflags & ~(X86_EFLAGS_IF|X86_EFLAGS_IOPL); - rflags |= !vcpu_info(n, evtchn_upcall_mask) << 9; - if ( VM_ASSIST(n->domain, architectural_iopl) ) - rflags |= n->arch.pv_vcpu.iopl; - - if ( is_pv_32bit_vcpu(n) ) - { - unsigned int *esp = ring_1(regs) ? - (unsigned int *)regs->rsp : - (unsigned int *)pv->kernel_sp; - int ret = 0; - - /* CS longword also contains full evtchn_upcall_mask. */ - cs_and_mask = (unsigned short)regs->cs | - ((unsigned int)vcpu_info(n, evtchn_upcall_mask) << 16); - - if ( !ring_1(regs) ) - { - ret = put_user(regs->ss, esp-1); - ret |= put_user(regs->esp, esp-2); - esp -= 2; - } - - if ( ret | - put_user(rflags, esp-1) | - put_user(cs_and_mask, esp-2) | - put_user(regs->eip, esp-3) | - put_user(uregs->gs, esp-4) | - put_user(uregs->fs, esp-5) | - put_user(uregs->es, esp-6) | - put_user(uregs->ds, esp-7) ) - { - gprintk(XENLOG_ERR, - "error while creating compat failsafe callback frame\n"); - domain_crash(n->domain); - } + bool disable = n->arch.vgc_flags & VGCF_failsafe_disables_events; - if ( n->arch.vgc_flags & VGCF_failsafe_disables_events ) - vcpu_info(n, evtchn_upcall_mask) = 1; - - regs->entry_vector |= TRAP_syscall; - regs->eflags &= ~(X86_EFLAGS_VM|X86_EFLAGS_RF|X86_EFLAGS_NT| - X86_EFLAGS_IOPL|X86_EFLAGS_TF); - regs->ss = FLAT_COMPAT_KERNEL_SS; - regs->esp = (unsigned long)(esp-7); - regs->cs = FLAT_COMPAT_KERNEL_CS; - regs->eip = pv->failsafe_callback_eip; - return; - } - - if ( !(n->arch.flags & TF_kernel_mode) ) - toggle_guest_mode(n); - else - regs->cs &= ~3; - - /* CS longword also contains full evtchn_upcall_mask. */ - cs_and_mask = (unsigned long)regs->cs | - ((unsigned long)vcpu_info(n, evtchn_upcall_mask) << 32); - - if ( put_user(regs->ss, rsp- 1) | - put_user(regs->rsp, rsp- 2) | - put_user(rflags, rsp- 3) | - put_user(cs_and_mask, rsp- 4) | - put_user(regs->rip, rsp- 5) | - put_user(uregs->gs, rsp- 6) | - put_user(uregs->fs, rsp- 7) | - put_user(uregs->es, rsp- 8) | - put_user(uregs->ds, rsp- 9) | - put_user(regs->r11, rsp-10) | - put_user(regs->rcx, rsp-11) ) - { - gprintk(XENLOG_ERR, - "error while creating failsafe callback frame\n"); - domain_crash(n->domain); - } - - if ( n->arch.vgc_flags & VGCF_failsafe_disables_events ) - vcpu_info(n, evtchn_upcall_mask) = 1; - - regs->entry_vector |= TRAP_syscall; - regs->rflags &= ~(X86_EFLAGS_AC|X86_EFLAGS_VM|X86_EFLAGS_RF| - X86_EFLAGS_NT|X86_EFLAGS_IOPL|X86_EFLAGS_TF); - regs->ss = FLAT_KERNEL_SS; - regs->rsp = (unsigned long)(rsp-11); - regs->cs = FLAT_KERNEL_CS; - regs->rip = pv->failsafe_callback_eip; + n->arch.pv_vcpu.trap_bounce = (struct trap_bounce){ + .flags = (TBF_FAILSAFE | TBF_EXCEPTION | + (disable ? TBF_INTERRUPT : 0)), + .cs = FLAT_COMPAT_KERNEL_CS, /* Ignored for 64bit guests. */ + .eip = n->arch.pv_vcpu.failsafe_callback_eip + }; } } diff --git a/xen/arch/x86/pv/traps.c b/xen/arch/x86/pv/traps.c index 8973b23..e372ecd 100644 --- a/xen/arch/x86/pv/traps.c +++ b/xen/arch/x86/pv/traps.c @@ -44,7 +44,8 @@ void pv_create_exception_frame(void) { struct vcpu *curr = current; struct trap_bounce *tb = &curr->arch.pv_vcpu.trap_bounce; - struct cpu_user_regs *regs = guest_cpu_user_regs(); + struct cpu_user_regs *regs = guest_cpu_user_regs(), + *uregs = &curr->arch.user_regs; const bool user_mode_frame = !guest_kernel_mode(curr, regs); uint8_t *evt_mask = &vcpu_info(curr, evtchn_upcall_mask); unsigned long rflags; @@ -66,10 +67,18 @@ void pv_create_exception_frame(void) if ( is_pv_32bit_vcpu(curr) ) { - /* { [ERRCODE,] EIP, CS/MASK , EFLAGS, [ESP, SS] } */ - unsigned int frame[6], *ptr = frame, ksp = + /* { [DS-GS,] [ERRCODE,] EIP, CS/MASK , EFLAGS, [ESP, SS] } */ + unsigned int frame[10], *ptr = frame, ksp = (user_mode_frame ? curr->arch.pv_vcpu.kernel_sp : regs->esp); + if ( tb->flags & TBF_FAILSAFE ) + { + *ptr++ = uregs->ds; + *ptr++ = uregs->es; + *ptr++ = uregs->fs; + *ptr++ = uregs->gs; + } + if ( tb->flags & TBF_EXCEPTION_ERRCODE ) *ptr++ = tb->error_code; @@ -100,13 +109,15 @@ void pv_create_exception_frame(void) regs->eflags &= ~(X86_EFLAGS_VM | X86_EFLAGS_RF | X86_EFLAGS_NT | X86_EFLAGS_TF); regs->rsp = ksp; - if ( user_mode_frame ) + if ( tb->flags & TBF_FAILSAFE ) + regs->ss = FLAT_COMPAT_KERNEL_SS; + else if ( user_mode_frame ) regs->ss = curr->arch.pv_vcpu.kernel_ss; } else { - /* { RCX, R11, [ERRCODE,] RIP, CS/MASK, RFLAGS, RSP, SS } */ - unsigned long frame[7], *ptr = frame, ksp = + /* { RCX, R11, [DS-GS,] [ERRCODE,] RIP, CS/MASK, RFLAGS, RSP, SS } */ + unsigned long frame[11], *ptr = frame, ksp = (user_mode_frame ? curr->arch.pv_vcpu.kernel_sp : regs->rsp) & ~0xf; if ( user_mode_frame ) @@ -115,6 +126,14 @@ void pv_create_exception_frame(void) *ptr++ = regs->rcx; *ptr++ = regs->r11; + if ( tb->flags & TBF_FAILSAFE ) + { + *ptr++ = uregs->ds; + *ptr++ = uregs->es; + *ptr++ = uregs->fs; + *ptr++ = uregs->gs; + } + if ( tb->flags & TBF_EXCEPTION_ERRCODE ) *ptr++ = tb->error_code; diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 50435e3..76414df 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -60,6 +60,7 @@ /* 'trap_bounce' flags values */ #define TBF_EXCEPTION 1 #define TBF_EXCEPTION_ERRCODE 2 +#define TBF_FAILSAFE 4 #define TBF_INTERRUPT 8 /* 'arch_vcpu' flags values */ -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel