aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2006-08-04 20:30:12 +0100
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2006-08-04 20:30:12 +0100
commit5eeca68ffd007f81ac202eafdc96d44e5bb69bfb (patch)
treee13e0b26a95bebdff317e2618039024145886428
parent092b64b838ed9b5dc0f7daea671d500501a419ae (diff)
downloadxen-5eeca68ffd007f81ac202eafdc96d44e5bb69bfb.tar.gz
xen-5eeca68ffd007f81ac202eafdc96d44e5bb69bfb.tar.bz2
xen-5eeca68ffd007f81ac202eafdc96d44e5bb69bfb.zip
[HVMLOADER] HVM loader initialises hypercall shim and uses
it to interrogate Xen version information. Also add support for HVM hypercall execution on 64-bit host. Signed-off-by: Steven Smith <ssmith@xensource.com> Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--tools/firmware/Makefile2
-rw-r--r--tools/firmware/hvmloader/Makefile9
-rw-r--r--tools/firmware/hvmloader/acpi_madt.c4
-rw-r--r--tools/firmware/hvmloader/hvmloader.c117
-rw-r--r--tools/firmware/hvmloader/hypercall.h180
-rw-r--r--tools/firmware/hvmloader/mp_tables.c3
-rw-r--r--tools/firmware/hvmloader/util.c96
-rw-r--r--tools/firmware/hvmloader/util.h19
-rw-r--r--xen/arch/x86/hvm/hvm.c122
-rw-r--r--xen/arch/x86/hvm/platform.c14
-rw-r--r--xen/common/kernel.c7
-rw-r--r--xen/include/asm-x86/guest_access.h5
-rw-r--r--xen/include/asm-x86/hvm/guest_access.h3
-rw-r--r--xen/include/public/version.h3
14 files changed, 503 insertions, 81 deletions
diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile
index 63ccb7b17e..85902319e8 100644
--- a/tools/firmware/Makefile
+++ b/tools/firmware/Makefile
@@ -30,7 +30,7 @@ all:
.PHONY: install
install: all
[ -d $(INSTALL_DIR) ] || install -d -m0755 $(INSTALL_DIR)
- [ ! -e $(TARGET) ] || install -m0644 $(TARGET) $(INSTALL_DIR)
+ install -m0644 $(TARGET) $(INSTALL_DIR)
.PHONY: clean
clean:
diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile
index ecf1110ebe..66e149599a 100644
--- a/tools/firmware/hvmloader/Makefile
+++ b/tools/firmware/hvmloader/Makefile
@@ -42,12 +42,15 @@ OBJCOPY = objcopy
CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float
LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
+SRCS = hvmloader.c acpi_madt.c mp_tables.c util.c
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
.PHONY: all
all: hvmloader
-hvmloader: roms.h hvmloader.c acpi_madt.c mp_tables.c
- $(CC) $(CFLAGS) -c hvmloader.c acpi_madt.c mp_tables.c
- $(CC) $(LDFLAGS) -o hvmloader.tmp hvmloader.o acpi_madt.o mp_tables.o
+hvmloader: roms.h $(SRCS)
+ $(CC) $(CFLAGS) -c $(SRCS)
+ $(CC) $(LDFLAGS) -o hvmloader.tmp $(OBJS)
$(OBJCOPY) hvmloader.tmp hvmloader
rm -f hvmloader.tmp
diff --git a/tools/firmware/hvmloader/acpi_madt.c b/tools/firmware/hvmloader/acpi_madt.c
index f977d3ee4f..5a9c3063ae 100644
--- a/tools/firmware/hvmloader/acpi_madt.c
+++ b/tools/firmware/hvmloader/acpi_madt.c
@@ -20,13 +20,11 @@
#include "../acpi/acpi2_0.h"
#include "../acpi/acpi_madt.h"
-
+#include "util.h"
#include <xen/hvm/hvm_info_table.h>
#define NULL ((void*)0)
-extern int puts(const char *s);
-
static struct hvm_info_table *table = NULL;
static int validate_hvm_info(struct hvm_info_table *t)
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
index 4c4637dc58..ec38f5737e 100644
--- a/tools/firmware/hvmloader/hvmloader.c
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -23,9 +23,13 @@
*/
#include "roms.h"
#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
+#include "hypercall.h"
+#include "util.h"
+#include <xen/version.h>
#include <xen/hvm/hvm_info_table.h>
/* memory map */
+#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
@@ -75,65 +79,14 @@ extern int acpi_madt_update(unsigned char* acpi_start);
extern void create_mp_tables(void);
struct hvm_info_table *get_hvm_info_table(void);
-static inline void
-outw(unsigned short addr, unsigned short val)
-{
- __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val));
-}
-
-static inline void
-outb(unsigned short addr, unsigned char val)
-{
- __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val));
-}
-
-static inline unsigned char
-inb(unsigned short addr)
-{
- unsigned char val;
-
- __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr));
- return val;
-}
-
-void *
-memcpy(void *dest, const void *src, unsigned n)
-{
- int t0, t1, t2;
-
- __asm__ __volatile__(
- "cld\n"
- "rep; movsl\n"
- "testb $2,%b4\n"
- "je 1f\n"
- "movsw\n"
- "1: testb $1,%b4\n"
- "je 2f\n"
- "movsb\n"
- "2:"
- : "=&c" (t0), "=&D" (t1), "=&S" (t2)
- : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
- : "memory"
- );
- return dest;
-}
-
-int
-puts(const char *s)
-{
- while (*s)
- outb(0xE9, *s++);
- return 0;
-}
-
-int
+static int
cirrus_check(void)
{
outw(0x3C4, 0x9206);
return inb(0x3C5) == 0x12;
}
-int
+static int
vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
{
int eax;
@@ -147,7 +100,7 @@ vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
return eax;
}
-int
+static int
check_amd(void)
{
char id[12];
@@ -162,6 +115,60 @@ check_amd(void)
return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
}
+static void
+cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
+{
+ __asm__ __volatile__(
+ "cpuid"
+ : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "0" (idx) );
+}
+
+static void
+wrmsr(uint32_t idx, uint64_t v)
+{
+ __asm__ __volatile__(
+ "wrmsr"
+ : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
+}
+
+static void
+init_hypercalls(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+ unsigned long i;
+ char signature[13], number[13];
+ xen_extraversion_t extraversion;
+
+ cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+
+ *(uint32_t *)(signature + 0) = ebx;
+ *(uint32_t *)(signature + 4) = ecx;
+ *(uint32_t *)(signature + 8) = edx;
+ signature[12] = '\0';
+
+ if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
+ puts("FATAL: Xen hypervisor not detected\n");
+ __asm__ __volatile__( "ud2" );
+ }
+
+ cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
+
+ puts("Detected Xen v");
+ puts(itoa(number, eax >> 16));
+ puts(".");
+ puts(itoa(number, eax & 0xffff));
+
+ cpuid(0x40000002, &eax, &ebx, &ecx, &edx);
+
+ for (i = 0; i < eax; i++)
+ wrmsr(ebx, HYPERCALL_PHYSICAL_ADDRESS + (i << 12) + i);
+
+ hypercall_xen_version(XENVER_extraversion, extraversion);
+ puts(extraversion);
+ puts("\n");
+}
+
int
main(void)
{
@@ -169,6 +176,8 @@ main(void)
puts("HVM Loader\n");
+ init_hypercalls();
+
puts("Loading ROMBIOS ...\n");
memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
if (t->apic_enabled)
diff --git a/tools/firmware/hvmloader/hypercall.h b/tools/firmware/hvmloader/hypercall.h
new file mode 100644
index 0000000000..5648abf003
--- /dev/null
+++ b/tools/firmware/hvmloader/hypercall.h
@@ -0,0 +1,180 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Copyright (c) 2002-2006, K A Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HVMLOADER_HYPERCALL_H__
+#define __HVMLOADER_HYPERCALL_H__
+
+/*
+ * NB. Hypercall address needs to be relative to a linkage symbol for
+ * some version of ld to relocate the relative calls properly.
+ * Keep this in sync with HYPERCALL_PHYSICAL_ADDRESS in hvmloader.c!
+ */
+#define hypercall_pa "_start - 0x80000"
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#define _hypercall0(type, name) \
+({ \
+ long __res; \
+ asm volatile ( \
+ "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
+ : "=a" (__res) \
+ : \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
+ : "=a" (__res), "=b" (__ign1) \
+ : "1" ((long)(a1)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "1" ((long)(a1)), "2" ((long)(a2)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call "hypercall_pa" + " STR(__HYPERVISOR_##name * 32) \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+static inline int
+hypercall_sched_op(
+ int cmd, void *arg)
+{
+ return _hypercall2(int, sched_op, cmd, arg);
+}
+
+static inline int
+hypercall_memory_op(
+ unsigned int cmd, void *arg)
+{
+ return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+hypercall_multicall(
+ void *call_list, int nr_calls)
+{
+ return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+static inline int
+hypercall_event_channel_op(
+ int cmd, void *arg)
+{
+ return _hypercall2(int, event_channel_op, cmd, arg);
+}
+
+static inline int
+hypercall_xen_version(
+ int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+hypercall_console_io(
+ int cmd, int count, char *str)
+{
+ return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+hypercall_vm_assist(
+ unsigned int cmd, unsigned int type)
+{
+ return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+hypercall_vcpu_op(
+ int cmd, int vcpuid, void *extra_args)
+{
+ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+hypercall_hvm_op(
+ int cmd, void *arg)
+{
+ return _hypercall2(int, hvm_op, cmd, arg);
+}
+
+#endif /* __HVMLOADER_HYPERCALL_H__ */
diff --git a/tools/firmware/hvmloader/mp_tables.c b/tools/firmware/hvmloader/mp_tables.c
index 160cdcfc9a..d836832662 100644
--- a/tools/firmware/hvmloader/mp_tables.c
+++ b/tools/firmware/hvmloader/mp_tables.c
@@ -93,7 +93,8 @@ typedef signed long int64_t;
#define INTR_MAX_NR 16
-extern int puts(const char *); /* for printing */
+#include "util.h"
+
extern int get_vcpu_nr(void); /* for the guest's VCPU count */
/*
diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c
new file mode 100644
index 0000000000..b1a38fd036
--- /dev/null
+++ b/tools/firmware/hvmloader/util.c
@@ -0,0 +1,96 @@
+/*
+ * util.c: Helper library functions for HVMLoader.
+ *
+ * Leendert van Doorn, leendert@watson.ibm.com
+ * Copyright (c) 2005, International Business Machines Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
+#include "util.h"
+
+void outw(uint16_t addr, uint16_t val)
+{
+ __asm__ __volatile__ ("outw %%ax, %%dx" :: "d"(addr), "a"(val));
+}
+
+void outb(uint16_t addr, uint8_t val)
+{
+ __asm__ __volatile__ ("outb %%al, %%dx" :: "d"(addr), "a"(val));
+}
+
+uint8_t inb(uint16_t addr)
+{
+ uint8_t val;
+ __asm__ __volatile__ ("inb %w1,%0" : "=a" (val) : "Nd" (addr));
+ return val;
+}
+
+char *itoa(char *a, unsigned int i)
+{
+ unsigned int _i = i, x = 0;
+
+ do {
+ x++;
+ _i /= 10;
+ } while (_i != 0);
+
+ a += x;
+ *a-- = '\0';
+
+ do {
+ *a-- = (i % 10) + '0';
+ i /= 10;
+ } while (i != 0);
+
+ return a + 1;
+}
+
+int strcmp(const char *cs, const char *ct)
+{
+ signed char res;
+
+ while (((res = *cs - *ct++) == 0) && (*cs++ != '\0'))
+ continue;
+
+ return res;
+}
+
+void *memcpy(void *dest, const void *src, unsigned n)
+{
+ int t0, t1, t2;
+
+ __asm__ __volatile__(
+ "cld\n"
+ "rep; movsl\n"
+ "testb $2,%b4\n"
+ "je 1f\n"
+ "movsw\n"
+ "1: testb $1,%b4\n"
+ "je 2f\n"
+ "movsb\n"
+ "2:"
+ : "=&c" (t0), "=&D" (t1), "=&S" (t2)
+ : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
+ : "memory"
+ );
+ return dest;
+}
+
+void puts(const char *s)
+{
+ while (*s)
+ outb(0xE9, *s++);
+}
diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h
new file mode 100644
index 0000000000..57aab64998
--- /dev/null
+++ b/tools/firmware/hvmloader/util.h
@@ -0,0 +1,19 @@
+#ifndef __HVMLOADER_UTIL_H__
+#define __HVMLOADER_UTIL_H__
+
+/* I/O output */
+void outw(uint16_t addr, uint16_t val);
+void outb(uint16_t addr, uint8_t val);
+
+/* I/O input */
+uint8_t inb(uint16_t addr);
+
+/* String and memory functions */
+int strcmp(const char *cs, const char *ct);
+void *memcpy(void *dest, const void *src, unsigned n);
+char *itoa(char *a, unsigned int i);
+
+/* Debug output */
+void puts(const char *s);
+
+#endif /* __HVMLOADER_UTIL_H__ */
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 7b348e32dd..cbc2a5bd4a 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -28,6 +28,7 @@
#include <xen/domain.h>
#include <xen/domain_page.h>
#include <xen/hypercall.h>
+#include <xen/guest_access.h>
#include <asm/current.h>
#include <asm/io.h>
#include <asm/shadow.h>
@@ -46,7 +47,8 @@
#include <public/sched.h>
#include <public/hvm/ioreq.h>
#include <public/hvm/hvm_info_table.h>
-#include <xen/guest_access.h>
+#include <public/version.h>
+#include <public/memory.h>
int hvm_enabled = 0;
@@ -305,55 +307,139 @@ void hvm_print_line(struct vcpu *v, const char c)
pbuf[(*index)++] = c;
}
-#if defined(__i386__)
-
typedef unsigned long hvm_hypercall_t(
unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
-#define HYPERCALL(x) [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x
+
+#define HYPERCALL(x) \
+ [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x
+#define HYPERCALL_COMPAT32(x) \
+ [ __HYPERVISOR_ ## x ] = (hvm_hypercall_t *) do_ ## x ## _compat32
+
+#if defined(__i386__)
+
static hvm_hypercall_t *hvm_hypercall_table[] = {
- HYPERCALL(mmu_update),
HYPERCALL(memory_op),
HYPERCALL(multicall),
- HYPERCALL(update_va_mapping),
- HYPERCALL(event_channel_op_compat),
HYPERCALL(xen_version),
- HYPERCALL(grant_table_op),
HYPERCALL(event_channel_op),
HYPERCALL(hvm_op)
};
-#undef HYPERCALL
void hvm_do_hypercall(struct cpu_user_regs *pregs)
{
- if ( ring_3(pregs) )
+ if ( unlikely(ring_3(pregs)) )
{
pregs->eax = -EPERM;
return;
}
- if ( pregs->eax > ARRAY_SIZE(hvm_hypercall_table) ||
- !hvm_hypercall_table[pregs->eax] )
+ if ( (pregs->eax >= NR_hypercalls) || !hvm_hypercall_table[pregs->eax] )
{
DPRINTK("HVM vcpu %d:%d did a bad hypercall %d.\n",
current->domain->domain_id, current->vcpu_id,
pregs->eax);
pregs->eax = -ENOSYS;
+ return;
}
- else
+
+ pregs->eax = hvm_hypercall_table[pregs->eax](
+ pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi);
+}
+
+#else /* defined(__x86_64__) */
+
+static long do_memory_op_compat32(int cmd, XEN_GUEST_HANDLE(void) arg)
+{
+ extern long do_add_to_physmap(struct xen_add_to_physmap *xatp);
+ long rc;
+
+ switch ( cmd )
+ {
+ case XENMEM_add_to_physmap:
{
- pregs->eax = hvm_hypercall_table[pregs->eax](
- pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi);
+ struct {
+ domid_t domid;
+ uint32_t space;
+ uint32_t idx;
+ uint32_t gpfn;
+ } u;
+ struct xen_add_to_physmap h;
+
+ if ( copy_from_guest(&u, arg, 1) )
+ return -EFAULT;
+
+ h.domid = u.domid;
+ h.space = u.space;
+ h.idx = u.idx;
+ h.gpfn = u.gpfn;
+
+ this_cpu(guest_handles_in_xen_space) = 1;
+ rc = do_memory_op(cmd, guest_handle_from_ptr(&h, void));
+ this_cpu(guest_handles_in_xen_space) = 0;
+
+ break;
+ }
+
+ default:
+ DPRINTK("memory_op %d.\n", cmd);
+ rc = -ENOSYS;
+ break;
}
+
+ return rc;
}
-#else /* __x86_64__ */
+static hvm_hypercall_t *hvm_hypercall64_table[NR_hypercalls] = {
+ HYPERCALL(memory_op),
+ HYPERCALL(xen_version),
+ HYPERCALL(hvm_op),
+ HYPERCALL(event_channel_op)
+};
+
+static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = {
+ HYPERCALL_COMPAT32(memory_op),
+ HYPERCALL(xen_version),
+ HYPERCALL(hvm_op),
+ HYPERCALL(event_channel_op)
+};
void hvm_do_hypercall(struct cpu_user_regs *pregs)
{
- printk("not supported yet!\n");
+ if ( unlikely(ring_3(pregs)) )
+ {
+ pregs->rax = -EPERM;
+ return;
+ }
+
+ pregs->rax = (uint32_t)pregs->eax; /* mask in case compat32 caller */
+ if ( (pregs->rax >= NR_hypercalls) || !hvm_hypercall64_table[pregs->rax] )
+ {
+ DPRINTK("HVM vcpu %d:%d did a bad hypercall %ld.\n",
+ current->domain->domain_id, current->vcpu_id,
+ pregs->rax);
+ pregs->rax = -ENOSYS;
+ return;
+ }
+
+ if ( current->domain->arch.ops->guest_paging_levels == PAGING_L4 )
+ {
+ pregs->rax = hvm_hypercall64_table[pregs->rax](pregs->rdi,
+ pregs->rsi,
+ pregs->rdx,
+ pregs->r10,
+ pregs->r8);
+ }
+ else
+ {
+ pregs->eax = hvm_hypercall32_table[pregs->eax]((uint32_t)pregs->ebx,
+ (uint32_t)pregs->ecx,
+ (uint32_t)pregs->edx,
+ (uint32_t)pregs->esi,
+ (uint32_t)pregs->edi);
+ }
}
-#endif
+#endif /* defined(__x86_64__) */
/* Initialise a hypercall transfer page for a VMX domain using
paravirtualised drivers. */
diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c
index efe443a8a0..af8b55d661 100644
--- a/xen/arch/x86/hvm/platform.c
+++ b/xen/arch/x86/hvm/platform.c
@@ -1034,17 +1034,31 @@ void handle_mmio(unsigned long va, unsigned long gpa)
}
}
+DEFINE_PER_CPU(int, guest_handles_in_xen_space);
+
/* Note that copy_{to,from}_user_hvm don't set the A and D bits on
PTEs, and require the PTE to be writable even when they're only
trying to read from it. The guest is expected to deal with
this. */
unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len)
{
+ if ( this_cpu(guest_handles_in_xen_space) )
+ {
+ memcpy(to, from, len);
+ return 0;
+ }
+
return !hvm_copy((void *)from, (unsigned long)to, len, HVM_COPY_OUT);
}
unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len)
{
+ if ( this_cpu(guest_handles_in_xen_space) )
+ {
+ memcpy(to, from, len);
+ return 0;
+ }
+
return !hvm_copy(to, (unsigned long)from, len, HVM_COPY_IN);
}
diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index 5c3069bb62..0f14494c20 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -217,6 +217,13 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE(void) arg)
return (!guest_handle_is_null(arg) ? -EINVAL : PAGE_SIZE);
}
+ case XENVER_guest_handle:
+ {
+ if ( copy_to_guest(arg, (char *)current->domain->handle,
+ sizeof(current->domain->handle)) )
+ return -EFAULT;
+ return 0;
+ }
}
return -ENOSYS;
diff --git a/xen/include/asm-x86/guest_access.h b/xen/include/asm-x86/guest_access.h
index 7b88aad86b..caad3525b0 100644
--- a/xen/include/asm-x86/guest_access.h
+++ b/xen/include/asm-x86/guest_access.h
@@ -20,9 +20,12 @@
/* Cast a guest handle to the specified type of handle. */
#define guest_handle_cast(hnd, type) ({ \
type *_x = (hnd).p; \
- (XEN_GUEST_HANDLE(type)) { _x }; \
+ (XEN_GUEST_HANDLE(type)) { _x }; \
})
+#define guest_handle_from_ptr(ptr, type) \
+ ((XEN_GUEST_HANDLE(type)) { (type *)ptr })
+
/*
* Copy an array of objects to guest context via a guest handle,
* specifying an offset into the guest array.
diff --git a/xen/include/asm-x86/hvm/guest_access.h b/xen/include/asm-x86/hvm/guest_access.h
index 7a89e81536..25ea341e5b 100644
--- a/xen/include/asm-x86/hvm/guest_access.h
+++ b/xen/include/asm-x86/hvm/guest_access.h
@@ -1,6 +1,9 @@
#ifndef __ASM_X86_HVM_GUEST_ACCESS_H__
#define __ASM_X86_HVM_GUEST_ACCESS_H__
+#include <xen/percpu.h>
+DECLARE_PER_CPU(int, guest_handles_in_xen_space);
+
unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len);
unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len);
diff --git a/xen/include/public/version.h b/xen/include/public/version.h
index 8976130c59..dbe18c9e08 100644
--- a/xen/include/public/version.h
+++ b/xen/include/public/version.h
@@ -57,6 +57,9 @@ typedef struct xen_feature_info xen_feature_info_t;
/* arg == NULL; returns host memory page size. */
#define XENVER_pagesize 7
+/* arg == xen_domain_handle_t. */
+#define XENVER_guest_handle 8
+
#endif /* __XEN_PUBLIC_VERSION_H__ */
/*