diff options
author | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2006-08-04 20:30:12 +0100 |
---|---|---|
committer | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2006-08-04 20:30:12 +0100 |
commit | 5eeca68ffd007f81ac202eafdc96d44e5bb69bfb (patch) | |
tree | e13e0b26a95bebdff317e2618039024145886428 /tools/firmware | |
parent | 092b64b838ed9b5dc0f7daea671d500501a419ae (diff) | |
download | xen-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/Makefile | 2 | ||||
-rw-r--r-- | tools/firmware/hvmloader/Makefile | 9 | ||||
-rw-r--r-- | tools/firmware/hvmloader/acpi_madt.c | 4 | ||||
-rw-r--r-- | tools/firmware/hvmloader/hvmloader.c | 117 | ||||
-rw-r--r-- | tools/firmware/hvmloader/hypercall.h | 180 | ||||
-rw-r--r-- | tools/firmware/hvmloader/mp_tables.c | 3 | ||||
-rw-r--r-- | tools/firmware/hvmloader/util.c | 96 | ||||
-rw-r--r-- | tools/firmware/hvmloader/util.h | 19 |
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__ */ |