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

Reply via email to