mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
[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>
This commit is contained in:
1 parent
092b64b838
commit
5eeca68ffd
14 files changed
+505
-83
No files matched your search
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -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++);
|
||||
}
|
||||
@@ -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__ */
|
||||
+106
-20
@@ -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);
|
||||
}
|
||||
|
||||
pregs->eax = hvm_hypercall_table[pregs->eax](
|
||||
pregs->ebx, pregs->ecx, pregs->edx, pregs->esi, pregs->edi);
|
||||
}
|
||||
|
||||
#else /* __x86_64__ */
|
||||
#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:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
/*
|
||||
|
||||