* [PATCH] Extboot support for Xen
@ 2008-01-15 20:02 Anthony Liguori
2008-01-15 21:35 ` Keir Fraser
2008-01-15 21:44 ` Daniel P. Berrange
0 siblings, 2 replies; 4+ messages in thread
From: Anthony Liguori @ 2008-01-15 20:02 UTC (permalink / raw)
To: Xen-devel, Keir Fraser
[-- Attachment #1: Type: text/plain, Size: 1105 bytes --]
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.
The version of QEMU in Xen is a bit old so I couldn't complete the plumbing.
The main problem is that Xen provides no way of exposing SCSI disks
right now
and PV disks aren't actually accessible within QEMU. I'm hoping someone
else
can pick that up though as I'm pretty overcommitted at the moment. The
extboot infrastructure is there though so it's just a matter of
initializing it
with the appropriate BlockDriverState.
Another thing to look at is the choice of physical address. extboot
occupies
1.5k of memory but option roms have to fall on a 2k boundary. I stole
2k from
the space used by etherboot. That should be fine since etherboot and
extboot
should never be loaded at the same time. Of course, someone with more
insight
into hvmloader may know of a better place.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
[-- Attachment #2: extboot.diff --]
[-- Type: text/x-patch, Size: 23067 bytes --]
Subject: [PATCH] Extboot support for Xen
Cc: Keir Fraser <Keir.Fraser@cl.cam.ac.uk>
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.
The version of QEMU in Xen is a bit old so I couldn't complete the plumbing.
The main problem is that Xen provides no way of exposing SCSI disks right now
and PV disks aren't actually accessible within QEMU. I'm hoping someone else
can pick that up though as I'm pretty overcommitted at the moment. The
extboot infrastructure is there though so it's just a matter of initializing it
with the appropriate BlockDriverState.
Another thing to look at is the choice of physical address. extboot occupies
1.5k of memory but option roms have to fall on a 2k boundary. I stole 2k from
the space used by etherboot. That should be fine since etherboot and extboot
should never be loaded at the same time. Of course, someone with more insight
into hvmloader may know of a better place.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
diff -r 533a8e6cebd0 tools/firmware/Makefile
--- a/tools/firmware/Makefile Sat Jan 12 11:26:04 2008 +0000
+++ b/tools/firmware/Makefile Tue Jan 15 13:55:22 2008 -0600
@@ -10,6 +10,7 @@ SUBDIRS += rombios rombios/32bit
SUBDIRS += rombios rombios/32bit
SUBDIRS += vgabios
SUBDIRS += vmxassist
+SUBDIRS += extboot
SUBDIRS += hvmloader
.PHONY: all
diff -r 533a8e6cebd0 tools/firmware/extboot/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/extboot/Makefile Tue Jan 15 13:55:22 2008 -0600
@@ -0,0 +1,41 @@
+OBJCOPY=objcopy
+
+# from kernel sources - scripts/Kbuild.include
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" is can be used as temporary file and
+# is automatically cleaned up.
+try-run = $(shell set -e; \
+ TMP="$(TMPOUT).$$$$.tmp"; \
+ if ($(1)) >/dev/null 2>&1; \
+ then echo "$(2)"; \
+ else echo "$(3)"; \
+ fi; \
+ rm -f "$$TMP")
+
+# cc-option-yn
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+ $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+
+CFLAGS = -Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin
+ifeq ($(call cc-option-yn,-fno-stack-protector),y)
+CFLAGS += -fno-stack-protector
+endif
+
+all: extboot.bin
+
+%.o: %.S
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+extboot.img: extboot.o
+ $(LD) --oformat binary -Ttext 0 -o $@ $<
+
+extboot.bin: extboot.img signrom
+ ./signrom extboot.img extboot.bin
+
+signrom: signrom.c
+ $(CC) -o $@ -g -Wall $^
+
+clean:
+ $(RM) *.o *.img *.bin signrom *~
diff -r 533a8e6cebd0 tools/firmware/extboot/STATUS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/extboot/STATUS Tue Jan 15 13:55:22 2008 -0600
@@ -0,0 +1,6 @@
+Working
+-------
+
+Ubuntu Server 7.04 (i386)
+Windows 2000 Professional (i386)
+Windows XP SP2 (i386)
diff -r 533a8e6cebd0 tools/firmware/extboot/extboot.S
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/extboot/extboot.S Tue Jan 15 13:55:22 2008 -0600
@@ -0,0 +1,742 @@
+/*
+ * 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 out 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
+ je 1f
+ cmp $2, %al
+ je 2f
+ jmp 3f
+
+1: /* hook int13: intb(0x404) == 1 */
+ /* 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)
+ jmp 3f
+
+2: /* linux boot: intb(0x404) == 2 */
+ cli
+ cld
+ mov $0x9000, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ mov $0x8ffe, %sp
+ ljmp $0x9000 + 0x20, $0
+
+3: /* fall through: inb(0x404) == 0 */
+ 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
+#if 0
+ /* this function is seriously borked */
+1:
+ push %ax
+ push %bp
+ push %cx
+ push %dx
+
+ allocbpa $8
+
+ movw $0, 0(%bp) /* read c,h,s */
+ push %bp
+ call send_command
+ add $2, %sp
+
+ /* check the size of the passed in data */
+ cmpw $26, 0(%si)
+ mov 0(%si), %ax
+ dump %ax
+ jle 0b
+
+ /* set flags to 2 */
+ movw $2, 2(%si)
+
+ /* cylinders */
+ mov 2(%bp), %ax
+ mov %ax, 4(%si)
+ xor %ax, %ax
+ mov %ax, 6(%si)
+
+ /* heads */
+ mov 4(%bp), %ax
+ mov %ax, 8(%si)
+ xor %ax, %ax
+ mov %ax, 10(%si)
+
+ /* sectors */
+ mov 6(%bp), %ax
+ mov %ax, 12(%si)
+ xor %ax, %ax
+ mov %ax, 14(%si)
+
+ /* calculate total sectors */
+
+ /* cx:dx = cylinders */
+ mov 2(%bp), %dx
+ xor %cx, %cx
+
+ /* *= heads */
+ push 4(%bp)
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ /* *= sectors */
+ push 6(%bp)
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ /* total number of sectors */
+ mov %dx, 16(%si)
+ mov %cx, 18(%si)
+ xor %ax, %ax
+ mov %ax, 20(%si)
+ mov %ax, 22(%si)
+
+ /* number of bytes per sector */
+ movw $512, 24(%si)
+
+ /* optional segmention:offset to EDD config */
+ cmpw $30, 0(%si)
+ jl 1f
+
+ movw $0xFFFF, 26(%si)
+ movw $0xFFFF, 28(%si)
+
+1:
+ freebpa
+
+ pop %dx
+ pop %cx
+ pop %bp
+ pop %ax
+
+ mov $0, %ah
+ clc
+ ret
+#endif
+
+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:
diff -r 533a8e6cebd0 tools/firmware/extboot/signrom.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/firmware/extboot/signrom.c Tue Jan 15 13:55:22 2008 -0600
@@ -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;
+}
diff -r 533a8e6cebd0 tools/firmware/hvmloader/Makefile
--- a/tools/firmware/hvmloader/Makefile Sat Jan 12 11:26:04 2008 +0000
+++ b/tools/firmware/hvmloader/Makefile Tue Jan 15 13:55:22 2008 -0600
@@ -55,6 +55,7 @@ roms.h: ../rombios/BIOS-bochs-latest ../
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:
diff -r 533a8e6cebd0 tools/firmware/hvmloader/config.h
--- a/tools/firmware/hvmloader/config.h Sat Jan 12 11:26:04 2008 +0000
+++ b/tools/firmware/hvmloader/config.h Tue Jan 15 13:55:22 2008 -0600
@@ -21,6 +21,9 @@
#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
#define ETHERBOOT_PHYSICAL_ADDRESS 0x000C8000
+/* extboot only needs 1.5k but option roms must be on a 2k boundary */
+/* FIXME: I think etherboot takes up this full space */
+#define EXTBOOT_PHYSICAL_ADDRESS 0x000CF800
#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
#define SMBIOS_PHYSICAL_ADDRESS 0x000E9000
#define SMBIOS_MAXIMUM_SIZE 0x00001000
diff -r 533a8e6cebd0 tools/firmware/hvmloader/hvmloader.c
--- a/tools/firmware/hvmloader/hvmloader.c Sat Jan 12 11:26:04 2008 +0000
+++ b/tools/firmware/hvmloader/hvmloader.c Tue Jan 15 13:55:22 2008 -0600
@@ -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 @@ int main(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");
@@ -396,6 +402,14 @@ int main(void)
memcpy((void *)ETHERBOOT_PHYSICAL_ADDRESS,
etherboot, sizeof(etherboot));
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() )
@@ -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,
diff -r 533a8e6cebd0 tools/ioemu/Makefile.target
--- a/tools/ioemu/Makefile.target Sat Jan 12 11:26:04 2008 +0000
+++ b/tools/ioemu/Makefile.target Tue Jan 15 13:55:22 2008 -0600
@@ -403,7 +403,7 @@ VL_OBJS+= ne2000.o rtl8139.o pcnet.o e10
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
diff -r 533a8e6cebd0 tools/ioemu/hw/extboot.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/hw/extboot.c Tue Jan 15 13:55:22 2008 -0600
@@ -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, §ors);
+
+ 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);
+}
diff -r 533a8e6cebd0 tools/ioemu/vl.h
--- a/tools/ioemu/vl.h Sat Jan 12 11:26:04 2008 +0000
+++ b/tools/ioemu/vl.h Tue Jan 15 13:55:22 2008 -0600
@@ -971,6 +971,9 @@ int pmac_ide_init (BlockDriverState **hd
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);
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Extboot support for Xen
2008-01-15 20:02 [PATCH] Extboot support for Xen Anthony Liguori
@ 2008-01-15 21:35 ` Keir Fraser
2008-01-15 21:45 ` Anthony Liguori
2008-01-15 21:44 ` Daniel P. Berrange
1 sibling, 1 reply; 4+ messages in thread
From: Keir Fraser @ 2008-01-15 21:35 UTC (permalink / raw)
To: Anthony Liguori, Xen-devel
On 15/1/08 20:02, "Anthony Liguori" <aliguori@us.ibm.com> wrote:
> The version of QEMU in Xen is a bit old so I couldn't complete the plumbing.
> The main problem is that Xen provides no way of exposing SCSI disks
> right now
> and PV disks aren't actually accessible within QEMU. I'm hoping someone
> else
> can pick that up though as I'm pretty overcommitted at the moment. The
> extboot infrastructure is there though so it's just a matter of
> initializing it
> with the appropriate BlockDriverState.
Could you send the original complete version of your qemu changes, which
applies to more recent qemu versions, to compare against?
Thanks,
Keir
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Extboot support for Xen
2008-01-15 20:02 [PATCH] Extboot support for Xen Anthony Liguori
2008-01-15 21:35 ` Keir Fraser
@ 2008-01-15 21:44 ` Daniel P. Berrange
1 sibling, 0 replies; 4+ messages in thread
From: Daniel P. Berrange @ 2008-01-15 21:44 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Xen-devel
On Tue, Jan 15, 2008 at 02:02:24PM -0600, Anthony Liguori wrote:
> 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.
>
> The version of QEMU in Xen is a bit old so I couldn't complete the plumbing.
> The main problem is that Xen provides no way of exposing SCSI disks
> right now
> and PV disks aren't actually accessible within QEMU. I'm hoping someone
> else
> can pick that up though as I'm pretty overcommitted at the moment. The
> extboot infrastructure is there though so it's just a matter of
> initializing it
> with the appropriate BlockDriverState.
We really badly need the '-drive' patch from QEMU 0.9.1 in Xen. We currently
hack this horribly by passing disks via xenstore, while all other args to
QEMU are regular command line args. If we had the -drive patch another large
chunk of Xen specific patches would go away which has to be a good thing.
If there aren't already plans to rebase to QEMU 0.9.1 in Xen 3.3.x series
I'd recommend back-porting the '-drive' patch to Xen's QEMU 0.9.0
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Extboot support for Xen
2008-01-15 21:35 ` Keir Fraser
@ 2008-01-15 21:45 ` Anthony Liguori
0 siblings, 0 replies; 4+ messages in thread
From: Anthony Liguori @ 2008-01-15 21:45 UTC (permalink / raw)
To: Keir Fraser; +Cc: Xen-devel
[-- Attachment #1: Type: text/plain, Size: 762 bytes --]
Keir Fraser wrote:
> On 15/1/08 20:02, "Anthony Liguori" <aliguori@us.ibm.com> wrote:
>
>
>> The version of QEMU in Xen is a bit old so I couldn't complete the plumbing.
>> The main problem is that Xen provides no way of exposing SCSI disks
>> right now
>> and PV disks aren't actually accessible within QEMU. I'm hoping someone
>> else
>> can pick that up though as I'm pretty overcommitted at the moment. The
>> extboot infrastructure is there though so it's just a matter of
>> initializing it
>> with the appropriate BlockDriverState.
>>
>
> Could you send the original complete version of your qemu changes, which
> applies to more recent qemu versions, to compare against?
>
Attached.
Regards,
Anthony Liguori
> Thanks,
> Keir
>
>
>
[-- Attachment #2: extboot.diff --]
[-- Type: text/x-patch, Size: 24903 bytes --]
Index: qemu/extboot/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/extboot/Makefile 2007-12-07 12:46:20.000000000 -0600
@@ -0,0 +1,21 @@
+OBJCOPY=objcopy
+
+CFLAGS=-Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin \
+ -fno-stack-protector
+
+all: extboot.bin
+
+%.o: %.S
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+extboot.img: extboot.o
+ $(LD) --oformat binary -Ttext 0 -o $@ $<
+
+extboot.bin: extboot.img signrom
+ ./signrom extboot.img extboot.bin
+
+signrom: signrom.c
+ $(CC) -o $@ -g -Wall $^
+
+clean:
+ $(RM) *.o *.img *.bin signrom *~
Index: qemu/extboot/extboot.S
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/extboot/extboot.S 2007-12-07 12:46:20.000000000 -0600
@@ -0,0 +1,742 @@
+/*
+ * 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 out 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
+ je 1f
+ cmp $2, %al
+ je 2f
+ jmp 3f
+
+1: /* hook int13: intb(0x404) == 1 */
+ /* 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)
+ jmp 3f
+
+2: /* linux boot: intb(0x404) == 2 */
+ cli
+ cld
+ mov $0x9000, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ mov $0x8ffe, %sp
+ ljmp $0x9000 + 0x20, $0
+
+3: /* fall through: inb(0x404) == 0 */
+ 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
+#if 0
+ /* this function is seriously borked */
+1:
+ push %ax
+ push %bp
+ push %cx
+ push %dx
+
+ allocbpa $8
+
+ movw $0, 0(%bp) /* read c,h,s */
+ push %bp
+ call send_command
+ add $2, %sp
+
+ /* check the size of the passed in data */
+ cmpw $26, 0(%si)
+ mov 0(%si), %ax
+ dump %ax
+ jle 0b
+
+ /* set flags to 2 */
+ movw $2, 2(%si)
+
+ /* cylinders */
+ mov 2(%bp), %ax
+ mov %ax, 4(%si)
+ xor %ax, %ax
+ mov %ax, 6(%si)
+
+ /* heads */
+ mov 4(%bp), %ax
+ mov %ax, 8(%si)
+ xor %ax, %ax
+ mov %ax, 10(%si)
+
+ /* sectors */
+ mov 6(%bp), %ax
+ mov %ax, 12(%si)
+ xor %ax, %ax
+ mov %ax, 14(%si)
+
+ /* calculate total sectors */
+
+ /* cx:dx = cylinders */
+ mov 2(%bp), %dx
+ xor %cx, %cx
+
+ /* *= heads */
+ push 4(%bp)
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ /* *= sectors */
+ push 6(%bp)
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ /* total number of sectors */
+ mov %dx, 16(%si)
+ mov %cx, 18(%si)
+ xor %ax, %ax
+ mov %ax, 20(%si)
+ mov %ax, 22(%si)
+
+ /* number of bytes per sector */
+ movw $512, 24(%si)
+
+ /* optional segmention:offset to EDD config */
+ cmpw $30, 0(%si)
+ jl 1f
+
+ movw $0xFFFF, 26(%si)
+ movw $0xFFFF, 28(%si)
+
+1:
+ freebpa
+
+ pop %dx
+ pop %cx
+ pop %bp
+ pop %ax
+
+ mov $0, %ah
+ clc
+ ret
+#endif
+
+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:
Index: qemu/extboot/signrom.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/extboot/signrom.c 2007-12-07 12:46:20.000000000 -0600
@@ -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;
+}
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target 2007-12-07 12:46:19.000000000 -0600
+++ qemu/Makefile.target 2007-12-10 10:22:08.000000000 -0600
@@ -443,7 +443,7 @@
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
-VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
+VL_OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o extboot.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
Index: qemu/hw/extboot.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/hw/extboot.c 2007-12-10 10:22:42.000000000 -0600
@@ -0,0 +1,128 @@
+/*
+ * 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 "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "block.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, §ors);
+
+ 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);
+}
Index: qemu/hw/pc.h
===================================================================
--- qemu.orig/hw/pc.h 2007-12-07 12:46:19.000000000 -0600
+++ qemu/hw/pc.h 2007-12-07 12:46:20.000000000 -0600
@@ -151,4 +151,8 @@
void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
BlockDriverState *bs);
+/* extboot.c */
+
+void extboot_init(BlockDriverState *bs, int cmd);
+
#endif
Index: qemu/hw/pc.c
===================================================================
--- qemu.orig/hw/pc.c 2007-12-07 12:46:19.000000000 -0600
+++ qemu/hw/pc.c 2007-12-10 10:22:09.000000000 -0600
@@ -38,6 +38,7 @@
#define BIOS_FILENAME "bios.bin"
#define VGABIOS_FILENAME "vgabios.bin"
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
+#define EXTBOOT_FILENAME "extboot.bin"
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
#define ACPI_DATA_SIZE 0x10000
@@ -696,6 +697,31 @@
nb_ne2k++;
}
+static int load_option_rom(const char *filename, int offset)
+{
+ ram_addr_t option_rom_offset;
+ int size, ret;
+
+ size = get_image_size(filename);
+ if (size < 0) {
+ fprintf(stderr, "Could not load option rom '%s'\n", filename);
+ exit(1);
+ }
+ if (size > (0x10000 - offset))
+ goto option_rom_error;
+ option_rom_offset = qemu_ram_alloc(size);
+ ret = load_image(filename, phys_ram_base + option_rom_offset);
+ if (ret != size) {
+ option_rom_error:
+ fprintf(stderr, "Too many option ROMS\n");
+ exit(1);
+ }
+ size = (size + 4095) & ~4095;
+ cpu_register_physical_memory(0xd0000 + offset,
+ size, option_rom_offset | IO_MEM_ROM);
+ return size;
+}
+
/* PC hardware initialisation */
static void pc_init1(int ram_size, int vga_ram_size,
const char *boot_device, DisplayState *ds,
@@ -706,7 +732,7 @@
char buf[1024];
int ret, linux_boot, i;
ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
- int bios_size, isa_bios_size, vga_bios_size;
+ int bios_size, isa_bios_size, vga_bios_size, opt_rom_offset;
PCIBus *pci_bus;
int piix3_devfn = -1;
CPUState *env;
@@ -804,32 +830,13 @@
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
- {
- ram_addr_t option_rom_offset;
- int size, offset;
-
- offset = 0;
- for (i = 0; i < nb_option_roms; i++) {
- size = get_image_size(option_rom[i]);
- if (size < 0) {
- fprintf(stderr, "Could not load option rom '%s'\n",
- option_rom[i]);
- exit(1);
- }
- if (size > (0x10000 - offset))
- goto option_rom_error;
- option_rom_offset = qemu_ram_alloc(size);
- ret = load_image(option_rom[i], phys_ram_base + option_rom_offset);
- if (ret != size) {
- option_rom_error:
- fprintf(stderr, "Too many option ROMS\n");
- exit(1);
- }
- size = (size + 4095) & ~4095;
- cpu_register_physical_memory(0xd0000 + offset,
- size, option_rom_offset | IO_MEM_ROM);
- offset += size;
- }
+ opt_rom_offset = 0;
+ for (i = 0; i < nb_option_roms; i++)
+ opt_rom_offset += load_option_rom(option_rom[i], opt_rom_offset);
+
+ if (extboot_drive != -1) {
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, EXTBOOT_FILENAME);
+ opt_rom_offset += load_option_rom(buf, opt_rom_offset);
}
/* map all the bios at the top of memory */
@@ -1020,6 +1027,18 @@
unit_id++;
}
}
+
+ if (extboot_drive != -1) {
+ DriveInfo *info = &drives_table[extboot_drive];
+ int cyls, heads, secs;
+
+ if (info->interface != IF_IDE) {
+ bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs);
+ bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs);
+ }
+
+ extboot_init(info->bdrv, 1);
+ }
}
static void pc_init_pci(int ram_size, int vga_ram_size,
Index: qemu/sysemu.h
===================================================================
--- qemu.orig/sysemu.h 2007-12-07 12:46:19.000000000 -0600
+++ qemu/sysemu.h 2007-12-10 10:22:07.000000000 -0600
@@ -133,6 +133,7 @@
int nb_drives;
DriveInfo drives_table[MAX_DRIVES+1];
+int extboot_drive;
extern int drive_get_index(BlockInterfaceType interface, int bus, int unit);
extern int drive_get_max_bus(BlockInterfaceType interface);
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c 2007-12-07 12:46:19.000000000 -0600
+++ qemu/vl.c 2007-12-10 10:22:07.000000000 -0600
@@ -167,6 +167,7 @@
to store the VM snapshots */
DriveInfo drives_table[MAX_DRIVES+1];
int nb_drives;
+int extboot_drive = -1;
/* point to the block driver where the snapshots are managed */
BlockDriverState *bs_snapshots;
int vga_ram_size;
@@ -4852,7 +4853,8 @@
int max_devs;
int index;
char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",
- "secs", "trans", "media", "snapshot", "file", NULL };
+ "secs", "trans", "media", "snapshot", "file", "boot",
+ NULL };
if (check_params(buf, sizeof(buf), params, str) < 0) {
fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n",
@@ -5008,6 +5010,19 @@
}
}
+ if (get_param_value(buf, sizeof(buf), "boot", str)) {
+ if (!strcmp(buf, "on")) {
+ if (extboot_drive != -1) {
+ fprintf(stderr, "qemu: two bootable drives specified\n");
+ return -1;
+ }
+ extboot_drive = nb_drives;
+ } else if (strcmp(buf, "off")) {
+ fprintf(stderr, "qemu: '%s' invalid boot option\n", str);
+ return -1;
+ }
+ }
+
get_param_value(file, sizeof(file), "file", str);
/* compute bus and unit according index */
@@ -7443,7 +7458,8 @@
"-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n"
"-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n"
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i]\n"
- " [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]\n"
+ " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
+ " [,boot=on|off]\n"
" use 'file' as a drive image\n"
"-mtdblock file use 'file' as on-board Flash memory image\n"
"-sd file use 'file' as SecureDigital card image\n"
Index: qemu/Makefile
===================================================================
--- qemu.orig/Makefile 2007-12-06 13:40:38.000000000 -0600
+++ qemu/Makefile 2007-12-10 10:22:10.000000000 -0600
@@ -171,7 +171,7 @@
mkdir -p "$(DESTDIR)$(datadir)"
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x openbios-sparc32 pxe-ne2k_pci.bin \
- pxe-rtl8139.bin pxe-pcnet.bin; do \
+ pxe-rtl8139.bin pxe-pcnet.bin extboot.bin; do \
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
done
ifndef CONFIG_WIN32
@@ -271,6 +271,7 @@
$(datadir)/pxe-ne2k_pci.bin \
$(datadir)/pxe-rtl8139.bin \
$(datadir)/pxe-pcnet.bin \
+ $(datadir)/extboot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-01-15 21:45 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-15 20:02 [PATCH] Extboot support for Xen Anthony Liguori
2008-01-15 21:35 ` Keir Fraser
2008-01-15 21:45 ` Anthony Liguori
2008-01-15 21:44 ` Daniel P. Berrange
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.