diff options
Diffstat (limited to 'tools/firmware/hvmloader')
-rw-r--r-- | tools/firmware/hvmloader/Makefile | 56 | ||||
-rw-r--r-- | tools/firmware/hvmloader/acpi_madt.c | 190 | ||||
-rw-r--r-- | tools/firmware/hvmloader/hvmloader.c | 211 | ||||
-rw-r--r-- | tools/firmware/hvmloader/mkhex | 26 |
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 "};" + |