WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [XEN] Emulate IN/OUT instructions with fu

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [XEN] Emulate IN/OUT instructions with full guest GPR context.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 13 Nov 2006 17:30:16 +0000
Delivery-date: Mon, 13 Nov 2006 09:30:04 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID ad7b60a1db8c25a592e222263f6251e68f2e67eb
# Parent  9a341c6ef6ae2ce90ccdcf89718d4365426d9d96
[XEN] Emulate IN/OUT instructions with full guest GPR context.
Based on a patch by Jan Beulich <jbeulich@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/traps.c             |  119 ++++++++++++++++++++++++++-------------
 xen/arch/x86/x86_32/Makefile     |    1 
 xen/arch/x86/x86_32/gpr_switch.S |   43 ++++++++++++++
 xen/arch/x86/x86_64/Makefile     |    1 
 xen/arch/x86/x86_64/gpr_switch.S |   63 ++++++++++++++++++++
 5 files changed, 189 insertions(+), 38 deletions(-)

diff -r 9a341c6ef6ae -r ad7b60a1db8c xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Mon Nov 13 14:25:48 2006 +0000
+++ b/xen/arch/x86/traps.c      Mon Nov 13 16:19:38 2006 +0000
@@ -985,8 +985,7 @@ static inline int admin_io_okay(
     return ioports_access_permitted(v->domain, port, port + bytes - 1);
 }
 
-/* Check admin limits. Silently fail the access if it is disallowed. */
-static inline unsigned char inb_user(
+static inline int guest_inb_okay(
     unsigned int port, struct vcpu *v, struct cpu_user_regs *regs)
 {
     /*
@@ -996,19 +995,21 @@ static inline unsigned char inb_user(
      * Note that we could emulate bit 4 instead of directly reading port 0x61,
      * but there's not really a good reason to do so.
      */
-    if ( admin_io_okay(port, 1, v, regs) || (port == 0x61) )
-        return inb(port);
-    return ~0;
-}
-//#define inb_user(_p, _d, _r) (admin_io_okay(_p, 1, _d, _r) ? inb(_p) : ~0)
-#define inw_user(_p, _d, _r) (admin_io_okay(_p, 2, _d, _r) ? inw(_p) : ~0)
-#define inl_user(_p, _d, _r) (admin_io_okay(_p, 4, _d, _r) ? inl(_p) : ~0)
-#define outb_user(_v, _p, _d, _r) \
-    (admin_io_okay(_p, 1, _d, _r) ? outb(_v, _p) : ((void)0))
-#define outw_user(_v, _p, _d, _r) \
-    (admin_io_okay(_p, 2, _d, _r) ? outw(_v, _p) : ((void)0))
-#define outl_user(_v, _p, _d, _r) \
-    (admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0))
+    return (admin_io_okay(port, 1, v, regs) || (port == 0x61));
+}
+#define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
+#define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
+#define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
+#define guest_outw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
+#define guest_outl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
+
+/* I/O emulation support. Helper routines for, and type of, the stack stub.*/
+void host_to_guest_gpr_switch(struct cpu_user_regs *)
+    __attribute__((__regparm__(1)));
+unsigned long guest_to_host_gpr_switch(unsigned long)
+    __attribute__((__regparm__(1)));
+typedef unsigned long (*io_emul_stub_t)(struct cpu_user_regs *)
+    __attribute__((__regparm__(1)));
 
 /* Instruction fetch with error handling. */
 #define insn_fetch(_type, _size, cs, eip)                                   \
@@ -1028,6 +1029,7 @@ static int emulate_privileged_op(struct 
     unsigned long *reg, eip = regs->eip, cs = regs->cs, res;
     u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0;
     unsigned int port, i, op_bytes = 4, data, rc;
+    char io_emul_stub[16];
     u32 l, h;
 
     /* Legacy prefixes. */
@@ -1068,6 +1070,9 @@ static int emulate_privileged_op(struct 
         opcode = insn_fetch(u8, 1, cs, eip);
     }
 #endif
+
+    if ( opcode == 0x0f )
+        goto twobyte_opcode;
     
     /* Input/Output String instructions. */
     if ( (opcode >= 0x6c) && (opcode <= 0x6f) )
@@ -1083,16 +1088,17 @@ static int emulate_privileged_op(struct 
         case 0x6d: /* INSW/INSL */
             if ( !guest_io_okay((u16)regs->edx, op_bytes, v, regs) )
                 goto fail;
+            port = (u16)regs->edx;
             switch ( op_bytes )
             {
             case 1:
-                data = (u8)inb_user((u16)regs->edx, v, regs);
+                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : ~0);
                 break;
             case 2:
-                data = (u16)inw_user((u16)regs->edx, v, regs);
+                data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);
                 break;
             case 4:
-                data = (u32)inl_user((u16)regs->edx, v, regs);
+                data = (u32)(guest_inl_okay(port, v, regs) ? inl(port) : ~0);
                 break;
             }
             if ( (rc = copy_to_user((void *)regs->edi, &data, op_bytes)) != 0 )
@@ -1115,16 +1121,20 @@ static int emulate_privileged_op(struct 
                 propagate_page_fault(regs->esi + op_bytes - rc, 0);
                 return EXCRET_fault_fixed;
             }
+            port = (u16)regs->edx;
             switch ( op_bytes )
             {
             case 1:
-                outb_user((u8)data, (u16)regs->edx, v, regs);
+                if ( guest_outb_okay(port, v, regs) )
+                    outb((u8)data, port);
                 break;
             case 2:
-                outw_user((u16)data, (u16)regs->edx, v, regs);
+                if ( guest_outw_okay(port, v, regs) )
+                    outw((u16)data, port);
                 break;
             case 4:
-                outl_user((u32)data, (u16)regs->edx, v, regs);
+                if ( guest_outl_okay(port, v, regs) )
+                    outl((u32)data, port);
                 break;
             }
             regs->esi += (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes);
@@ -1140,6 +1150,27 @@ static int emulate_privileged_op(struct 
 
         goto done;
     }
+
+    /*
+     * Very likely to be an I/O instruction (IN/OUT).
+     * Build an on-stack stub to execute the instruction with full guest
+     * GPR context. This is needed for some systems which (ab)use IN/OUT
+     * to communicate with BIOS code in system-management mode.
+     */
+    /* call host_to_guest_gpr_switch */
+    io_emul_stub[0] = 0xe8;
+    *(s32 *)&io_emul_stub[1] =
+        (char *)host_to_guest_gpr_switch - &io_emul_stub[5];
+    /* data16 or nop */
+    io_emul_stub[5] = (op_bytes != 2) ? 0x90 : 0x66;
+    /* <io-access opcode> */
+    io_emul_stub[6] = opcode;
+    /* imm8 or nop */
+    io_emul_stub[7] = 0x90;
+    /* jmp guest_to_host_gpr_switch */
+    io_emul_stub[8] = 0xe9;
+    *(s32 *)&io_emul_stub[9] =
+        (char *)guest_to_host_gpr_switch - &io_emul_stub[13];
 
     /* I/O Port and Interrupt Flag instructions. */
     switch ( opcode )
@@ -1148,21 +1179,31 @@ static int emulate_privileged_op(struct 
         op_bytes = 1;
     case 0xe5: /* IN imm8,%eax */
         port = insn_fetch(u8, 1, cs, eip);
+        io_emul_stub[7] = port; /* imm8 */
     exec_in:
         if ( !guest_io_okay(port, op_bytes, v, regs) )
             goto fail;
         switch ( op_bytes )
         {
         case 1:
-            regs->eax &= ~0xffUL;
-            regs->eax |= (u8)inb_user(port, v, regs);
+            res = regs->eax & ~0xffUL;
+            if ( guest_inb_okay(port, v, regs) )
+                regs->eax = res | (u8)((io_emul_stub_t)io_emul_stub)(regs);
+            else
+                regs->eax = res | (u8)~0;
             break;
         case 2:
-            regs->eax &= ~0xffffUL;
-            regs->eax |= (u16)inw_user(port, v, regs);
+            res = regs->eax & ~0xffffUL;
+            if ( guest_inw_okay(port, v, regs) )
+                regs->eax = res | (u16)((io_emul_stub_t)io_emul_stub)(regs);
+            else
+                regs->eax = res | (u16)~0;
             break;
         case 4:
-            regs->eax = (u32)inl_user(port, v, regs);
+            if ( guest_inl_okay(port, v, regs) )
+                regs->eax = (u32)((io_emul_stub_t)io_emul_stub)(regs);
+            else
+                regs->eax = (u32)~0;
             break;
         }
         goto done;
@@ -1177,19 +1218,23 @@ static int emulate_privileged_op(struct 
         op_bytes = 1;
     case 0xe7: /* OUT %eax,imm8 */
         port = insn_fetch(u8, 1, cs, eip);
+        io_emul_stub[7] = port; /* imm8 */
     exec_out:
         if ( !guest_io_okay(port, op_bytes, v, regs) )
             goto fail;
         switch ( op_bytes )
         {
         case 1:
-            outb_user((u8)regs->eax, port, v, regs);
+            if ( guest_outb_okay(port, v, regs) )
+                ((io_emul_stub_t)io_emul_stub)(regs);
             break;
         case 2:
-            outw_user((u16)regs->eax, port, v, regs);
+            if ( guest_outw_okay(port, v, regs) )
+                ((io_emul_stub_t)io_emul_stub)(regs);
             break;
         case 4:
-            outl_user((u32)regs->eax, port, v, regs);
+            if ( guest_outl_okay(port, v, regs) )
+                ((io_emul_stub_t)io_emul_stub)(regs);
             break;
         }
         goto done;
@@ -1212,15 +1257,13 @@ static int emulate_privileged_op(struct 
          */
         /*v->vcpu_info->evtchn_upcall_mask = (opcode == 0xfa);*/
         goto done;
-
-    case 0x0f: /* Two-byte opcode */
-        break;
-
-    default:
-        goto fail;
-    }
-
-    /* Remaining instructions only emulated from guest kernel. */
+    }
+
+    /* No decode of this single-byte opcode. */
+    goto fail;
+
+ twobyte_opcode:
+    /* Two-byte opcodes only emulated from guest kernel. */
     if ( !guest_kernel_mode(v, regs) )
         goto fail;
 
diff -r 9a341c6ef6ae -r ad7b60a1db8c xen/arch/x86/x86_32/Makefile
--- a/xen/arch/x86/x86_32/Makefile      Mon Nov 13 14:25:48 2006 +0000
+++ b/xen/arch/x86/x86_32/Makefile      Mon Nov 13 16:19:38 2006 +0000
@@ -1,5 +1,6 @@ obj-y += domain_page.o
 obj-y += domain_page.o
 obj-y += entry.o
+obj-y += gpr_switch.o
 obj-y += mm.o
 obj-y += seg_fixup.o
 obj-y += traps.o
diff -r 9a341c6ef6ae -r ad7b60a1db8c xen/arch/x86/x86_64/Makefile
--- a/xen/arch/x86/x86_64/Makefile      Mon Nov 13 14:25:48 2006 +0000
+++ b/xen/arch/x86/x86_64/Makefile      Mon Nov 13 16:19:38 2006 +0000
@@ -1,3 +1,4 @@ obj-y += entry.o
 obj-y += entry.o
+obj-y += gpr_switch.o
 obj-y += mm.o
 obj-y += traps.o
diff -r 9a341c6ef6ae -r ad7b60a1db8c xen/arch/x86/x86_32/gpr_switch.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/x86_32/gpr_switch.S  Mon Nov 13 16:19:38 2006 +0000
@@ -0,0 +1,43 @@
+/*
+ * GPR context switch between host and guest.
+ * Used by IO-port-access emulation stub.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+ENTRY(host_to_guest_gpr_switch)
+        movl  (%esp), %ecx
+        movl  %eax, (%esp)
+        movl  UREGS_edx(%eax), %edx
+        pushl %ebx
+        movl  UREGS_ebx(%eax), %ebx
+        pushl %ebp
+        movl  UREGS_ebp(%eax), %ebp
+        pushl %esi
+        movl  UREGS_esi(%eax), %esi
+        pushl %edi
+        movl  UREGS_edi(%eax), %edi
+        pushl %ecx
+        movl  UREGS_ecx(%eax), %ecx
+        movl  UREGS_eax(%eax), %eax
+        ret
+
+ENTRY(guest_to_host_gpr_switch)
+        pushl %edx
+        movl  5*4(%esp), %edx
+        movl  %eax, UREGS_eax(%edx)
+        popl  UREGS_edx(%edx)
+        movl  %edi, UREGS_edi(%edx)
+        popl  %edi
+        movl  %esi, UREGS_esi(%edx)
+        popl  %esi
+        movl  %ebp, UREGS_ebp(%edx)
+        popl  %ebp
+        movl  %ebx, UREGS_ebx(%edx)
+        popl  %ebx
+        movl  %ecx, UREGS_ecx(%edx)
+        popl  %ecx
+        ret
diff -r 9a341c6ef6ae -r ad7b60a1db8c xen/arch/x86/x86_64/gpr_switch.S
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/x86_64/gpr_switch.S  Mon Nov 13 16:19:38 2006 +0000
@@ -0,0 +1,63 @@
+/*
+ * GPR context switch between host and guest.
+ * Used by IO-port-access emulation stub.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+ENTRY(host_to_guest_gpr_switch)
+        movq  (%rsp), %rcx
+        movq  %rdi, (%rsp)
+        movq  UREGS_rdx(%rdi), %rdx
+        pushq %rbx
+        movq  UREGS_rax(%rdi), %rax
+        movq  UREGS_rbx(%rdi), %rbx
+        pushq %rbp
+        movq  UREGS_rsi(%rdi), %rsi
+        movq  UREGS_rbp(%rdi), %rbp
+        pushq %r12
+        movq  UREGS_r8(%rdi), %r8
+        movq  UREGS_r12(%rdi), %r12
+        pushq %r13
+        movq  UREGS_r9(%rdi), %r9
+        movq  UREGS_r13(%rdi), %r13
+        pushq %r14
+        movq  UREGS_r10(%rdi), %r10
+        movq  UREGS_r14(%rdi), %r14
+        pushq %r15
+        movq  UREGS_r11(%rdi), %r11
+        movq  UREGS_r15(%rdi), %r15
+        pushq %rcx
+        movq  UREGS_rcx(%rdi), %rcx
+        movq  UREGS_rdi(%rdi), %rdi
+        ret
+
+ENTRY(guest_to_host_gpr_switch)
+        pushq %rdi
+        movq  7*8(%rsp), %rdi
+        movq  %rax, UREGS_rax(%rdi)
+        popq  UREGS_rdi(%rdi)
+        movq  %r15, UREGS_r15(%rdi)
+        movq  %r11, UREGS_r11(%rdi)
+        popq  %r15
+        movq  %r14, UREGS_r14(%rdi)
+        movq  %r10, UREGS_r10(%rdi)
+        popq  %r14
+        movq  %r13, UREGS_r13(%rdi)
+        movq  %r9, UREGS_r9(%rdi)
+        popq  %r13
+        movq  %r12, UREGS_r12(%rdi)
+        movq  %r8, UREGS_r8(%rdi)
+        popq  %r12
+        movq  %rbp, UREGS_rbp(%rdi)
+        movq  %rsi, UREGS_rsi(%rdi)
+        popq  %rbp
+        movq  %rbx, UREGS_rbx(%rdi)
+        movq  %rdx, UREGS_rdx(%rdi)
+        popq  %rbx
+        movq  %rcx, UREGS_rcx(%rdi)
+        popq  %rcx
+        ret

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [XEN] Emulate IN/OUT instructions with full guest GPR context., Xen patchbot-unstable <=