mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
that they don't conflict with the hypercall calling convention. Signed-off-by: Steven Smith <ssmith@xensource.com>
220 lines
4.9 KiB
C
220 lines
4.9 KiB
C
/*
|
|
* 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 */
|
|
#include <xen/hvm/hvm_info_table.h>
|
|
|
|
/* 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 0x80000001
|
|
|
|
/*
|
|
* 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);
|
|
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
|
|
cirrus_check(void)
|
|
{
|
|
outw(0x3C4, 0x9206);
|
|
return inb(0x3C5) == 0x12;
|
|
}
|
|
|
|
int
|
|
vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
|
|
{
|
|
int eax;
|
|
|
|
__asm__ __volatile__(
|
|
".byte 0x0F,0x01,0xD9"
|
|
: "=a" (eax)
|
|
: "a"(function),
|
|
"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)
|
|
{
|
|
struct hvm_info_table *t = get_hvm_info_table();
|
|
|
|
puts("HVM Loader\n");
|
|
|
|
puts("Loading ROMBIOS ...\n");
|
|
memcpy((void *)ROMBIOS_PHYSICAL_ADDRESS, rombios, sizeof(rombios));
|
|
if (t->apic_enabled)
|
|
create_mp_tables();
|
|
|
|
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, 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;
|
|
}
|
|
|