[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:
kfraser@localhost.localdomain committed 2006-08-04 20:30:12 +01:00
1 parent 092b64b838
commit 5eeca68ffd
14 files changed
+505 -83

No files matched your search

+1 -1
View File
@@ -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:
+6 -3
View File
@@ -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
+1 -3
View File
@@ -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)
+63 -54
View File
@@ -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)
+180
View File
@@ -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__ */
+2 -1
View File
@@ -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 */
/*
+96
View File
@@ -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++);
}
+19
View File
@@ -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
View File
@@ -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. */
+14
View File
@@ -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);
}
+7
View File
@@ -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;
+4 -1
View File
@@ -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.
+3
View File
@@ -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);
+3
View File
@@ -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__ */
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.