From 4fc9af53d88c0a2a810704a06cb39a7182982e4e Mon Sep 17 00:00:00 2001 From: aliguori Date: Sat, 8 Nov 2008 16:27:07 +0000 Subject: [PATCH] Use an option rom instead of boot sector for -kernel Generate an option rom instead of using a hijacked boot sector for kernel booting. This just requires adding a small option ROM header and a few more instructions to the boot sector to take over the int19 vector and run our boot code. A disk is no longer needed when using -kernel on x86. Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5650 c046a42c-6fe2-441c-8c8c-71466251a162 --- block.c | 32 --------------------------- block.h | 1 - block_int.h | 3 --- hw/pc.c | 72 ++++++++++++++++++++++++++++++++++++++++++------------------- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/block.c b/block.c index 48229cde7b..0f1734ebca 100644 --- a/block.c +++ b/block.c @@ -527,14 +527,6 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, if (!drv) return -ENOMEDIUM; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(buf, bs->boot_sector_data, 512); - sector_num++; - nb_sectors--; - buf += 512; - if (nb_sectors == 0) - return 0; - } if (drv->bdrv_pread) { int ret, len; len = nb_sectors * 512; @@ -567,9 +559,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, return -ENOMEDIUM; if (bs->read_only) return -EACCES; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); - } if (drv->bdrv_pwrite) { int ret, len; len = nb_sectors * 512; @@ -750,16 +739,6 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) *nb_sectors_ptr = length; } -/* force a given boot sector. */ -void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size) -{ - bs->boot_sector_enabled = 1; - if (size > 512) - size = 512; - memcpy(bs->boot_sector_data, data, size); - memset(bs->boot_sector_data + size, 0, 512 - size); -} - void bdrv_set_geometry_hint(BlockDriverState *bs, int cyls, int heads, int secs) { @@ -1155,14 +1134,6 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, if (!drv) return NULL; - /* XXX: we assume that nb_sectors == 0 is suppored by the async read */ - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(buf, bs->boot_sector_data, 512); - sector_num++; - nb_sectors--; - buf += 512; - } - ret = drv->bdrv_aio_read(bs, sector_num, buf, nb_sectors, cb, opaque); if (ret) { @@ -1185,9 +1156,6 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, return NULL; if (bs->read_only) return NULL; - if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) { - memcpy(bs->boot_sector_data, buf, 512); - } ret = drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque); diff --git a/block.h b/block.h index 72c1c24bb4..12053d9f1e 100644 --- a/block.h +++ b/block.h @@ -79,7 +79,6 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset); int64_t bdrv_getlength(BlockDriverState *bs); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); int bdrv_commit(BlockDriverState *bs); -void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size); /* async block I/O */ typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); diff --git a/block_int.h b/block_int.h index 7f1a514063..e83fd2c077 100644 --- a/block_int.h +++ b/block_int.h @@ -104,9 +104,6 @@ struct BlockDriverState { BlockDriver *drv; /* NULL means no media */ void *opaque; - int boot_sector_enabled; - uint8_t boot_sector_data[512]; - char filename[1024]; char backing_file[1024]; /* if non zero, the image is a diff of this file image */ diff --git a/hw/pc.c b/hw/pc.c index 167d628fca..1486b683a8 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -438,30 +438,45 @@ static void bochs_bios_init(void) /* Generate an initial boot sector which sets state and jump to a specified vector */ -static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) +static void generate_bootsect(uint8_t *option_rom, + uint32_t gpr[8], uint16_t segs[6], uint16_t ip) { - uint8_t bootsect[512], *p; + uint8_t rom[512], *p, *reloc; + uint8_t sum; int i; - int hda; - hda = drive_get_index(IF_IDE, 0, 0); - if (hda == -1) { - fprintf(stderr, "A disk image must be given for 'hda' when booting " - "a Linux kernel\n(if you really don't want it, use /dev/zero)\n"); - exit(1); - } + memset(rom, 0, sizeof(rom)); + + p = rom; + /* Make sure we have an option rom signature */ + *p++ = 0x55; + *p++ = 0xaa; - memset(bootsect, 0, sizeof(bootsect)); + /* ROM size in sectors*/ + *p++ = 1; - /* Copy the MSDOS partition table if possible */ - bdrv_read(drives_table[hda].bdrv, 0, bootsect, 1); + /* Hook int19 */ - /* Make sure we have a partition signature */ - bootsect[510] = 0x55; - bootsect[511] = 0xaa; + *p++ = 0x50; /* push ax */ + *p++ = 0x1e; /* push ds */ + *p++ = 0x31; *p++ = 0xc0; /* xor ax, ax */ + *p++ = 0x8e; *p++ = 0xd8; /* mov ax, ds */ + *p++ = 0xc7; *p++ = 0x06; /* movvw _start,0x64 */ + *p++ = 0x64; *p++ = 0x00; + reloc = p; + *p++ = 0x00; *p++ = 0x00; + + *p++ = 0x8c; *p++ = 0x0e; /* mov cs,0x66 */ + *p++ = 0x66; *p++ = 0x00; + + *p++ = 0x1f; /* pop ds */ + *p++ = 0x58; /* pop ax */ + *p++ = 0xcb; /* lret */ + /* Actual code */ - p = bootsect; + *reloc = (p - rom); + *p++ = 0xfa; /* CLI */ *p++ = 0xfc; /* CLD */ @@ -491,7 +506,13 @@ static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) *p++ = segs[1]; /* CS */ *p++ = segs[1] >> 8; - bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect)); + /* sign rom */ + sum = 0; + for (i = 0; i < (sizeof(rom) - 1); i++) + sum += rom[i]; + rom[sizeof(rom) - 1] = -sum; + + memcpy(option_rom, rom, sizeof(rom)); } static long get_file_size(FILE *f) @@ -508,7 +529,8 @@ static long get_file_size(FILE *f) return size; } -static void load_linux(const char *kernel_filename, +static void load_linux(uint8_t *option_rom, + const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline) { @@ -658,7 +680,7 @@ static void load_linux(const char *kernel_filename, memset(gpr, 0, sizeof gpr); gpr[4] = cmdline_addr-real_addr-16; /* SP (-16 is paranoia) */ - generate_bootsect(gpr, seg, 0); + generate_bootsect(option_rom, gpr, seg, 0); } static void main_cpu_reset(void *opaque) @@ -862,6 +884,15 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, int size, offset; offset = 0; + if (linux_boot) { + option_rom_offset = qemu_ram_alloc(TARGET_PAGE_SIZE); + load_linux(phys_ram_base + option_rom_offset, + kernel_filename, initrd_filename, kernel_cmdline); + cpu_register_physical_memory(0xd0000, TARGET_PAGE_SIZE, + option_rom_offset | IO_MEM_ROM); + offset = TARGET_PAGE_SIZE; + } + for (i = 0; i < nb_option_roms; i++) { size = get_image_size(option_rom[i]); if (size < 0) { @@ -891,9 +922,6 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, bochs_bios_init(); - if (linux_boot) - load_linux(kernel_filename, initrd_filename, kernel_cmdline); - cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); i8259 = i8259_init(cpu_irq[0]); ferr_irq = i8259[13]; -- 2.11.0