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: Mon, 18 Sep 2006 15:10:51 +0100 [thread overview]
Message-ID: <450EC50B.76E4.0078.0@novell.com> (raw)
In-Reply-To: <C12C5861.1215%Keir.Fraser@cl.cam.ac.uk>
[-- Attachment #1: Type: text/plain, Size: 2087 bytes --]
>>> Keir Fraser <Keir.Fraser@cl.cam.ac.uk> 12.09.06 13:28 >>>
>On 12/9/06 11:32, "Jan Beulich" <jbeulich@novell.com> wrote:
>
>> Hm, I don't like this on-the-fly building of code very much, and I also don't
>> like writing assembly code that can obviously written to perform better. Also,
>> on 64-bits the code wouldn't look so much nicer since there's no {push,pop}ad.
>> But certainly, if you refuse to take the patch without changing that...
>
>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?
>
>Something like:
> call save_host_restore_guest
> <IN or OUT>
> call save_guest_restore_host
> ret
>
>Would that be reasonable?
Attaching the revised patch.
>> That sounds right (and better than the current way). I'll do that change,
>> though I guess I'd still not call it direct execution.
>
>'Special' is a crappy description because it's so non-specific. How about
>'BIOS' ports? I can't think of any reason that emulating these accesses
>could be a problem, except that BIOS/firmware is trapping them and expecting
>more context than the hardware instruction defines as being required.
>
>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.
The new measurement results (full context compared to normal emulation):
PentiumIII (32-bit) 88%
Pentium4 (64-bit) 90%
Jan
[-- Attachment #2: xen-x86-io-register-context-3.patch --]
[-- Type: text/plain, Size: 23654 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-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/domain_build.c 2006-09-18 15:15:40.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-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/sysctl.c 2006-09-18 13:58:56.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-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/traps.c 2006-09-18 15:15:58.000000000 +0200
@@ -1002,9 +1002,20 @@ static inline int admin_io_okay(
return ioports_access_permitted(v->domain, port, port + bytes - 1);
}
+typedef unsigned long io_emul_stub_t(struct cpu_user_regs *) __attribute__((__regparm__(1)));
+long io_emul_stub_offset = 0, io_emul_insn_offset = 0;
+
+/* 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. */
static inline unsigned char inb_user(
- unsigned int port, struct vcpu *v, struct cpu_user_regs *regs)
+ unsigned int port, io_emul_stub_t *stub,
+ struct vcpu *v, struct cpu_user_regs *regs)
{
/*
* Allow read access to port 0x61. Bit 4 oscillates with period 30us, and
@@ -1014,18 +1025,54 @@ static inline int admin_io_okay(
* 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 !stub || normal_io_okay(port, 1) ? inb(port) : stub(regs);
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))
+
+static inline unsigned short inw_user(
+ unsigned int port, io_emul_stub_t *stub,
+ struct vcpu *v, struct cpu_user_regs *regs)
+{
+ if ( admin_io_okay(port, 2, v, regs) )
+ return !stub || normal_io_okay(port, 2) ? inw(port) : stub(regs);
+ return ~0;
+}
+
+static inline unsigned int inl_user(
+ unsigned int port, io_emul_stub_t *stub,
+ struct vcpu *v, struct cpu_user_regs *regs)
+{
+ if ( admin_io_okay(port, 4, v, regs) )
+ return !stub || normal_io_okay(port, 4) ? inl(port) : stub(regs);
+ return ~0;
+}
+
+static inline void outb_user(
+ unsigned char value, unsigned int port,
+ io_emul_stub_t *stub,
+ struct vcpu *v, struct cpu_user_regs *regs)
+{
+ if ( admin_io_okay(port, 1, v, regs) )
+ !stub || normal_io_okay(port, 1) ? outb(value, port) : (void)stub(regs);
+}
+
+static inline void outw_user(
+ unsigned short value, unsigned int port,
+ io_emul_stub_t *stub,
+ struct vcpu *v, struct cpu_user_regs *regs)
+{
+ if ( admin_io_okay(port, 2, v, regs) )
+ !stub || normal_io_okay(port, 2) ? outw(value, port) : (void)stub(regs);
+}
+
+static inline void outl_user(
+ unsigned int value, unsigned int port,
+ io_emul_stub_t *stub,
+ struct vcpu *v, struct cpu_user_regs *regs)
+{
+ if ( admin_io_okay(port, 4, v, regs) )
+ !stub || normal_io_okay(port, 4) ? outl(value, port) : (void)stub(regs);
+}
/* Instruction fetch with error handling. */
#define insn_fetch(_type, _size, _ptr) \
@@ -1044,6 +1091,8 @@ static int emulate_privileged_op(struct
u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0;
unsigned int port, i, op_bytes = 4, data, rc;
u32 l, h;
+ io_emul_stub_t *stub;
+ char *insn;
/* Legacy prefixes. */
for ( i = 0; i < 8; i++ )
@@ -1101,13 +1150,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, NULL, v, regs);
break;
case 2:
- data = (u16)inw_user((u16)regs->edx, v, regs);
+ data = (u16)inw_user((u16)regs->edx, NULL, v, regs);
break;
case 4:
- data = (u32)inl_user((u16)regs->edx, v, regs);
+ data = (u32)inl_user((u16)regs->edx, NULL, v, regs);
break;
}
if ( (rc = copy_to_user((void *)regs->edi, &data, op_bytes)) != 0 )
@@ -1133,13 +1182,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, NULL, v, regs);
break;
case 2:
- outw_user((u16)data, (u16)regs->edx, v, regs);
+ outw_user((u16)data, (u16)regs->edx, NULL, v, regs);
break;
case 4:
- outl_user((u32)data, (u16)regs->edx, v, regs);
+ outl_user((u32)data, (u16)regs->edx, NULL, v, regs);
break;
}
regs->esi += (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes);
@@ -1157,27 +1206,33 @@ static int emulate_privileged_op(struct
}
/* I/O Port and Interrupt Flag instructions. */
+ insn = (char *)get_stack_bottom();
+ stub = (io_emul_stub_t *)(insn + io_emul_stub_offset);
+ insn += io_emul_insn_offset;
+ *insn++ = op_bytes != 2 ? 0x90 : 0x66;
+ *insn++ = opcode;
switch ( opcode )
{
case 0xe4: /* IN imm8,%al */
op_bytes = 1;
case 0xe5: /* IN imm8,%eax */
port = insn_fetch(u8, 1, eip);
+ *insn = port;
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;
+ regs->eax = res | (u8)inb_user(port, stub, v, regs);
break;
case 2:
- regs->eax &= ~0xffffUL;
- regs->eax |= (u16)inw_user(port, v, regs);
+ res = regs->eax & ~0xffffUL;
+ regs->eax = res | (u16)inw_user(port, stub, v, regs);
break;
case 4:
- regs->eax = (u32)inl_user(port, v, regs);
+ regs->eax = (u32)inl_user(port, stub, v, regs);
break;
}
goto done;
@@ -1186,25 +1241,27 @@ static int emulate_privileged_op(struct
op_bytes = 1;
case 0xed: /* IN %dx,%eax */
port = (u16)regs->edx;
+ *insn = 0x90;
goto exec_in;
case 0xe6: /* OUT %al,imm8 */
op_bytes = 1;
case 0xe7: /* OUT %eax,imm8 */
port = insn_fetch(u8, 1, eip);
+ *insn = port;
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);
+ outb_user((u8)regs->eax, port, stub, v, regs);
break;
case 2:
- outw_user((u16)regs->eax, port, v, regs);
+ outw_user((u16)regs->eax, port, stub, v, regs);
break;
case 4:
- outl_user((u32)regs->eax, port, v, regs);
+ outl_user((u32)regs->eax, port, stub, v, regs);
break;
}
goto done;
@@ -1213,6 +1270,7 @@ static int emulate_privileged_op(struct
op_bytes = 1;
case 0xef: /* OUT %eax,%dx */
port = (u16)regs->edx;
+ *insn = 0x90;
goto exec_out;
case 0xfa: /* CLI */
Index: 2006-09-11/xen/arch/x86/x86_32/Makefile
===================================================================
--- 2006-09-11.orig/xen/arch/x86/x86_32/Makefile 2006-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/x86_32/Makefile 2006-09-18 13:58:56.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-18 14:32:37.000000000 +0200
@@ -0,0 +1,42 @@
+/*
+ * Special (full-context) I/O handling routines.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+ENTRY(save_host_restore_guest)
+ 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(save_guest_restore_host)
+ 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
Index: 2006-09-11/xen/arch/x86/x86_32/traps.c
===================================================================
--- 2006-09-11.orig/xen/arch/x86/x86_32/traps.c 2006-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/x86_32/traps.c 2006-09-18 15:15:40.000000000 +0200
@@ -13,6 +13,7 @@
#include <xen/nmi.h>
#include <asm/current.h>
#include <asm/flushtlb.h>
+#include <asm/io.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/support.h>
@@ -250,6 +251,7 @@ fastcall void smp_deferred_nmi(struct cp
void __init percpu_traps_init(void)
{
struct tss_struct *tss = &doublefault_tss;
+ char *stack_bottom, *stack;
asmlinkage int hypercall(void);
if ( smp_processor_id() != 0 )
@@ -283,6 +285,28 @@ void __init percpu_traps_init(void)
(unsigned long)tss, 235, 9);
set_task_gate(TRAP_double_fault, __DOUBLEFAULT_TSS_ENTRY<<3);
+
+ /*
+ * Stub for full-context I/O emulation.
+ */
+ stack_bottom = (char *)get_stack_bottom();
+ stack = (char *)((unsigned long)stack_bottom & ~(STACK_SIZE - 1));
+ if (!io_emul_stub_offset)
+ io_emul_stub_offset = stack - stack_bottom;
+ else
+ BUG_ON(io_emul_stub_offset != stack - stack_bottom);
+ /* call save_host_restore_guest */
+ stack[0] = 0xe8;
+ *(s32*)&stack[1] = (char *)save_host_restore_guest - &stack[5];
+ stack += 5;
+ if (!io_emul_insn_offset)
+ io_emul_insn_offset = stack - stack_bottom;
+ else
+ BUG_ON(io_emul_insn_offset != stack - stack_bottom);
+ stack += 3; /* operand size prefix, opcode, immediate */
+ /* jmp save_guest_restore_host */
+ stack[0] = 0xe9;
+ *(s32*)&stack[1] = (char *)save_guest_restore_host - &stack[5];
}
void init_int80_direct_trap(struct vcpu *v)
Index: 2006-09-11/xen/arch/x86/x86_64/Makefile
===================================================================
--- 2006-09-11.orig/xen/arch/x86/x86_64/Makefile 2006-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/x86_64/Makefile 2006-09-18 15:15:40.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-18 14:41:26.000000000 +0200
@@ -0,0 +1,62 @@
+/*
+ * Special (full-context) I/O handling routines.
+ *
+ * Copyright (c) 2006, Novell, Inc.
+ */
+
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+ENTRY(save_host_restore_guest)
+ 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(save_guest_restore_host)
+ 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
Index: 2006-09-11/xen/arch/x86/x86_64/traps.c
===================================================================
--- 2006-09-11.orig/xen/arch/x86/x86_64/traps.c 2006-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/arch/x86/x86_64/traps.c 2006-09-18 15:15:41.000000000 +0200
@@ -14,6 +14,7 @@
#include <xen/nmi.h>
#include <asm/current.h>
#include <asm/flushtlb.h>
+#include <asm/io.h>
#include <asm/msr.h>
#include <asm/shadow.h>
#include <asm/hvm/hvm.h>
@@ -331,6 +332,29 @@ void __init percpu_traps_init(void)
wrmsr(MSR_STAR, 0, (FLAT_RING3_CS32<<16) | __HYPERVISOR_CS);
wrmsr(MSR_SYSCALL_MASK, EF_VM|EF_RF|EF_NT|EF_DF|EF_IE|EF_TF, 0U);
+
+ /*
+ * Stub for full-context I/O emulation.
+ */
+
+ /* Skip the compatibility-mode entry trampoline. */
+ stack += 26;
+ if (!io_emul_stub_offset)
+ io_emul_stub_offset = stack - stack_bottom;
+ else
+ BUG_ON(io_emul_stub_offset != stack - stack_bottom);
+ /* call save_host_restore_guest */
+ stack[0] = 0xe8;
+ *(s32*)&stack[1] = (char *)save_host_restore_guest - &stack[5];
+ stack += 5;
+ if (!io_emul_insn_offset)
+ io_emul_insn_offset = stack - stack_bottom;
+ else
+ BUG_ON(io_emul_insn_offset != stack - stack_bottom);
+ stack += 3; /* operand size prefix, opcode, immediate */
+ /* jmp save_guest_restore_host */
+ stack[0] = 0xe9;
+ *(s32*)&stack[1] = (char *)save_guest_restore_host - &stack[5];
}
static long register_guest_callback(struct callback_register *reg)
Index: 2006-09-11/xen/include/asm-x86/io.h
===================================================================
--- 2006-09-11.orig/xen/include/asm-x86/io.h 2006-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/include/asm-x86/io.h 2006-09-18 15:11:38.000000000 +0200
@@ -50,4 +50,10 @@ __OUT(b,"b",char)
__OUT(w,"w",short)
__OUT(l,,int)
+struct cpu_user_regs;
+void save_host_restore_guest(struct cpu_user_regs *) __attribute__((__regparm__(1)));
+unsigned long save_guest_restore_host(unsigned long) __attribute__((__regparm__(1)));
+
+extern long io_emul_stub_offset, io_emul_insn_offset;
+
#endif
Index: 2006-09-11/xen/include/asm-x86/iocap.h
===================================================================
--- 2006-09-11.orig/xen/include/asm-x86/iocap.h 2006-09-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/include/asm-x86/iocap.h 2006-09-18 13:58:56.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-18 13:58:26.000000000 +0200
+++ 2006-09-11/xen/include/public/sysctl.h 2006-09-18 13:58:56.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
prev parent reply other threads:[~2006-09-18 14:10 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
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 [this message]
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=450EC50B.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.