aboutsummaryrefslogtreecommitdiffstats
path: root/tools/firmware/hvmloader
diff options
context:
space:
mode:
Diffstat (limited to 'tools/firmware/hvmloader')
-rw-r--r--tools/firmware/hvmloader/Makefile56
-rw-r--r--tools/firmware/hvmloader/acpi_madt.c190
-rw-r--r--tools/firmware/hvmloader/hvmloader.c211
-rw-r--r--tools/firmware/hvmloader/mkhex26
4 files changed, 483 insertions, 0 deletions
diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile
new file mode 100644
index 0000000000..c23698e775
--- /dev/null
+++ b/tools/firmware/hvmloader/Makefile
@@ -0,0 +1,56 @@
+#
+# Makefile
+#
+# 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.
+#
+
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+# The HVM loader is started in 32-bit mode at the address below:
+LOADADDR = 0x100000
+
+DEFINES =-DDEBUG
+XENINC =-I$(XEN_ROOT)/tools/libxc
+
+OBJECTS = hvmloader.o acpi_madt.o
+
+CC = gcc
+OBJCOPY = objcopy
+CFLAGS = $(DEFINES) -I. $(XENINC) -Wall -fno-builtin -O2 -msoft-float
+CFLAGS += -m32 -march=i686
+LDFLAGS = -m32 -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR)
+
+all: hvmloader
+
+hvmloader: roms.h hvmloader.c acpi_madt.c
+ $(CC) $(CFLAGS) -c hvmloader.c acpi_madt.c
+ $(CC) $(LDFLAGS) -o hvmloader.tmp hvmloader.o acpi_madt.o
+ $(OBJCOPY) hvmloader.tmp hvmloader
+ rm -f hvmloader.tmp
+
+roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabios/VGABIOS-lgpl-latest.cirrus.bin ../vmxassist/vmxassist.bin
+ ./mkhex rombios ../rombios/BIOS-bochs-latest > roms.h
+ ./mkhex vgabios_stdvga ../vgabios/VGABIOS-lgpl-latest.bin >> roms.h
+ ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
+ ./mkhex vmxassist ../vmxassist/vmxassist.bin >> roms.h
+ ./mkhex acpi ../acpi/acpi.bin >> roms.h
+
+clean:
+ rm -f roms.h acpi.h
+ rm -f hvmloader hvmloader.tmp hvmloader.o $(OBJECTS)
+
diff --git a/tools/firmware/hvmloader/acpi_madt.c b/tools/firmware/hvmloader/acpi_madt.c
new file mode 100644
index 0000000000..2e6d8d79e2
--- /dev/null
+++ b/tools/firmware/hvmloader/acpi_madt.c
@@ -0,0 +1,190 @@
+/*
+ * acpi_madt.c: Update ACPI MADT table for multiple processor guest.
+ *
+ * Yu Ke, ke.yu@intel.com
+ * Copyright (c) 2005, Intel 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"
+#include "../acpi/acpi_madt.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)
+{
+ char signature[] = "HVM INFO";
+ uint8_t *ptr = (uint8_t *)t;
+ uint8_t sum = 0;
+ int i;
+
+ /* strncmp(t->signature, "HVM INFO", 8) */
+ for (i = 0; i < 8; i++) {
+ if (signature[i] != t->signature[i]) {
+ puts("Bad hvm info signature\n");
+ return 0;
+ }
+ }
+
+ for (i = 0; i < t->length; i++)
+ sum += ptr[i];
+
+ return (sum == 0);
+}
+
+/* xc_vmx_builder wrote hvm info at 0x9F800. Return it. */
+static struct hvm_info_table *
+get_hvm_info_table(void)
+{
+ struct hvm_info_table *t;
+
+ if (table != NULL)
+ return table;
+
+ t = (struct hvm_info_table *)HVM_INFO_PADDR;
+
+ if (!validate_hvm_info(t)) {
+ puts("Bad hvm info table\n");
+ return NULL;
+ }
+
+ table = t;
+
+ return table;
+}
+
+int
+get_vcpu_nr(void)
+{
+ struct hvm_info_table *t = get_hvm_info_table();
+ return (t ? t->nr_vcpus : 1); /* default 1 vcpu */
+}
+
+int
+get_acpi_enabled(void)
+{
+ struct hvm_info_table *t = get_hvm_info_table();
+ return (t ? t->acpi_enabled : 0); /* default no acpi */
+}
+
+
+static void *
+acpi_madt_get_madt(unsigned char *acpi_start)
+{
+ ACPI_2_0_RSDP *rsdp=NULL;
+ ACPI_2_0_RSDT *rsdt=NULL;
+ ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *madt;
+
+ rsdp = (ACPI_2_0_RSDP *)(acpi_start + sizeof(ACPI_2_0_FACS));
+ if (rsdp->Signature != ACPI_2_0_RSDP_SIGNATURE) {
+ puts("Bad RSDP signature\n");
+ return NULL;
+ }
+
+ rsdt= (ACPI_2_0_RSDT *)
+ (acpi_start + rsdp->RsdtAddress - ACPI_PHYSICAL_ADDRESS);
+ if (rsdt->Header.Signature != ACPI_2_0_RSDT_SIGNATURE) {
+ puts("Bad RSDT signature\n");
+ return NULL;
+ }
+
+ madt = (ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *)
+ ( acpi_start+ rsdt->Entry[1] - ACPI_PHYSICAL_ADDRESS);
+ if (madt->Header.Header.Signature !=
+ ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE) {
+ puts("Bad MADT signature \n");
+ return NULL;
+ }
+
+ return madt;
+}
+
+static void
+set_checksum(void *start, int checksum_offset, int len)
+{
+ unsigned char sum = 0;
+ unsigned char *ptr;
+
+ ptr = start;
+ ptr[checksum_offset] = 0;
+ while (len--)
+ sum += *ptr++;
+
+ ptr = start;
+ ptr[checksum_offset] = -sum;
+}
+
+static int
+acpi_madt_set_local_apics(
+ int nr_vcpu,
+ ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *madt)
+{
+ int i;
+
+ if ((nr_vcpu > MAX_VIRT_CPUS) || (nr_vcpu < 0) || !madt)
+ return -1;
+
+ for (i = 0; i < nr_vcpu; i++) {
+ madt->LocalApic[i].Type = ACPI_PROCESSOR_LOCAL_APIC;
+ madt->LocalApic[i].Length = sizeof (ACPI_LOCAL_APIC_STRUCTURE);
+ madt->LocalApic[i].AcpiProcessorId = i;
+ madt->LocalApic[i].ApicId = i;
+ madt->LocalApic[i].Flags = 1;
+ }
+
+ madt->Header.Header.Length =
+ sizeof(ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE) -
+ (MAX_VIRT_CPUS - nr_vcpu)* sizeof(ACPI_LOCAL_APIC_STRUCTURE);
+
+ return 0;
+}
+
+#define FIELD_OFFSET(TYPE,Field) ((unsigned int)(&(((TYPE *) 0)->Field)))
+
+int acpi_madt_update(unsigned char *acpi_start)
+{
+ int rc;
+ ACPI_MULTIPLE_APIC_DESCRIPTION_TABLE *madt;
+
+ madt = acpi_madt_get_madt(acpi_start);
+ if (!madt)
+ return -1;
+
+ rc = acpi_madt_set_local_apics(get_vcpu_nr(), madt);
+ if (rc != 0)
+ return rc;
+
+ set_checksum(
+ madt, FIELD_OFFSET(ACPI_TABLE_HEADER, Checksum),
+ madt->Header.Header.Length);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
new file mode 100644
index 0000000000..9700dfbb08
--- /dev/null
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -0,0 +1,211 @@
+/*
+ * hvmloader.c: HVM ROMBIOS/VGABIOS/ACPI/VMXAssist image loader.
+ *
+ * A quicky so that we can boot rom images as if they were a Linux kernel.
+ * This code will copy the rom images (ROMBIOS/VGABIOS/VM86) into their
+ * respective spaces and transfer control to VM86 to execute the BIOSes.
+ *
+ * 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 "roms.h"
+#include "../acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */
+
+/* memory map */
+#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
+#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
+#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
+
+/* invoke SVM's paged realmode support */
+#define SVM_VMMCALL_RESET_TO_REALMODE 0x00000001
+
+/*
+ * C runtime start off
+ */
+asm(
+" .text \n"
+" .globl _start \n"
+"_start: \n"
+" cld \n"
+" cli \n"
+" lgdt gdt_desr \n"
+" movl $stack_top, %esp \n"
+" movl %esp, %ebp \n"
+" call main \n"
+" jmp halt \n"
+" \n"
+"gdt_desr: \n"
+" .word gdt_end - gdt - 1 \n"
+" .long gdt \n"
+" \n"
+" .align 8 \n"
+"gdt: \n"
+" .quad 0x0000000000000000 \n"
+" .quad 0x00CF92000000FFFF \n"
+" .quad 0x00CF9A000000FFFF \n"
+"gdt_end: \n"
+" \n"
+"halt: \n"
+" sti \n"
+" jmp . \n"
+" \n"
+" .bss \n"
+" .align 8 \n"
+"stack: \n"
+" .skip 0x4000 \n"
+"stack_top: \n"
+);
+
+extern int get_acpi_enabled(void);
+extern int acpi_madt_update(unsigned char* acpi_start);
+
+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
+cirrus_check(void)
+{
+ outw(0x3C4, 0x9206);
+ return inb(0x3C5) == 0x12;
+}
+
+int
+vmmcall(int edi, int esi, int edx, int ecx, int ebx)
+{
+ int eax;
+
+ __asm__ __volatile__(
+ ".byte 0x0F,0x01,0xD9"
+ : "=a" (eax)
+ : "a"(0x58454E00), /* XEN\0 key */
+ "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi)
+ );
+ return eax;
+}
+
+int
+check_amd(void)
+{
+ char id[12];
+
+ __asm__ __volatile__(
+ "cpuid"
+ : "=b" (*(int *)(&id[0])),
+ "=c" (*(int *)(&id[8])),
+ "=d" (*(int *)(&id[4]))
+ : "a" (0)
+ );
+ return __builtin_memcmp(id, "AuthenticAMD", 12) == 0;
+}
+
+int
+main(void)
+{
+ puts("HVM Loader\n");
+
+ puts("Loading ROMBIOS ...\n");
+ memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
+ if (cirrus_check()) {
+ puts("Loading Cirrus VGABIOS ...\n");
+ memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
+ vgabios_cirrusvga, sizeof(vgabios_cirrusvga));
+ } else {
+ puts("Loading Standard VGABIOS ...\n");
+ memcpy((void *)VGABIOS_PHYSICAL_ADDRESS,
+ vgabios_stdvga, sizeof(vgabios_stdvga));
+ }
+
+ if (get_acpi_enabled() != 0) {
+ puts("Loading ACPI ...\n");
+ acpi_madt_update((unsigned char *) acpi);
+ if (ACPI_PHYSICAL_ADDRESS+sizeof(acpi) <= 0xF0000) {
+ /*
+ * Make sure acpi table does not overlap rombios
+ * currently acpi less than 8K will be OK.
+ */
+ memcpy((void *)ACPI_PHYSICAL_ADDRESS, acpi,
+ sizeof(acpi));
+ }
+ }
+
+ if (check_amd()) {
+ /* AMD implies this is SVM */
+ puts("SVM go ...\n");
+ vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0);
+ } else {
+ puts("Loading VMXAssist ...\n");
+ memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
+ vmxassist, sizeof(vmxassist));
+
+ puts("VMX go ...\n");
+ __asm__ __volatile__(
+ "jmp *%%eax"
+ : : "a" (VMXASSIST_PHYSICAL_ADDRESS), "d" (0)
+ );
+ }
+
+ puts("Failed to invoke ROMBIOS\n");
+ return 0;
+}
+
diff --git a/tools/firmware/hvmloader/mkhex b/tools/firmware/hvmloader/mkhex
new file mode 100644
index 0000000000..7389d70483
--- /dev/null
+++ b/tools/firmware/hvmloader/mkhex
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#
+# mkhex: Generate C embeddable hexdumps
+#
+# 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.
+#
+
+echo "unsigned $1[] = {"
+od -v -t x $2 | sed 's/^[0-9]* /0x/' | sed 's/ /, 0x/g' | sed 's/$/,/'
+echo "};"
+