public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] Add extboot to kvm-userspace (v2)
@ 2008-01-03 15:11 Anthony Liguori
       [not found] ` <11993730983872-git-send-email-aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 3+ messages in thread
From: Anthony Liguori @ 2008-01-03 15:11 UTC (permalink / raw)
  To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f; +Cc: Anthony Liguori, Avi Kivity

extboot is an x86 Option ROM that passes through int13 functions to a VMM which
allows a VMM to expose an arbitrary block device as the primary BIOS disk.  It
can be used to boot SCSI or paravirtual devices.

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/extboot/Makefile b/extboot/Makefile
new file mode 100644
index 0000000..1ea71a7
--- /dev/null
+++ b/extboot/Makefile
@@ -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 *~
diff --git a/extboot/STATUS b/extboot/STATUS
new file mode 100644
index 0000000..687c6d6
--- /dev/null
+++ b/extboot/STATUS
@@ -0,0 +1,6 @@
+Working
+-------
+
+Ubuntu Server 7.04 (i386)
+Windows 2000 Professional (i386)
+Windows XP SP2 (i386)
diff --git a/extboot/extboot.S b/extboot/extboot.S
new file mode 100644
index 0000000..7b6e9b2
--- /dev/null
+++ b/extboot/extboot.S
@@ -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-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+ */
+
+.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 --git a/extboot/signrom.c b/extboot/signrom.c
new file mode 100644
index 0000000..fe8d677
--- /dev/null
+++ b/extboot/signrom.c
@@ -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-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+ */
+
+#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;
+}

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] Add QEMU support for extboot (v2)
       [not found] ` <11993730983872-git-send-email-aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2008-01-03 15:11   ` Anthony Liguori
       [not found]     ` <11993731003389-git-send-email-aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 3+ messages in thread
From: Anthony Liguori @ 2008-01-03 15:11 UTC (permalink / raw)
  To: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f; +Cc: Anthony Liguori, Avi Kivity

This patch adds support to QEMU for extboot.  It requires that an extboot.bin
binary be copied into the pc-bios directory or else make install will not
function properly.

To use extboot to boot from an arbitrary block device, simply append a
",boot=on" to the block device to boot from.  For instance, to boot from a SCSI
disk, one would use:

 -drive file=/path/to/image.img,if=scsi,boot=on

v2 adds the file extboot.c.  Sorry for the mix-up.

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/qemu/Makefile b/qemu/Makefile
index ce76352..a3c6870 100644
--- a/qemu/Makefile
+++ b/qemu/Makefile
@@ -179,7 +179,7 @@ endif
 	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
@@ -281,6 +281,7 @@ tarbin:
         $(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 )
diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index 0c5ca47..289cd18 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -471,7 +471,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
 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), ia64)
diff --git a/qemu/hw/extboot.c b/qemu/hw/extboot.c
new file mode 100644
index 0000000..8759895
--- /dev/null
+++ b/qemu/hw/extboot.c
@@ -0,0 +1,128 @@
+/*
+ * Extended boot option ROM support.
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+ *
+ * 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, &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);
+}
diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c
index 5a1b7d4..aa9e16e 100644
--- a/qemu/hw/pc.c
+++ b/qemu/hw/pc.c
@@ -43,6 +43,7 @@ extern int kvm_allowed;
 #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
@@ -715,6 +716,37 @@ extern kvm_context_t kvm_context;
 extern int kvm_allowed;
 #endif
 
+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);
+#ifdef USE_KVM
+    if (kvm_allowed)
+	    kvm_cpu_register_physical_memory(0xd0000 + offset,
+                                             size, option_rom_offset |
+                                             IO_MEM_ROM);
+#endif
+    return size;
+}
+
 /* PC hardware initialisation */
 static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
                      const char *boot_device, DisplayState *ds,
@@ -726,7 +758,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
     int ret, linux_boot, i;
     ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
     ram_addr_t above_4g_mem_size = 0;
-    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;
@@ -869,40 +901,13 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
 					 /* | IO_MEM_ROM */);
 #endif
 
+    opt_rom_offset = 0;
+    for (i = 0; i < nb_option_roms; i++)
+	opt_rom_offset += load_option_rom(option_rom[i], opt_rom_offset);
 
-    {
-        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);
-#ifdef USE_KVM
-            if (kvm_allowed)
-                kvm_cpu_register_physical_memory(0xd0000 + offset,
-                                             size, option_rom_offset |
-                                             IO_MEM_ROM);
-#endif
-
-            offset += size;
-        }
+    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 */
@@ -1117,6 +1122,18 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
 	    unit_id++;
 	}
     }
+
+    if (extboot_drive != -1) {
+	DriveInfo *info = &drives_table[extboot_drive];
+	int cyls, heads, secs;
+
+	if (info->type != 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(ram_addr_t ram_size, int vga_ram_size,
diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h
index 5d4c747..7d1832f 100644
--- a/qemu/hw/pc.h
+++ b/qemu/hw/pc.h
@@ -151,4 +151,8 @@ void virtio_net_poll(void);
 void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
 		      BlockDriverState *bs);
 
+/* extboot.c */
+
+void extboot_init(BlockDriverState *bs, int cmd);
+
 #endif
diff --git a/qemu/sysemu.h b/qemu/sysemu.h
index b9f4b43..a72a4d6 100644
--- a/qemu/sysemu.h
+++ b/qemu/sysemu.h
@@ -148,6 +148,7 @@ typedef struct DriveInfo {
 
 int nb_drives;
 DriveInfo drives_table[MAX_DRIVES+1];
+int extboot_drive;
 
 extern int drive_get_index(BlockInterfaceType type, int bus, int unit);
 extern int drive_get_max_bus(BlockInterfaceType type);
diff --git a/qemu/vl.c b/qemu/vl.c
index c47b294..39b2e24 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -177,6 +177,7 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
    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;
@@ -4930,7 +4931,7 @@ static int drive_init(const char *str, int snapshot, QEMUMachine *machine)
     int bdrv_flags;
     char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",
                        "secs", "trans", "media", "snapshot", "file",
-                       "cache", NULL };
+                       "cache", "boot", NULL };
 
     if (check_params(buf, sizeof(buf), params, str) < 0) {
          fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n",
@@ -5101,6 +5102,19 @@ static int drive_init(const char *str, int snapshot, QEMUMachine *machine)
         }
     }
 
+    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 */
@@ -7895,8 +7909,8 @@ static void help(int exitcode)
            "-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]"
-           "       [,cache=on|off]\n"
+           "       [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]\n"
+           "       [,cache=on|off][,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"

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 2/2] Add QEMU support for extboot (v2)
       [not found]     ` <11993731003389-git-send-email-aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2008-01-03 15:32       ` Avi Kivity
  0 siblings, 0 replies; 3+ messages in thread
From: Avi Kivity @ 2008-01-03 15:32 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

Anthony Liguori wrote:
> This patch adds support to QEMU for extboot.  It requires that an extboot.bin
> binary be copied into the pc-bios directory or else make install will not
> function properly.
>
> To use extboot to boot from an arbitrary block device, simply append a
> ",boot=on" to the block device to boot from.  For instance, to boot from a SCSI
> disk, one would use:
>
>  -drive file=/path/to/image.img,if=scsi,boot=on
>
>   

Applied, thanks.

-- 
error compiling committee.c: too many arguments to function


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-01-03 15:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-03 15:11 [PATCH 1/2] Add extboot to kvm-userspace (v2) Anthony Liguori
     [not found] ` <11993730983872-git-send-email-aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-01-03 15:11   ` [PATCH 2/2] Add QEMU support for extboot (v2) Anthony Liguori
     [not found]     ` <11993731003389-git-send-email-aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-01-03 15:32       ` Avi Kivity

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox