All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Jan Beulich" <jbeulich@novell.com>
To: Keir Fraser <Keir.Fraser@cl.cam.ac.uk>
Cc: xen-devel@lists.xensource.com
Subject: Re: [PATCH] enable port accesses with (almost) full register context
Date: Wed, 13 Sep 2006 10:46:43 +0100	[thread overview]
Message-ID: <4507EFA3.76E4.0078.0@novell.com> (raw)
In-Reply-To: <C12C5861.1215%Keir.Fraser@cl.cam.ac.uk>

[-- Attachment #1: Type: text/plain, Size: 2612 bytes --]

>IMO you're doing code building anyway, but just of one instruction. You get
>rid of the locking by doing it to a per-CPU buffer, and the stack is the
>obvious place, calling out to register save/restore code. I don't really
>care about the performance of the save/restore code -- it's obviously going
>to be trivial compared with the unavoidable trap-and-emulate cost. Also, do
>you need separate save/restore code for IN vs. OUT instructions?

Actually, in the code I currently have I do. This is because for out-s I need
to merge the value output with the user-specified rAX, under the
assumption that output value and register contents are not always identical
(i.e. if particular bits within a port would need to be special treated by Xen,
which I can easily imagine to be required at some point).

>Something like:
>    call save_host_restore_guest
>    <IN or OUT>
>    call save_guest_restore_host
>    ret
>
>Would that be reasonable?

It would, provided the above assumption about the need to modify the
output value would never become true. Additionally, for 64-bits, I'm
concerned about the potential need for using indirect calls here (as well
as in the syscall trampolines): there's nothing keeping a user from making
the Xen heap 2Gb or more in size. These would further slow things down,
but depending on the nature of allocations made from the Xen heap it
may also be possible to simply place an upper limit on the heap size, as
it currently is assumed adjacent to the Xen image (but taking memory
holes at rather low addresses into account a user may even be required
to bump the heap size significantly - what if only a few Mb of memory
below 4Gb existed? - since, after all, the heap size is the size of address
space consumed, not the amount of memory used).

>Alternatively, perhaps we could get rid of the distinction and emulate all
>port accesses in this way? I suspect that the cost of state save/restore and
>building the trampoline is dwarfed by the cost of the GPF and even the cost
>of the I/O port access itself (they don't tend to be super fast). Could you
>do a few quick measurements to determine this? If the extra cost is less
>than, say, 10%, I'd be inclined to take the hit to avoid interface changes.

Percentages of full-context relative to simply emulated i/o, without having
changed the assembly file approach to the stub building one, yet (as per
above issues):

PentiumIII (32-bit) with locking	67%
PentiumIII (32-bit) without locking	84%
Pentium4 (64-bit) with locking		86%
Pentium4 (64-bit) without locking	89%

Revised patch (domctl->sysctl, naming) attached.

Jan

[-- Attachment #2: xen-x86-io-register-context-2.patch --]
[-- Type: text/plain, Size: 25202 bytes --]

From:  Jan Beulich
Bugzilla #192150

Index: 2006-09-11/xen/arch/x86/domain_build.c
===================================================================
--- 2006-09-11.orig/xen/arch/x86/domain_build.c	2006-09-11 13:50:54.000000000 +0200
+++ 2006-09-11/xen/arch/x86/domain_build.c	2006-09-13 11:05:06.000000000 +0200
@@ -33,6 +33,11 @@
 extern unsigned long initial_images_nrpages(void);
 extern void discard_initial_images(void);
 
+/* I/O-port Xen-enforced or admin-specified access control. */
+struct rangeset *ioport_caps = NULL;
+/* I/O-port admin-specified non-special access requirements. */
+struct rangeset *ioport_emul = NULL;
+
 static long dom0_nrpages;
 
 /*
@@ -64,6 +69,12 @@ integer_param("dom0_max_vcpus", opt_dom0
 static unsigned int opt_dom0_shadow;
 boolean_param("dom0_shadow", opt_dom0_shadow);
 
+static char opt_ioports_noemul[200] = "";
+string_param("ioports_noemul", opt_ioports_noemul);
+
+static char opt_ioports_disable[200] = "";
+string_param("ioports_disable", opt_ioports_disable);
+
 static char opt_dom0_ioports_disable[200] = "";
 string_param("dom0_ioports_disable", opt_dom0_ioports_disable);
 
@@ -102,10 +113,10 @@ static struct page_info *alloc_chunk(str
     return page;
 }
 
-static void process_dom0_ioports_disable(void)
+static void process_ioports(char *opt)
 {
     unsigned long io_from, io_to;
-    char *t, *u, *s = opt_dom0_ioports_disable;
+    char *t, *u, *s = opt;
 
     if ( *s == '\0' )
         return;
@@ -117,7 +128,9 @@ static void process_dom0_ioports_disable
         {
         parse_error:
             printk("Invalid ioport range <%s> "
-                   "in dom0_ioports_disable, skipping\n", t);
+                   "in %sioports_%s, skipping\n", t,
+                   opt == opt_dom0_ioports_disable ? "dom0_" : "",
+                   opt != opt_ioports_noemul ? "disable" : "noemul");
             continue;
         }
 
@@ -131,11 +144,26 @@ static void process_dom0_ioports_disable
         if ( (*u != '\0') || (io_to < io_from) || (io_to >= 65536) )
             goto parse_error;
 
-        printk("Disabling dom0 access to ioport range %04lx-%04lx\n",
-            io_from, io_to);
+        if ( opt != opt_ioports_noemul )
+        {
+            printk("Disabling %saccess to ioport range %04lx-%04lx\n",
+                opt != opt_ioports_disable ? "dom0 " : "",
+                io_from, io_to);
 
-        if ( ioports_deny_access(dom0, io_from, io_to) != 0 )
-            BUG();
+            if ( opt == opt_ioports_disable
+                 && ioports_deny_access_all(io_from, io_to) != 0 )
+                BUG();
+            if ( ioports_deny_access(dom0, io_from, io_to) != 0 )
+                BUG();
+        }
+        else
+        {
+            printk("Setting non-emulated access for ioport range %04lx-%04lx\n",
+                io_from, io_to);
+
+            if ( ioports_set_noemul(io_from, io_to) != 0 )
+                BUG();
+        }
     }
 }
 
@@ -815,6 +843,13 @@ int construct_dom0(struct domain *d,
 
     rc = 0;
 
+    /* Command-line I/O ranges. */
+    ioport_caps = rangeset_new(NULL,
+                               "global I/O Port access control",
+                               RANGESETF_prettyprint_hex);
+    BUG_ON(!ioport_caps);
+    rc |= ioports_permit_access_all(0, 0xFFFF);
+
     /* DOM0 is permitted full I/O capabilities. */
     rc |= ioports_permit_access(dom0, 0, 0xFFFF);
     rc |= iomem_permit_access(dom0, 0UL, ~0UL);
@@ -824,15 +859,20 @@ int construct_dom0(struct domain *d,
      * Modify I/O port access permissions.
      */
     /* Master Interrupt Controller (PIC). */
+    rc |= ioports_deny_access_all(0x20, 0x21);
     rc |= ioports_deny_access(dom0, 0x20, 0x21);
     /* Slave Interrupt Controller (PIC). */
+    rc |= ioports_deny_access_all(0xA0, 0xA1);
     rc |= ioports_deny_access(dom0, 0xA0, 0xA1);
     /* Interval Timer (PIT). */
+    rc |= ioports_deny_access_all(0x40, 0x43);
     rc |= ioports_deny_access(dom0, 0x40, 0x43);
     /* PIT Channel 2 / PC Speaker Control. */
+    rc |= ioports_deny_access_all(0x61, 0x61);
     rc |= ioports_deny_access(dom0, 0x61, 0x61);
     /* Command-line I/O ranges. */
-    process_dom0_ioports_disable();
+    process_ioports(opt_ioports_disable);
+    process_ioports(opt_dom0_ioports_disable);
 
     /*
      * Modify I/O memory access permissions.
@@ -851,6 +891,14 @@ int construct_dom0(struct domain *d,
             rc |= iomem_deny_access(dom0, mfn, mfn);
     }
 
+    /* Command-line I/O ranges requiring full register context access. */
+    ioport_emul = rangeset_new(NULL,
+                               "I/O Port emulation control",
+                               RANGESETF_prettyprint_hex);
+    BUG_ON(!ioport_emul);
+    rc |= ioports_set_emul(0, 0xFFFF);
+    process_ioports(opt_ioports_noemul);
+
     BUG_ON(rc != 0);
 
     return 0;
Index: 2006-09-11/xen/arch/x86/sysctl.c
===================================================================
--- 2006-09-11.orig/xen/arch/x86/sysctl.c	2006-08-28 08:32:37.000000000 +0200
+++ 2006-09-11/xen/arch/x86/sysctl.c	2006-09-13 09:47:23.000000000 +0200
@@ -57,6 +57,23 @@ long arch_do_sysctl(
     }
     break;
     
+    case XEN_SYSCTL_ioport_emulation:
+    {
+        unsigned int fp = sysctl->u.ioport_emulation.first_port;
+        unsigned int np = sysctl->u.ioport_emulation.nr_ports;
+
+        ret = -EINVAL;
+        if ( (fp + np) > 65536 )
+            break;
+
+        if ( np == 0 )
+            ret = 0;
+        else if ( sysctl->u.ioport_emulation.emulate )
+            ret = ioports_set_emul(fp, fp + np - 1);
+        else
+            ret = ioports_set_noemul(fp, fp + np - 1);
+    }
+    break;
 
     default:
         ret = -ENOSYS;
Index: 2006-09-11/xen/arch/x86/traps.c
===================================================================
--- 2006-09-11.orig/xen/arch/x86/traps.c	2006-09-11 13:50:54.000000000 +0200
+++ 2006-09-11/xen/arch/x86/traps.c	2006-09-13 11:05:07.000000000 +0200
@@ -1002,16 +1002,76 @@ static inline int admin_io_okay(
     return ioports_access_permitted(v->domain, port, port + bytes - 1);
 }
 
+/* Can the I/O access be carried out without full register context? */
+static inline int normal_io_okay(
+    unsigned int port, unsigned int bytes)
+{
+    return ioports_emul(port, port + bytes - 1);
+}
+
 /* Check admin limits. Silently fail the access if it is disallowed. */
-#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))
+static inline unsigned char inb_user(
+    unsigned int port, int string,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    if ( admin_io_okay(port, 1, v, regs) )
+        return string || normal_io_okay(port, 1)
+               ? inb(port)
+               : inb_special(port, regs);
+    return ~0;
+}
+
+static inline unsigned short inw_user(
+    unsigned int port, int string,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    if ( admin_io_okay(port, 2, v, regs) )
+        return string || normal_io_okay(port, 2)
+               ? inw(port)
+               : inw_special(port, regs);
+    return ~0;
+}
+
+static inline unsigned int inl_user(
+    unsigned int port, int string,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    if ( admin_io_okay(port, 4, v, regs) )
+        return string || normal_io_okay(port, 4)
+               ? inl(port)
+               : inl_special(port, regs);
+    return ~0;
+}
+
+static inline void outb_user(
+    unsigned char value, unsigned int port, int string,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    if ( admin_io_okay(port, 1, v, regs) )
+        string || normal_io_okay(port, 1)
+        ? outb(value, port)
+        : outb_special(value, port, regs);
+}
+
+static inline void outw_user(
+    unsigned short value, unsigned int port, int string,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    if ( admin_io_okay(port, 2, v, regs) )
+        string || normal_io_okay(port, 2)
+        ? outw(value, port)
+        : outw_special(value, port, regs);
+}
+
+static inline void outl_user(
+    unsigned int value, unsigned int port, int string,
+    struct vcpu *v, struct cpu_user_regs *regs)
+{
+    if ( admin_io_okay(port, 4, v, regs) )
+        string || normal_io_okay(port, 4)
+        ? outl(value, port)
+        : outl_special(value, port, regs);
+}
 
 /* Instruction fetch with error handling. */
 #define insn_fetch(_type, _size, _ptr)                                      \
@@ -1087,13 +1140,13 @@ static int emulate_privileged_op(struct 
             switch ( op_bytes )
             {
             case 1:
-                data = (u8)inb_user((u16)regs->edx, v, regs);
+                data = (u8)inb_user((u16)regs->edx, 1, v, regs);
                 break;
             case 2:
-                data = (u16)inw_user((u16)regs->edx, v, regs);
+                data = (u16)inw_user((u16)regs->edx, 1, v, regs);
                 break;
             case 4:
-                data = (u32)inl_user((u16)regs->edx, v, regs);
+                data = (u32)inl_user((u16)regs->edx, 1, v, regs);
                 break;
             }
             if ( (rc = copy_to_user((void *)regs->edi, &data, op_bytes)) != 0 )
@@ -1119,13 +1172,13 @@ static int emulate_privileged_op(struct 
             switch ( op_bytes )
             {
             case 1:
-                outb_user((u8)data, (u16)regs->edx, v, regs);
+                outb_user((u8)data, (u16)regs->edx, 1, v, regs);
                 break;
             case 2:
-                outw_user((u16)data, (u16)regs->edx, v, regs);
+                outw_user((u16)data, (u16)regs->edx, 1, v, regs);
                 break;
             case 4:
-                outl_user((u32)data, (u16)regs->edx, v, regs);
+                outl_user((u32)data, (u16)regs->edx, 1, v, regs);
                 break;
             }
             regs->esi += (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes);
@@ -1156,14 +1209,14 @@ static int emulate_privileged_op(struct 
         {
         case 1:
             regs->eax &= ~0xffUL;
-            regs->eax |= (u8)inb_user(port, v, regs);
+            regs->eax |= (u8)inb_user(port, 0, v, regs);
             break;
         case 2:
             regs->eax &= ~0xffffUL;
-            regs->eax |= (u16)inw_user(port, v, regs);
+            regs->eax |= (u16)inw_user(port, 0, v, regs);
             break;
         case 4:
-            regs->eax = (u32)inl_user(port, v, regs);
+            regs->eax = (u32)inl_user(port, 0, v, regs);
             break;
         }
         goto done;
@@ -1184,13 +1237,13 @@ static int emulate_privileged_op(struct 
         switch ( op_bytes )
         {
         case 1:
-            outb_user((u8)regs->eax, port, v, regs);
+            outb_user((u8)regs->eax, port, 0, v, regs);
             break;
         case 2:
-            outw_user((u16)regs->eax, port, v, regs);
+            outw_user((u16)regs->eax, port, 0, v, regs);
             break;
         case 4:
-            outl_user((u32)regs->eax, port, v, regs);
+            outl_user((u32)regs->eax, port, 0, v, regs);
             break;
         }
         goto done;
Index: 2006-09-11/xen/arch/x86/x86_32/Makefile
===================================================================
--- 2006-09-11.orig/xen/arch/x86/x86_32/Makefile	2006-09-11 13:50:54.000000000 +0200
+++ 2006-09-11/xen/arch/x86/x86_32/Makefile	2006-09-11 13:52:31.000000000 +0200
@@ -1,5 +1,6 @@
 obj-y += domain_page.o
 obj-y += entry.o
+obj-y += io.o
 obj-y += mm.o
 obj-y += seg_fixup.o
 obj-y += traps.o
Index: 2006-09-11/xen/arch/x86/x86_32/io.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 2006-09-11/xen/arch/x86/x86_32/io.S	2006-09-13 11:04:05.000000000 +0200
@@ -0,0 +1,155 @@
+/*
+ * Special (full-context) I/O handling routines.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+#define PROTECTED_PORT 0x20 // must be some port no domain will ever be granted access
+
+ .macro in_special w, a
+ENTRY(in\w\(_special))
+	movl	2*4(%esp), %ecx
+	pushl	%ebx
+	movl	UREGS_ebx(%ecx), %ebx
+	movl	UREGS_edx(%ecx), %edx
+	pushl	%ebp
+	movl	UREGS_ebp(%ecx), %ebp
+	movl	UREGS_eax(%ecx), %eax
+	pushl	%esi
+	movl	UREGS_esi(%ecx), %esi
+	movw	4*4(%esp), %dx
+	pushl	%edi
+	testb	%dh, %dh
+	movl	UREGS_edi(%ecx), %edi
+	jz	.Ltry_lock_in\w
+	movl	UREGS_ecx(%ecx), %ecx
+	in\w	%dx, %\a
+ .ifndef .Lin_restore
+.Lin_restore:
+	movl	%ecx, 5*4(%esp)
+	movl	6*4(%esp), %ecx
+	movl	%edx, UREGS_edx(%ecx)
+	movl	5*4(%esp), %edx
+	movl	%edi, UREGS_edi(%ecx)
+	popl	%edi
+	movl	%esi, UREGS_esi(%ecx)
+	popl	%esi
+	movl	%ebp, UREGS_ebp(%ecx)
+	popl	%ebp
+	movl	%ebx, UREGS_ebx(%ecx)
+	popl	%ebx
+	movl	%eax, UREGS_eax(%ecx)
+	movl	%edx, UREGS_ecx(%ecx)
+	ret
+ .else
+ 	jmp	.Lin_restore
+ .endif
+.Ltry_lock_in\w:
+#ifdef CONFIG_SMP
+	movb	$PROTECTED_PORT, %al
+	lock cmpxchgb %dl, .Lport_in\w
+	jne	.Lretry_in\w
+	movl	UREGS_eax(%ecx), %eax
+#else
+	movb	%dl, .Lport_in\w
+#endif
+	movl	UREGS_edx(%ecx), %edx
+	movl	UREGS_ecx(%ecx), %ecx
+	jmp	.Limm_in\w
+ .data # .section .wtext, "axw"
+.Limm_in\w:
+	in\w	$PROTECTED_PORT, %\a
+ .equiv .Lport_in\w, . - 1
+#ifdef CONFIG_SMP
+	movb	$PROTECTED_PORT, .Lport_in\w
+#endif
+ 	jmp	.Lin_restore
+ .previous
+#ifdef CONFIG_SMP
+.Lretry_in\w:
+	pause
+	jmp	.Ltry_lock_in\w
+#endif
+ .endm
+
+	in_special b, al
+	in_special w, ax
+	in_special l, eax
+
+ .macro out_special w, a
+ENTRY(out\w\(_special))
+	movl	3*4(%esp), %ecx
+	pushl	%ebx
+	movl	UREGS_ebx(%ecx), %ebx
+	movl	UREGS_edx(%ecx), %edx
+	pushl	%ebp
+	movl	UREGS_ebp(%ecx), %ebp
+ .ifnes "\w", "l"
+	movl	UREGS_eax(%ecx), %eax
+ .endif
+	pushl	%esi
+	movl	UREGS_esi(%ecx), %esi
+	movw	5*4(%esp), %dx
+	pushl	%edi
+	testb	%dh, %dh
+	movl	UREGS_edi(%ecx), %edi
+	mov\w	5*4(%esp), %\a
+	jz	.Llock_out\w
+	movl	UREGS_ecx(%ecx), %ecx
+	out\w	%\a, %dx
+ .ifndef .Lout_restore
+.Lout_restore:
+	movl	%ecx, 5*4(%esp)
+	movl	7*4(%esp), %ecx
+	movl	%edx, UREGS_edx(%ecx)
+	movl	5*4(%esp), %edx
+	movl	%edi, UREGS_edi(%ecx)
+	popl	%edi
+	movl	%esi, UREGS_esi(%ecx)
+	popl	%esi
+	movl	%ebp, UREGS_ebp(%ecx)
+	popl	%ebp
+	movl	%ebx, UREGS_ebx(%ecx)
+	popl	%ebx
+	movl	%eax, UREGS_eax(%ecx)
+	movl	%edx, UREGS_ecx(%ecx)
+	ret
+ .else
+	jmp	.Lout_restore
+ .endif
+.Llock_out\w:
+#ifdef CONFIG_SMP
+	pushl	%eax
+.Ltry_lock_out\w:
+	movb	$PROTECTED_PORT, %al
+	lock cmpxchgb %dl, .Lport_out\w
+	jne	.Lretry_out\w
+	popl	%eax
+#else
+	movb	%dl, .Lport_out\w
+#endif
+	movl	UREGS_edx(%ecx), %edx
+	movl	UREGS_ecx(%ecx), %ecx
+	jmp	.Limm_out\w
+ .data # .section .wtext, "axw"
+.Limm_out\w:
+	out\w	%\a, $PROTECTED_PORT
+ .equiv .Lport_out\w, . - 1
+#ifdef CONFIG_SMP
+	movb	$PROTECTED_PORT, .Lport_out\w
+#endif
+	jmp	.Lout_restore
+ .previous
+#ifdef CONFIG_SMP
+.Lretry_out\w:
+	pause
+	jmp	.Ltry_lock_out\w
+#endif
+ .endm
+
+	out_special b, al
+	out_special w, ax
+	out_special l, eax
Index: 2006-09-11/xen/arch/x86/x86_64/Makefile
===================================================================
--- 2006-09-11.orig/xen/arch/x86/x86_64/Makefile	2006-09-11 13:50:54.000000000 +0200
+++ 2006-09-11/xen/arch/x86/x86_64/Makefile	2006-09-13 11:05:05.000000000 +0200
@@ -1,3 +1,4 @@
 obj-y += entry.o
+obj-y += io.o
 obj-y += mm.o
 obj-y += traps.o
Index: 2006-09-11/xen/arch/x86/x86_64/io.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 2006-09-11/xen/arch/x86/x86_64/io.S	2006-09-13 11:04:38.000000000 +0200
@@ -0,0 +1,202 @@
+/*
+ * Special (full-context) I/O handling routines.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+#define PROTECTED_PORT 0x20 // must be some port no domain will ever be granted access
+
+ .macro in_special w, a
+ENTRY(in\w\(_special))
+	pushq	%rbx
+	movq	UREGS_rbx(%rsi), %rbx
+	movq	UREGS_rdx(%rsi), %rdx
+	pushq	%rbp
+	movq	UREGS_rbp(%rsi), %rbp
+	movq	UREGS_rax(%rsi), %rax
+	pushq	%r12
+	movq	UREGS_r12(%rsi), %r12
+	movq	UREGS_r8(%rsi), %r8
+	pushq	%r13
+	movq	UREGS_r13(%rsi), %r13
+	movq	UREGS_r9(%rsi), %r9
+	pushq	%r14
+	movq	UREGS_r14(%rsi), %r14
+	movq	UREGS_r10(%rsi), %r10
+	movw	%di, %dx
+	pushq	%r15
+	movq	UREGS_r15(%rsi), %r15
+	movq	UREGS_r11(%rsi), %r11
+	testb	%dh, %dh
+	movq	UREGS_rcx(%rsi), %rcx
+	movq	UREGS_rdi(%rsi), %rdi
+	pushq	%rsi
+	jz	.Ltry_lock_in\w
+	movq	UREGS_rsi(%rsi), %rsi
+	in\w	%dx, %\a
+ .ifndef .Lin_restore
+.Lin_restore:
+	pushq	%rsi
+	movq	8(%rsp), %rsi
+	movq	%rdx, UREGS_rdx(%rsi)
+	popq	UREGS_rsi(%rsi)
+	movq	%rdi, UREGS_rdi(%rsi)
+	movq	%rcx, UREGS_rcx(%rsi)
+	popq	%rdx
+	movq	%r11, UREGS_r11(%rsi)
+	movq	%r15, UREGS_r15(%rsi)
+	popq	%r15
+	movq	%r10, UREGS_r10(%rsi)
+	movq	%r14, UREGS_r14(%rsi)
+	popq	%r14
+	movq	%r9, UREGS_r9(%rsi)
+	movq	%r13, UREGS_r13(%rsi)
+	popq	%r13
+	movq	%r8, UREGS_r8(%rsi)
+	movq	%r12, UREGS_r12(%rsi)
+	popq	%r12
+	movq	%rbp, UREGS_rbp(%rsi)
+	popq	%rbp
+	movq	%rbx, UREGS_rbx(%rsi)
+	popq	%rbx
+	movq	%rax, UREGS_rax(%rsi)
+	ret
+ .else
+ 	jmp	.Lin_restore
+ .endif
+.Ltry_lock_in\w:
+#ifdef CONFIG_SMP
+	movb	$PROTECTED_PORT, %al
+	lock cmpxchgb %dl, .Lport_in\w(%rip)
+	jne	.Lretry_in\w
+	movb	UREGS_rax(%rsi), %al
+#else
+	movb	%dl, .Lport_in\w(%rip)
+#endif
+	movq	UREGS_rdx(%rsi), %rdx
+	movq	UREGS_rsi(%rsi), %rsi
+	jmp	.Limm_in\w
+ .data # .section .wtext, "axw"
+.Limm_in\w:
+	in\w	$PROTECTED_PORT, %\a
+ .equiv .Lport_in\w, . - 1
+#ifdef CONFIG_SMP
+	movb	$PROTECTED_PORT, .Lport_in\w(%rip)
+#endif
+ 	jmp	.Lin_restore
+ .previous
+#ifdef CONFIG_SMP
+.Lretry_in\w:
+	pause
+	jmp	.Ltry_lock_in\w
+#endif
+ .endm
+
+	in_special b, al
+	in_special w, ax
+	in_special l, eax
+
+ .macro out_special w, a, v
+ENTRY(out\w\(_special))
+	movq	%rdx, %rcx
+	pushq	%rbx
+	movq	UREGS_rbx(%rdx), %rbx
+	movq	UREGS_rdx(%rdx), %rdx
+	pushq	%rbp
+	movq	UREGS_rbp(%rcx), %rbp
+	movq	UREGS_rax(%rcx), %rax
+	pushq	%r12
+	movq	UREGS_r12(%rcx), %r12
+	movq	UREGS_r8(%rcx), %r8
+	pushq	%r13
+	movq	UREGS_r13(%rcx), %r13
+	movq	UREGS_r9(%rcx), %r9
+	pushq	%r14
+	movq	UREGS_r14(%rcx), %r14
+	movq	UREGS_r10(%rcx), %r10
+	movw	%si, %dx
+	pushq	%r15
+	movq	UREGS_r15(%rcx), %r15
+	movq	UREGS_r11(%rcx), %r11
+ .ifnes "\w", "l"
+	mov\w	%\v, %\a
+ .else
+ .ifnes "\v", "edi"
+ .err
+ .endif
+	shrdq	$32, %rdi, %rax
+	rolq	$32, %rax
+ .endif
+	testb	%dh, %dh
+	movq	UREGS_rsi(%rcx), %rsi
+	movq	UREGS_rdi(%rcx), %rdi
+	pushq	%rcx
+	jz	.Llock_out\w
+	movq	UREGS_rcx(%rcx), %rcx
+	out\w	%\a, %dx
+ .ifndef .Lout_restore
+.Lout_restore:
+	pushq	%rcx
+	movq	8(%rsp), %rcx
+	movq	%rdx, UREGS_rdx(%rcx)
+	popq	UREGS_rcx(%rcx)
+	movq	%rdi, UREGS_rdi(%rcx)
+	movq	%rsi, UREGS_rsi(%rcx)
+	popq	%rdx
+	movq	%r11, UREGS_r11(%rcx)
+	movq	%r15, UREGS_r15(%rcx)
+	popq	%r15
+	movq	%r10, UREGS_r10(%rcx)
+	movq	%r14, UREGS_r14(%rcx)
+	popq	%r14
+	movq	%r9, UREGS_r9(%rcx)
+	movq	%r13, UREGS_r13(%rcx)
+	popq	%r13
+	movq	%r8, UREGS_r8(%rcx)
+	movq	%r12, UREGS_r12(%rcx)
+	popq	%r12
+	movq	%rbp, UREGS_rbp(%rcx)
+	popq	%rbp
+	movq	%rbx, UREGS_rbx(%rcx)
+	popq	%rbx
+	movq	%rax, UREGS_rax(%rcx)
+	ret
+ .else
+	jmp	.Lout_restore
+ .endif
+.Llock_out\w:
+#ifdef CONFIG_SMP
+	pushq	%rax
+.Ltry_lock_out\w:
+	movb	$PROTECTED_PORT, %al
+	lock cmpxchgb %dl, .Lport_out\w(%rip)
+	jne	.Lretry_out\w
+	popq	%rax
+#else
+	movb	%dl, .Lport_out\w(%rip)
+#endif
+	movq	UREGS_rdx(%rcx), %rdx
+	movq	UREGS_rcx(%rcx), %rcx
+	jmp	.Limm_out\w
+ .data # .section .wtext, "axw"
+.Limm_out\w:
+	out\w	%\a, $PROTECTED_PORT
+ .equiv .Lport_out\w, . - 1
+#ifdef CONFIG_SMP
+	movb	$PROTECTED_PORT, .Lport_out\w(%rip)
+#endif
+	jmp	.Lout_restore
+ .previous
+#ifdef CONFIG_SMP
+.Lretry_out\w:
+	pause
+	jmp	.Ltry_lock_out\w
+#endif
+ .endm
+
+	out_special b, al, dil
+	out_special w, ax, di
+	out_special l, eax, edi
Index: 2006-09-11/xen/include/asm-x86/io.h
===================================================================
--- 2006-09-11.orig/xen/include/asm-x86/io.h	2006-09-11 13:50:54.000000000 +0200
+++ 2006-09-11/xen/include/asm-x86/io.h	2006-09-11 13:52:31.000000000 +0200
@@ -5,6 +5,8 @@
 #include <xen/types.h>
 #include <asm/page.h>
 
+struct cpu_user_regs;
+
 /* We don't need real ioremap() on Xen/x86. */
 #define ioremap(x,l) (__va(x))
 #define iounmap(p)   ((void)0)
@@ -19,32 +21,34 @@
 #define __OUT1(s,x) \
 static inline void out##s(unsigned x value, unsigned short port) {
 
-#define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
+#define __OUT2(s,s1) \
+    __asm__ __volatile__ ("out" #s " %" s1 "0,%w1" : : "a" (value), "Nd" (port)); \
+}
 
 #define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port));} 
-
-#define __IN1(s) \
-static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
-
-#define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
-
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } 
-
-#define RETURN_TYPE unsigned char
-__IN(b,"")
-#undef RETURN_TYPE
-#define RETURN_TYPE unsigned short
-__IN(w,"")
-#undef RETURN_TYPE
-#define RETURN_TYPE unsigned int
-__IN(l,"")
-#undef RETURN_TYPE
+extern void out##s##_special(unsigned x value, unsigned short port, \
+                             struct cpu_user_regs *); \
+__OUT1(s,x) __OUT2(s,s1) \
+__OUT1(s##_p,x) __OUT2(s,s1)
+
+#define __IN1(s,x) \
+static inline unsigned x in##s(unsigned short port) { \
+    unsigned x value;
+
+#define __IN2(s,s1) \
+    __asm__ __volatile__ ("in" #s " %w1,%" s1 "0" : "=a" (value) : "Nd" (port)); \
+    return value; \
+}
+
+#define __IN(s,s1,x) \
+extern unsigned x in##s##_special(unsigned short port, \
+                                  struct cpu_user_regs *); \
+__IN1(s,x) __IN2(s,s1) \
+__IN1(s##_p,x) __IN2(s,s1)
+
+__IN(b,"b",char)
+__IN(w,"w",short)
+__IN(l,,int)
 
 __OUT(b,"b",char)
 __OUT(w,"w",short)
Index: 2006-09-11/xen/include/asm-x86/iocap.h
===================================================================
--- 2006-09-11.orig/xen/include/asm-x86/iocap.h	2006-09-11 13:50:54.000000000 +0200
+++ 2006-09-11/xen/include/asm-x86/iocap.h	2006-09-13 09:47:46.000000000 +0200
@@ -7,6 +7,15 @@
 #ifndef __X86_IOCAP_H__
 #define __X86_IOCAP_H__
 
+extern struct rangeset *ioport_caps, *ioport_emul;
+
+#define ioports_permit_access_all(s, e)                 \
+    rangeset_add_range(ioport_caps, s, e)
+#define ioports_deny_access_all(s, e)                   \
+    rangeset_remove_range(ioport_caps, s, e)
+#define ioports_any_access_permitted(s, e)              \
+    rangeset_contains_range(ioport_caps, s, e)
+
 #define ioports_permit_access(d, s, e)                  \
     rangeset_add_range((d)->arch.ioport_caps, s, e)
 #define ioports_deny_access(d, s, e)                    \
@@ -14,6 +23,13 @@
 #define ioports_access_permitted(d, s, e)               \
     rangeset_contains_range((d)->arch.ioport_caps, s, e)
 
+#define ioports_set_emul(s, e)                          \
+    rangeset_add_range(ioport_emul, s, e)
+#define ioports_set_noemul(s, e)                        \
+    rangeset_remove_range(ioport_emul, s, e)
+#define ioports_emul(s, e)                              \
+    rangeset_contains_range(ioport_emul, s, e)
+
 #define cache_flush_permitted(d)                       \
     (!rangeset_is_empty((d)->iomem_caps))
 
Index: 2006-09-11/xen/include/public/sysctl.h
===================================================================
--- 2006-09-11.orig/xen/include/public/sysctl.h	2006-09-11 09:06:11.000000000 +0200
+++ 2006-09-11/xen/include/public/sysctl.h	2006-09-13 09:45:47.000000000 +0200
@@ -122,6 +122,15 @@ struct xen_sysctl_getdomaininfolist {
 typedef struct xen_sysctl_getdomaininfolist xen_sysctl_getdomaininfolist_t;
 DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getdomaininfolist_t);
 
+#define XEN_SYSCTL_ioport_emulation 7
+struct xen_sysctl_ioport_emulation {
+    uint32_t first_port;              /* first port int range */
+    uint32_t nr_ports;                /* size of port range */
+    uint8_t  emulate;                 /* emulate access to range? */
+};
+typedef struct xen_sysctl_ioport_emulation xen_sysctl_ioport_emulation_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_ioport_emulation_t);
+
 struct xen_sysctl {
     uint32_t cmd;
     uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
@@ -132,6 +141,7 @@ struct xen_sysctl {
         struct xen_sysctl_sched_id          sched_id;
         struct xen_sysctl_perfc_op          perfc_op;
         struct xen_sysctl_getdomaininfolist getdomaininfolist;
+        struct xen_sysctl_ioport_emulation  ioport_emulation;
         uint8_t                             pad[128];
     } u;
 };

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

  reply	other threads:[~2006-09-13  9:46 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-09-11 16:12 [PATCH] enable port accesses with (almost) full register context Jan Beulich
2006-09-11 16:19 ` Keir Fraser
2006-09-12  7:15   ` Jan Beulich
2006-09-12  7:53     ` Keir Fraser
2006-09-12  9:03       ` Jan Beulich
2006-09-12  9:50         ` Keir Fraser
2006-09-12 10:32           ` Jan Beulich
2006-09-12 11:28             ` Keir Fraser
2006-09-13  9:46               ` Jan Beulich [this message]
2006-09-13 12:10                 ` Keir Fraser
2006-09-18 10:40                   ` Jan Beulich
2006-09-18 11:05                     ` Keir Fraser
2006-09-18 11:36                       ` Jan Beulich
2006-09-18 12:22                         ` Keir Fraser
2006-09-18 14:10               ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4507EFA3.76E4.0078.0@novell.com \
    --to=jbeulich@novell.com \
    --cc=Keir.Fraser@cl.cam.ac.uk \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.