hvm: Extboot support for Xen

This patch adds extboot to Xen.  It should be pretty harmless as the
moment because it's never enabled.  extboot allows arbitrary block
devices to be used to boot guests including SCSI and PV disks.  I've
tested it with both Windows and Linux guests in QEMU.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Keir Fraser committed 2008-01-17 16:39:14 +00:00
1 parent bdd22133fc
commit 86f69d44ae
13 files changed
+898 -1

No files matched your search

+1
View File
@@ -10,6 +10,7 @@ SUBDIRS :=
SUBDIRS += rombios rombios/32bit
SUBDIRS += vgabios
SUBDIRS += vmxassist
SUBDIRS += extboot
SUBDIRS += hvmloader
.PHONY: all
+30
View File
@@ -0,0 +1,30 @@
override XEN_TARGET_ARCH = x86_32
XEN_ROOT = ../../..
CFLAGS := -I$(XEN_ROOT)/tools/libxc -I.
include $(XEN_ROOT)/tools/Rules.mk
# Disable PIE/SSP if GCC supports them. They can break us.
CFLAGS += $(call cc-option,$(CC),-nopie,)
CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
CFLAGS += -fno-builtin -O2 -msoft-float
.PHONY: all
all: extboot.bin
%.o: %.S
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
extboot.img: extboot.o
$(LD) $(LDFLAGS_DIRECT) --oformat binary -Ttext 0 -o $@ $<
extboot.bin: extboot.img signrom
./signrom extboot.img extboot.bin
signrom: signrom.c
$(HOSTCC) $(HOSTCFLAGS) -o $@ $^
clean:
$(RM) -f *.o *.img *.bin signrom *~
+6
View File
@@ -0,0 +1,6 @@
Working
-------
Ubuntu Server 7.04 (i386)
Windows 2000 Professional (i386)
Windows XP SP2 (i386)
+633
View File
@@ -0,0 +1,633 @@
/*
* Extended Boot Option ROM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corporation, 2007
* Authors: Anthony Liguori <aliguori@us.ibm.com>
*/
.code16
.text
.global _start
_start:
.short 0xaa55
.byte (_end - _start) / 512
push %ax
push %bx
push %cx
push %dx
push %ds
/* setup ds so we can access the IVT */
xor %ax, %ax
mov %ax, %ds
/* save old int 19 at int 2b */
mov $(0x19 * 4), %bx
mov 0(%bx), %ax
mov 2(%bx), %cx
mov $(0x2b * 4), %bx
mov %ax, 0(%bx)
mov %cx, 2(%bx)
/* install our int 19 handler */
mov $(0x19 * 4), %bx
mov $int19_handler, %ax
mov %ax, 0(%bx)
mov %cs, 2(%bx)
pop %ds
pop %dx
pop %cx
pop %bx
pop %ax
lret
int19_handler:
push %ax
push %bx
push %cx
push %dx
push %ds
movw $0x404, %dx
inb %dx, %al
cmp $1, %al
jne 1f
/* hook int13 */
/* setup ds to access IVT */
xor %ax, %ax
mov %ax, %ds
/* save old int 13 to int 2c */
mov $(0x13 * 4), %bx
mov 0(%bx), %ax
mov 2(%bx), %cx
mov $(0x2c * 4), %bx
mov %ax, 0(%bx)
mov %cx, 2(%bx)
/* install our int 13 handler */
mov $(0x13 * 4), %bx
mov $int13_handler, %ax
mov %ax, 0(%bx)
mov %cs, 2(%bx)
1: pop %ds
pop %dx
pop %cx
pop %bx
pop %ax
int $0x2b
#define FLAGS_CF 0x01
.macro clc
push %ax
pushf
pop %ax
and $(~FLAGS_CF), %ax
push %ax
popf
pop %ax
.endm
.macro stc
push %ax
pushf
pop %ax
or $(FLAGS_CF), %ax
push %ax
popf
pop %ax
.endm
/* we clobber %bx */
.macro alloca size
push %ds
push %bp
mov %sp, %bp /* remember the current stack position */
mov %ss, %bx
mov %bx, %ds
sub \size, %sp
and $(~0x0F), %sp
mov %sp, %bx
push %bp
mov 0(%bp), %bp
.endm
/* we clobber %bp */
.macro allocbpa size
mov %sp, %bp /* remember the current stack position */
sub \size, %sp
and $(~0x0F), %sp
push %bp
mov %sp, %bp
add $2, %bp
.endm
.macro freea
pop %sp
add $2, %sp
pop %ds
.endm
.macro freebpa
pop %sp
.endm
.macro dump reg
push %ax
push %dx
mov \reg, %ax
mov $0x406, %dx
outw %ax, %dx
pop %dx
pop %ax
.endm
.macro callout value
push %bp
push %bx
mov %sp, %bp
alloca $16
push %ax
push %dx
mov %ax, 0(%bx) /* ax */
mov 0(%bp), %ax /* bx */
mov %ax, 2(%bx)
mov %cx, 4(%bx) /* cx */
mov %dx, 6(%bx) /* dx */
mov %si, 8(%bx) /* si */
mov %ds, 10(%bx) /* ds */
mov %es, 12(%bx) /* ds */
movw \value, 14(%bx) /* value */
mov %bx, %ax
shr $4, %ax
mov %ds, %dx
add %dx, %ax
mov $0x407, %dx
outw %ax, %dx
pop %dx
pop %ax
freea
pop %bx
pop %bp
.endm
send_command:
push %bp
mov %sp, %bp
push %ax
push %bx
push %dx
mov 4(%bp), %ax
shr $4, %ax
and $0x0FFF, %ax
mov %ss, %bx
add %bx, %ax
mov $0x405, %dx
outw %ax, %dx
pop %dx
pop %bx
pop %ax
pop %bp
push %ax
mov 2(%bx), %ax
pop %ax
ret
add32: /* lo, hi, lo, hi */
push %bp
mov %sp, %bp
movw 4(%bp), %cx /* hi */
movw 6(%bp), %dx /* lo */
add 10(%bp), %dx
jnc 1f
add $1, %cx
1: add 8(%bp), %cx
pop %bp
ret
mul32: /* lo, hi, lo, hi */
/* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
push %bp
mov %sp, %bp
push %ax
push %bx
xor %cx, %cx
xor %dx, %dx
/* for (i = 0; i < 16;) */
xor %bx, %bx
0:
cmp $16, %bx
jge 2f
mov 6(%bp), %ax
and $1, %ax
cmp $1, %ax
jne 1f
push 10(%bp)
push 8(%bp)
push %dx
push %cx
call add32
add $8, %sp
1:
shlw $1, 8(%bp)
movw 10(%bp), %ax
and $0x8000, %ax
cmp $0x8000, %ax
jne 1f
orw $1, 8(%bp)
1:
shlw $1, 10(%bp)
shrw $1, 6(%bp)
/* i++) { */
add $1, %bx
jmp 0b
2:
pop %bx
pop %ax
pop %bp
ret
disk_reset:
movb $0, %ah
clc
ret
/* this really should be a function, not a macro but i'm lazy */
.macro read_write_disk_sectors cmd
push %ax
push %bx
push %cx
push %dx
push %si
push %bp
sub $10, %sp
mov %sp, %bp
/* save nb_sectors */
mov %al, 6(%bp)
movb $0, 7(%bp)
/* save buffer */
mov %bx, 8(%bp)
/* cylinders */
xor %ax, %ax
mov %cl, %al
shl $2, %ax
and $0x300, %ax
mov %ch, %al
mov %ax, 0(%bp)
/* heads */
xor %ax, %ax
mov %dh, %al
mov %ax, 2(%bp)
/* sectors - 1 */
xor %ax, %ax
mov %cl, %al
and $0x3F, %al
sub $1, %ax
mov %ax, 4(%bp)
alloca $8
movw $0, 0(%bx) /* read c,h,s */
push %bx
call send_command
add $2, %sp
mov 6(%bx), %ax /* total_sectors */
mov 2(%bp), %si /* *= heads */
mul %si
add 4(%bp), %ax /* += sectors - 1 */
push 4(%bx) /* total_heads */
push $0
push 6(%bx) /* total_sectors */
push $0
call mul32
add $8, %sp
push 0(%bp) /* cylinders */
push $0
push %dx
push %cx
call mul32
add $8, %sp
add %ax, %dx
jnc 1f
add $1, %cx
1:
freea
alloca $16
movw \cmd, 0(%bx) /* read */
movw 6(%bp), %ax /* nb_sectors */
movw %ax, 2(%bx)
movw %es, 4(%bx) /* segment */
movw 8(%bp), %ax /* offset */
mov %ax, 6(%bx)
movw %dx, 8(%bx) /* sector */
movw %cx, 10(%bx)
movw $0, 12(%bx)
movw $0, 14(%bx)
push %bx
call send_command
add $2, %sp
freea
add $10, %sp
pop %bp
pop %si
pop %dx
pop %cx
pop %bx
pop %ax
mov $0, %ah
clc
ret
.endm
read_disk_sectors:
read_write_disk_sectors $0x01
write_disk_sectors:
read_write_disk_sectors $0x02
read_disk_drive_parameters:
push %bx
/* allocate memory for packet, pointer gets returned in bx */
alloca $8
/* issue command */
movw $0, 0(%bx) /* cmd = 0, read c,h,s */
push %bx
call send_command
add $2, %sp
/* normalize sector value */
movb 6(%bx), %cl
andb $0x3F, %cl
movb %cl, 6(%bx)
/* normalize cylinders */
subw $2, 2(%bx)
/* normalize heads */
subw $1, 4(%bx)
/* return code */
mov $0, %ah
/* cylinders */
movb 2(%bx), %ch
movb 3(%bx), %cl
shlb $6, %cl
andb $0xC0, %cl
/* sectors */
orb 6(%bx), %cl
/* heads */
movb 4(%bx), %dh
/* drives */
movb $1, %dl
/* status */
mov $0, %ah
freea
pop %bx
/* do this last since it's the most sensitive */
clc
ret
alternate_disk_reset:
movb $0, %ah
clc
ret
read_disk_drive_size:
push %bx
alloca $8
movw $0, 0(%bx) /* cmd = 0, read c,h,s */
push %bx
call send_command
add $2, %sp
/* cylinders - 1 to cx:dx */
mov 2(%bx), %dx
xor %cx, %cx
sub $1, %dx
/* heads */
push 4(%bx)
push $0
push %dx
push %cx
call mul32
add $8, %sp
/* sectors */
push 6(%bx)
push $0
push %dx
push %cx
call mul32
add $8, %sp
/* status */
mov $3, %ah
freea
pop %bx
clc
ret
check_if_extensions_present:
mov $0x30, %ah
mov $0xAA55, %bx
mov $0x07, %cx
clc
ret
.macro extended_read_write_sectors cmd
cmpb $10, 0(%si)
jg 1f
mov $1, %ah
stc
ret
1:
push %ax
push %bp
allocbpa $16
movw \cmd, 0(%bp) /* read */
movw 2(%si), %ax /* nb_sectors */
movw %ax, 2(%bp)
movw 4(%si), %ax /* offset */
movw %ax, 6(%bp)
movw 6(%si), %ax /* segment */
movw %ax, 4(%bp)
movw 8(%si), %ax /* block */
movw %ax, 8(%bp)
movw 10(%si), %ax
movw %ax, 10(%bp)
movw 12(%si), %ax
movw %ax, 12(%bp)
movw 14(%si), %ax
movw %ax, 14(%bp)
push %bp
call send_command
add $2, %sp
freebpa
pop %bp
pop %ax
mov $0, %ah
clc
ret
.endm
extended_read_sectors:
extended_read_write_sectors $0x01
extended_write_sectors:
extended_read_write_sectors $0x02
get_extended_drive_parameters:
mov $1, %ah
stc
ret
terminate_disk_emulation:
mov $1, %ah
stc
ret
int13_handler:
cmp $0x80, %dl
je 1f
int $0x2c
iret
1:
cmp $0x0, %ah
jne 1f
call disk_reset
iret
1:
cmp $0x2, %ah
jne 1f
call read_disk_sectors
iret
1:
cmp $0x8, %ah
jne 1f
call read_disk_drive_parameters
iret
1:
cmp $0x15, %ah
jne 1f
call read_disk_drive_size
iret
1:
cmp $0x41, %ah
jne 1f
call check_if_extensions_present
iret
1:
cmp $0x42, %ah
jne 1f
call extended_read_sectors
iret
1:
cmp $0x48, %ah
jne 1f
call get_extended_drive_parameters
iret
1:
cmp $0x4b, %ah
jne 1f
call terminate_disk_emulation
iret
1:
cmp $0x0d, %ah
jne 1f
call alternate_disk_reset
iret
1:
cmp $0x03, %ah
jne 1f
call write_disk_sectors
iret
1:
cmp $0x43, %ah
jne 1f
call extended_write_sectors
iret
1:
int $0x18 /* boot failed */
iret
.align 512, 0
_end:
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+79
View File
@@ -0,0 +1,79 @@
/*
* Extended Boot Option ROM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corporation, 2007
* Authors: Anthony Liguori <aliguori@us.ibm.com>
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *fin, *fout;
char buffer[512], oldbuffer[512];
int i, size, lag = 0;
uint8_t sum = 0;
if (argc != 3) {
printf("Usage: %s ROM OUTPUT\n", argv[0]);
return 1;
}
fin = fopen(argv[1], "rb");
fout = fopen(argv[2], "wb");
if (fin == NULL || fout == NULL) {
fprintf(stderr, "Could not open input/output files\n");
return 1;
}
do {
size = fread(buffer, 512, 1, fin);
if (size == 1) {
for (i = 0; i < 512; i++)
sum += buffer[i];
if (lag) {
if (fwrite(oldbuffer, 512, 1, fout) != 1) {
fprintf(stderr, "Write failed\n");
return 1;
}
}
lag = 1;
memcpy(oldbuffer, buffer, 512);
}
} while (size == 1);
if (size != 0) {
fprintf(stderr, "Failed to read from input file\n");
return 1;
}
oldbuffer[511] = -sum;
if (fwrite(oldbuffer, 512, 1, fout) != 1) {
fprintf(stderr, "Failed to write to output file\n");
return 1;
}
fclose(fin);
fclose(fout);
return 0;
}
+1
View File
@@ -55,6 +55,7 @@ roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabi
sh ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
sh ./mkhex vmxassist ../vmxassist/vmxassist.bin >> roms.h
cat ../etherboot/eb-rtl8139.zrom.h >> roms.h
sh ./mkhex extboot ../extboot/extboot.bin >> roms.h
.PHONY: clean
clean:
+1
View File
@@ -22,6 +22,7 @@
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
#define ETHERBOOT_PHYSICAL_ADDRESS 0x000C8000
#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
#define EXTBOOT_PHYSICAL_ADDRESS 0x000DF800
#define SMBIOS_PHYSICAL_ADDRESS 0x000E9000
#define SMBIOS_MAXIMUM_SIZE 0x00001000
#define ACPI_PHYSICAL_ADDRESS 0x000EA000
+18
View File
@@ -316,6 +316,11 @@ static int must_load_nic(void)
return ((boot_order & 0xf0) == 0x40);
}
static int must_load_extboot(void)
{
return (inb(0x404) == 1);
}
/* Replace possibly erroneous memory-size CMOS fields with correct values. */
static void cmos_write_memory_size(void)
{
@@ -354,6 +359,7 @@ static void cmos_write_memory_size(void)
int main(void)
{
int acpi_sz = 0, vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
int extboot_sz = 0;
printf("HVM Loader\n");
@@ -398,6 +404,14 @@ int main(void)
etherboot_sz = sizeof(etherboot);
}
if ( must_load_extboot() )
{
printf("Loading EXTBOOT ...\n");
memcpy((void *)EXTBOOT_PHYSICAL_ADDRESS,
extboot, sizeof(extboot));
extboot_sz = sizeof(extboot);
}
if ( get_acpi_enabled() )
{
printf("Loading ACPI ...\n");
@@ -416,6 +430,10 @@ int main(void)
printf(" %05x-%05x: Etherboot ROM\n",
ETHERBOOT_PHYSICAL_ADDRESS,
ETHERBOOT_PHYSICAL_ADDRESS + etherboot_sz - 1);
if ( extboot_sz )
printf(" %05x-%05x: Extboot ROM\n",
EXTBOOT_PHYSICAL_ADDRESS,
EXTBOOT_PHYSICAL_ADDRESS + extboot_sz - 1);
if ( use_vmxassist() )
printf(" %05x-%05x: VMXAssist\n",
VMXASSIST_PHYSICAL_ADDRESS,
+1 -1
View File
@@ -403,7 +403,7 @@ VL_OBJS+= ne2000.o rtl8139.o pcnet.o e100.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) extboot.o
ifeq ($(ARCH),ia64)
VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
else
+125
View File
@@ -0,0 +1,125 @@
/*
* Extended boot option ROM support.
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "vl.h"
/* Extended Boot ROM suport */
union extboot_cmd
{
uint16_t type;
struct {
uint16_t type;
uint16_t cylinders;
uint16_t heads;
uint16_t sectors;
} query_geometry;
struct {
uint16_t type;
uint16_t nb_sectors;
uint16_t segment;
uint16_t offset;
uint64_t sector;
} xfer;
};
static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
{
bdrv_get_geometry_hint(bs, c, h, s);
if (*c <= 1024) {
*c >>= 0;
*h <<= 0;
} else if (*c <= 2048) {
*c >>= 1;
*h <<= 1;
} else if (*c <= 4096) {
*c >>= 2;
*h <<= 2;
} else if (*c <= 8192) {
*c >>= 3;
*h <<= 3;
} else {
*c >>= 4;
*h <<= 4;
}
/* what is the correct algorithm for this?? */
if (*h == 256) {
*h = 255;
*c = *c + 1;
}
}
static uint32_t extboot_read(void *opaque, uint32_t addr)
{
int *pcmd = opaque;
return *pcmd;
}
static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
{
union extboot_cmd *cmd = (void *)(phys_ram_base + ((value & 0xFFFF) << 4));
BlockDriverState *bs = opaque;
int cylinders, heads, sectors, err;
get_translated_chs(bs, &cylinders, &heads, &sectors);
if (cmd->type == 0x01 || cmd->type == 0x02) {
target_ulong pa = cmd->xfer.segment * 16 + cmd->xfer.segment;
/* possible buffer overflow */
if ((pa + cmd->xfer.nb_sectors * 512) > phys_ram_size)
return;
}
switch (cmd->type) {
case 0x00:
cmd->query_geometry.cylinders = cylinders;
cmd->query_geometry.heads = heads;
cmd->query_geometry.sectors = sectors;
cpu_physical_memory_set_dirty((value & 0xFFFF) << 4);
break;
case 0x01:
err = bdrv_read(bs, cmd->xfer.sector, phys_ram_base +
cmd->xfer.segment * 16 + cmd->xfer.offset,
cmd->xfer.nb_sectors);
if (err)
printf("Read failed\n");
break;
case 0x02:
err = bdrv_write(bs, cmd->xfer.sector, phys_ram_base +
cmd->xfer.segment * 16 + cmd->xfer.offset,
cmd->xfer.nb_sectors);
if (err)
printf("Write failed\n");
cpu_physical_memory_set_dirty(cmd->xfer.segment * 16 + cmd->xfer.offset);
break;
}
}
void extboot_init(BlockDriverState *bs, int cmd)
{
int *pcmd;
pcmd = qemu_mallocz(sizeof(int));
if (!pcmd) {
fprintf(stderr, "Error allocating memory\n");
exit(1);
}
*pcmd = cmd;
register_ioport_read(0x404, 1, 1, extboot_read, pcmd);
register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
}
+3
View File
@@ -971,6 +971,9 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn);
int pmac_ide_init (BlockDriverState **hd_table,
SetIRQFunc *set_irq, void *irq_opaque, int irq);
/* extboot.c */
void extboot_init(BlockDriverState *bs, int cmd);
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.