qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Alexander Graf <agraf@suse.de>
To: qemu-devel@nongnu.org
Cc: glommer@redhat.com, avi@redhat.com
Subject: [Qemu-devel] [PATCH 3/6] Convert multiboot to fw_cfg backed data storage
Date: Wed, 11 Nov 2009 19:09:23 +0100	[thread overview]
Message-ID: <1257962966-22902-4-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1257962966-22902-1-git-send-email-agraf@suse.de>

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 <agraf@suse.de>
---
 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..291ca1d 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 (copy_rom(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
 
-- 
1.6.0.2

  parent reply	other threads:[~2009-11-11 18:09 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-11 18:09 [Qemu-devel] [PATCH 0/6] Fix -kernel with SeaBIOS Alexander Graf
2009-11-11 18:09 ` [Qemu-devel] [PATCH 1/6] Make fw_cfg interface 32-bit aware Alexander Graf
2009-11-11 21:53   ` [Qemu-devel] " Anthony Liguori
2009-11-11 22:15     ` Alexander Graf
2009-11-11 22:22       ` Anthony Liguori
2009-11-12  0:03         ` Alexander Graf
2009-11-12  0:14           ` Anthony Liguori
2009-11-11 18:09 ` [Qemu-devel] [PATCH 2/6] Introduce copy_rom Alexander Graf
2009-11-11 21:57   ` [Qemu-devel] " Anthony Liguori
2009-11-12  0:02     ` Alexander Graf
2009-11-11 18:09 ` Alexander Graf [this message]
2009-11-11 18:09 ` [Qemu-devel] [PATCH 4/6] Move common option rom code to header file Alexander Graf
2009-11-11 18:09 ` [Qemu-devel] [PATCH 5/6] Convert linux bootrom to external rom and fw_cfg Alexander Graf
2009-11-11 18:09 ` [Qemu-devel] [PATCH 6/6] Add linuxboot to BLOBS Alexander Graf
2009-11-12 14:53 ` [Qemu-devel] [PATCH 0/6] Fix -kernel with SeaBIOS Christoph Hellwig
2009-11-12 14:56   ` Alexander Graf
  -- strict thread matches above, loose matches on Subject: below --
2009-11-12 20:53 [Qemu-devel] [PATCH 0/6] Fix -kernel with SeaBIOS v2 Alexander Graf
2009-11-12 20:53 ` [Qemu-devel] [PATCH 3/6] Convert multiboot to fw_cfg backed data storage Alexander Graf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1257962966-22902-4-git-send-email-agraf@suse.de \
    --to=agraf@suse.de \
    --cc=avi@redhat.com \
    --cc=glommer@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).