aboutsummaryrefslogtreecommitdiffstats
path: root/tools/firmware
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 /tools/firmware
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>
Diffstat (limited to 'tools/firmware')
-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
8 files changed, 368 insertions, 62 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__ */