Index: qemu/extboot/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu/extboot/Makefile 2007-12-05 09:43:11.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-05 09:43:11.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 + */ + +.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-05 09:43:11.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 + */ + +#include +#include +#include + +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-05 09:43:27.000000000 -0600 +++ qemu/Makefile.target 2007-12-05 09:43:34.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-05 09:45:02.000000000 -0600 @@ -0,0 +1,128 @@ +/* + * Virtio Network Device + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori + * + * 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-05 09:43:27.000000000 -0600 +++ qemu/hw/pc.h 2007-12-05 09:43:34.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-05 09:43:51.000000000 -0600 +++ qemu/hw/pc.c 2007-12-05 10:11:43.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-05 09:43:51.000000000 -0600 +++ qemu/sysemu.h 2007-12-05 09:44:01.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-05 09:43:51.000000000 -0600 +++ qemu/vl.c 2007-12-05 09:44:01.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-05 10:12:45.000000000 -0600 +++ qemu/Makefile 2007-12-05 10:13:04.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 )