From patchwork Thu Nov 12 20:53:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 38291 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BC6A9B7BAD for ; Fri, 13 Nov 2009 08:22:22 +1100 (EST) Received: from localhost ([127.0.0.1]:43639 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N8h7T-0000JD-Jt for incoming@patchwork.ozlabs.org; Thu, 12 Nov 2009 16:22:19 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1N8gfW-0005CV-1M for qemu-devel@nongnu.org; Thu, 12 Nov 2009 15:53:26 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1N8gfP-00057q-E0 for qemu-devel@nongnu.org; Thu, 12 Nov 2009 15:53:24 -0500 Received: from [199.232.76.173] (port=48098 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N8gfP-00057M-2r for qemu-devel@nongnu.org; Thu, 12 Nov 2009 15:53:19 -0500 Received: from cantor2.suse.de ([195.135.220.15]:43661 helo=mx2.suse.de) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1N8gfN-0008Ee-93 for qemu-devel@nongnu.org; Thu, 12 Nov 2009 15:53:17 -0500 Received: from relay1.suse.de (mail2.suse.de [195.135.221.8]) by mx2.suse.de (Postfix) with ESMTP id DB7488672B; Thu, 12 Nov 2009 21:53:15 +0100 (CET) From: Alexander Graf To: qemu-devel@nongnu.org Date: Thu, 12 Nov 2009 21:53:12 +0100 Message-Id: <1258059195-17582-4-git-send-email-agraf@suse.de> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: <1258059195-17582-1-git-send-email-agraf@suse.de> References: <1258059195-17582-1-git-send-email-agraf@suse.de> X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.4-2.6 Cc: Glauber Costa , Juan Quintela , Avi Kivity , Christoph Hellwig Subject: [Qemu-devel] [PATCH 3/6] Convert multiboot to fw_cfg backed data storage X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Right now we load the guest kernel to RAM, fire off the BIOS, hope it doesn't clobber memory and run an option rom that jumps into the kernel. That breaks with SeaBIOS, as that clears memory. So let's read all kernel, module etc. data using the fw_cfg interface when in the int19 handler. This patch implements said mechanism for multiboot. Signed-off-by: Alexander Graf --- v1 -> v2: - rename copy_rom -> rom_copy --- hw/fw_cfg.h | 5 ++- hw/pc.c | 43 ++++++++++++++++------- pc-bios/optionrom/multiboot.S | 77 ++++++++++++++++++++++++++++++++--------- 3 files changed, 94 insertions(+), 31 deletions(-) diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h index 359d45a..1e004b7 100644 --- a/hw/fw_cfg.h +++ b/hw/fw_cfg.h @@ -17,7 +17,10 @@ #define FW_CFG_NUMA 0x0d #define FW_CFG_BOOT_MENU 0x0e #define FW_CFG_MAX_CPUS 0x0f -#define FW_CFG_MAX_ENTRY 0x10 +#define FW_CFG_KERNEL_ENTRY 0x10 +#define FW_CFG_KERNEL_DATA 0x11 +#define FW_CFG_INITRD_DATA 0x12 +#define FW_CFG_MAX_ENTRY 0x13 #define FW_CFG_WRITE_CHANNEL 0x4000 #define FW_CFG_ARCH_LOCAL 0x8000 diff --git a/hw/pc.c b/hw/pc.c index bf4718e..55bd1a4 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -603,6 +603,8 @@ static int load_multiboot(void *fw_cfg, uint32_t mb_mod_end; uint8_t bootinfo[0x500]; uint32_t cmdline = 0x200; + uint8_t *mb_kernel_data; + uint8_t *mb_bootinfo_data; /* Ok, let's see if it is a multiboot image. The header is 12x32bit long, so the latest entry may be 8192 - 48. */ @@ -643,6 +645,12 @@ static int load_multiboot(void *fw_cfg, mh_load_addr = mh_entry_addr = elf_entry; mb_kernel_size = kernel_size; + mb_kernel_data = qemu_malloc(mb_kernel_size); + if (rom_copy(mb_kernel_data, elf_entry, kernel_size) != kernel_size) { + fprintf(stderr, "Error while fetching elf kernel from rom\n"); + exit(1); + } + #ifdef DEBUG_MULTIBOOT fprintf(stderr, "qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n", mb_kernel_size, (size_t)mh_entry_addr); @@ -656,7 +664,6 @@ static int load_multiboot(void *fw_cfg, uint32_t mh_bss_end_addr = ldl_p(header+i+24); #endif uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); - uint8_t *kernel; mh_entry_addr = ldl_p(header+i+28); mb_kernel_size = get_file_size(f) - mb_kernel_text_offset; @@ -676,12 +683,9 @@ static int load_multiboot(void *fw_cfg, mb_kernel_size, mh_load_addr); #endif - kernel = qemu_malloc(mb_kernel_size); + mb_kernel_data = qemu_malloc(mb_kernel_size); fseek(f, mb_kernel_text_offset, SEEK_SET); - fread(kernel, 1, mb_kernel_size, f); - rom_add_blob_fixed(kernel_filename, kernel, mb_kernel_size, - mh_load_addr); - qemu_free(kernel); + fread(mb_kernel_data, 1, mb_kernel_size, f); fclose(f); } @@ -732,9 +736,14 @@ static int load_multiboot(void *fw_cfg, exit(1); } mb_mod_end = mb_mod_start + mb_mod_length; - rom_add_file_fixed(initrd_filename, mb_mod_start); - mb_mod_count++; + + /* append module data at the end of last module */ + mb_kernel_data = qemu_realloc(mb_kernel_data, + mh_load_addr - mb_mod_end); + load_image(initrd_filename, + mb_kernel_data + mb_mod_start - mh_load_addr); + stl_p(bootinfo + mb_mod_info + 0, mb_mod_start); stl_p(bootinfo + mb_mod_info + 4, mb_mod_start + mb_mod_length); stl_p(bootinfo + mb_mod_info + 12, 0x0); /* reserved */ @@ -774,13 +783,21 @@ static int load_multiboot(void *fw_cfg, fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr); #endif + /* save bootinfo off the stack */ + mb_bootinfo_data = qemu_malloc(sizeof(bootinfo)); + memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo)); + /* Pass variables to option rom */ - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_entry_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, mmap_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mb_mod_end - mh_load_addr); + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, mb_kernel_data, + mb_mod_end - mh_load_addr); - rom_add_blob_fixed("multiboot-info", bootinfo, sizeof(bootinfo), - mb_bootinfo); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo)); + fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data, + sizeof(bootinfo)); option_rom[nb_option_roms] = "multiboot.bin"; nb_option_roms++; diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S index e6cbefd..dafac73 100644 --- a/pc-bios/optionrom/multiboot.S +++ b/pc-bios/optionrom/multiboot.S @@ -26,6 +26,14 @@ #define MULTIBOOT_MAGIC 0x2badb002 +#define GS_PROT_JUMP 0 +#define GS_GDT_DESC 6 + +/* Break the translation block flow so -d cpu shows us values */ +#define DEBUG_HERE \ + jmp 1f; \ + 1: + /* Read a variable from the fw_cfg device. Clobbers: %edx Out: %eax */ @@ -44,12 +52,31 @@ bswap %eax .endm +/* + * Read a blob from the fw_cfg device. + * Requires _ADDR, _SIZE and _DATA values for the parameter. + * + * Clobbers: %eax, %edx, %es, %ecx, %edi + */ +#define read_fw_blob(var) \ + read_fw var ## _ADDR; \ + mov %eax, %edi; \ + read_fw var ## _SIZE; \ + mov %eax, %ecx; \ + mov $var ## _DATA, %ax; \ + mov $BIOS_CFG_IOPORT_CFG, %edx; \ + outw %ax, (%dx); \ + mov $BIOS_CFG_IOPORT_DATA, %dx; \ + cld; \ + DEBUG_HERE \ + rep insb (%dx), %es:(%edi); + .code16 .text .global _start _start: .short 0xaa55 - .byte 1 /* (_end - _start) / 512 */ + .byte (_end - _start) / 512 push %eax push %ds @@ -57,10 +84,6 @@ _start: xor %ax, %ax mov %ax, %ds - /* save old int 19 */ - mov (0x19*4), %eax - mov %eax, %cs:old_int19 - /* install our int 19 handler */ movw $int19_handler, (0x19*4) mov %cs, (0x19*4+2) @@ -84,15 +107,34 @@ run_multiboot: mov %cs, %eax shl $0x4, %eax - /* fix the gdt descriptor to be PC relative */ - mov (gdt_desc+2), %ebx - add %eax, %ebx - mov %ebx, (gdt_desc+2) + /* set up a long jump descriptor that is PC relative */ - /* fix the prot mode indirect jump to be PC relative */ + /* move stack memory to %gs */ + mov %ss, %ecx + shl $0x4, %ecx + mov %esp, %ebx + add %ebx, %ecx + sub $0x20, %ecx + sub $0x30, %esp + shr $0x4, %ecx + mov %cx, %gs + + /* now push the indirect jump decriptor there */ mov (prot_jump), %ebx add %eax, %ebx - mov %ebx, (prot_jump) + movl %ebx, %gs:GS_PROT_JUMP + mov $8, %bx + movw %bx, %gs:GS_PROT_JUMP + 4 + + /* fix the gdt descriptor to be PC relative */ + movw (gdt_desc), %bx + movw %bx, %gs:GS_GDT_DESC + movl (gdt_desc+2), %ebx + add %eax, %ebx + movl %ebx, %gs:GS_GDT_DESC + 2 + + /* Read the bootinfo struct into RAM */ + read_fw_blob(FW_CFG_INITRD) /* FS = bootinfo_struct */ read_fw FW_CFG_INITRD_ADDR @@ -100,7 +142,7 @@ run_multiboot: mov %ax, %fs /* ES = mmap_addr */ - read_fw FW_CFG_INITRD_SIZE + mov %eax, %fs:0x48 shr $4, %eax mov %ax, %es @@ -144,7 +186,7 @@ mmap_done: real_to_prot: /* Load the GDT before going into protected mode */ lgdt: - data32 lgdt %cs:gdt_desc + data32 lgdt %gs:GS_GDT_DESC /* get us to protected mode now */ movl $1, %eax @@ -152,7 +194,7 @@ lgdt: /* the LJMP sets CS for us and gets us to 32-bit */ ljmp: - data32 ljmp *%cs:prot_jump + data32 ljmp *%gs:GS_PROT_JUMP prot_mode: .code32 @@ -165,8 +207,11 @@ prot_mode: movl %eax, %fs movl %eax, %gs + /* Read the kernel and modules into RAM */ + read_fw_blob(FW_CFG_KERNEL) + /* Jump off to the kernel */ - read_fw FW_CFG_KERNEL_ADDR + read_fw FW_CFG_KERNEL_ENTRY mov %eax, %ecx /* EBX contains a pointer to the bootinfo struct */ @@ -180,8 +225,6 @@ ljmp2: /* Variables */ .align 4, 0 -old_int19: .long 0 - prot_jump: .long prot_mode .short 8