All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 1/2] multiboot: Fix module loading and setting of mmap.
@ 2009-11-30 22:25 Adam Lackorzynski
  2009-11-30 22:26 ` [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules Adam Lackorzynski
  0 siblings, 1 reply; 10+ messages in thread
From: Adam Lackorzynski @ 2009-11-30 22:25 UTC (permalink / raw)
  To: qemu-devel

multiboot: Fix module loading and setting of mmap.

Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
Acked-by: Alexander Graf <agraf@suse.de>
---
 hw/pc.c                       |    2 +-
 pc-bios/multiboot.bin         |  Bin 512 -> 1024 bytes
 pc-bios/optionrom/multiboot.S |    5 ++++-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 7c791c4..6bcfe1b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -661,7 +661,7 @@ static int load_multiboot(void *fw_cfg,
 
             /* append module data at the end of last module */
             mb_kernel_data = qemu_realloc(mb_kernel_data,
-                                          mh_load_addr - mb_mod_end);
+                                          mb_mod_end - mh_load_addr);
             load_image(initrd_filename,
                        mb_kernel_data + mb_mod_start - mh_load_addr);
 
diff --git a/pc-bios/multiboot.bin b/pc-bios/multiboot.bin
index 59737c3c6798f83c1b35534d7865c79ba9ca3bc8..d7da6e04ad6d71d26f577d9d6a019719bcce8766 100644
GIT binary patch
delta 261
zcmXZVu}Z^G6vpv$F1I0cu#I9V4%gzY#MMa$cNeJ-(0mTo!A)Em=wfIHT=E32KEb6f
z2@WZAa%&f<xELrj&`k=OK!*b#{NR6l>Dz<rSAi>annbhA>QS4*9nc|err{)-{caFW
zkS-*`52Rlb!8dr0Vcx-T=_1W#lw+iR82s)bP(*Jwd4ZBNQf*NVi%LEaTeb=1pTyK@
z+^ns}PHl-)KRP1F^qtxdQnO1ag{ZR4?YeL3`o3c=dU$b3KcBZeG`LkZ4HHr0DDm)j
sLZm;BWd>vGLhU(Kng}aYiFF^Qsf$Z-!SNZpqTu*}quA%c_PYG^4_6gol>h($

delta 120
zcmZqRXkd{DUB#FdAZK`>??&3f6b8Mt#U_l$*-{u3C-RF+cFSckrZFB)>jcr=au!gI
z1>?lS%1k@BCmvOp_`zCCFO8p3EQ2v^2O|Rm1HaM%y|n*&7L1b}8FeS`W7J{=3f^Ow
R{EE?l$$@dQBGY6>MgYdxBLx5e

diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S
index be5c9fc..9131837 100644
--- a/pc-bios/optionrom/multiboot.S
+++ b/pc-bios/optionrom/multiboot.S
@@ -62,6 +62,9 @@ run_multiboot:
 	add		%eax, %ebx
 	movl		%ebx, %gs:GS_GDT_DESC + 2
 
+	xor		%eax, %eax
+	mov		%eax, %es
+
 	/* Read the bootinfo struct into RAM */
 	read_fw_blob(FW_CFG_INITRD)
 
@@ -71,7 +74,7 @@ run_multiboot:
 	mov		%ax, %fs
 
 	/* ES = mmap_addr */
-	mov		%eax, %fs:0x48
+	mov 		%fs:48, %eax
 	shr		$4, %eax
 	mov		%ax, %es
 
-- 
1.6.5.3


Adam
-- 
Adam                 adam@os.inf.tu-dresden.de
  Lackorzynski         http://os.inf.tu-dresden.de/~adam/

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

* [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules
  2009-11-30 22:25 [Qemu-devel] [PATCH 1/2] multiboot: Fix module loading and setting of mmap Adam Lackorzynski
@ 2009-11-30 22:26 ` Adam Lackorzynski
  2009-12-01  6:51   ` Alexander Graf
  2009-12-03 20:26   ` Anthony Liguori
  0 siblings, 2 replies; 10+ messages in thread
From: Adam Lackorzynski @ 2009-11-30 22:26 UTC (permalink / raw)
  To: qemu-devel

multiboot: Support arbitrary number of modules


Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
---
 hw/pc.c |  216 +++++++++++++++++++++++++++++++++++++++++---------------------
 1 files changed, 143 insertions(+), 73 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 6bcfe1b..163bec1 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -507,6 +507,79 @@ static long get_file_size(FILE *f)
 #error multiboot struct needs to fit in 16 bit real mode
 #endif
 
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+struct mb_state {
+    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
+    uint32_t mb_buf_phys; /* address in target */
+    int mb_buf_size;      /* size of mb_buf in bytes */
+    int mb_mods_avail;    /* available slots for mb modules infos */
+    int mb_mods_count;    /* currently used slots of mb modules */
+    int offset_mbinfo;    /* offset of mb-info's in bytes */
+    int offset_cmdlines;  /* offset in buffer for cmdlines */
+    int offset_mods;      /* offset of modules in bytes */
+};
+
+static uint32_t mb_add_cmdline(struct mb_state *s, const char *cmdline)
+{
+    int len = strlen(cmdline) + 1;
+    uint32_t p = s->offset_cmdlines;
+
+    pstrcpy((char *)s->mb_buf + p, len, cmdline);
+    s->offset_cmdlines += len;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(struct mb_state *s,
+                       uint32_t start, uint32_t end,
+                       uint32_t cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+#ifdef DEBUG_MULTIBOOT
+    fprintf(stderr, "mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
+#endif
+
+    s->mb_mods_count++;
+}
+
 static int load_multiboot(void *fw_cfg,
                           FILE *f,
                           const char *kernel_filename,
@@ -519,12 +592,8 @@ static int load_multiboot(void *fw_cfg,
     uint32_t mh_entry_addr;
     uint32_t mh_load_addr;
     uint32_t mb_kernel_size;
-    uint32_t mmap_addr = MULTIBOOT_STRUCT_ADDR;
-    uint32_t mb_bootinfo = MULTIBOOT_STRUCT_ADDR + 0x500;
-    uint32_t mb_mod_end;
-    uint8_t bootinfo[0x500];
-    uint32_t cmdline = 0x200;
-    uint8_t *mb_kernel_data;
+    struct mb_state mbs;
+    uint8_t bootinfo[MBI_SIZE];
     uint8_t *mb_bootinfo_data;
 
     /* Ok, let's see if it is a multiboot image.
@@ -549,6 +618,7 @@ static int load_multiboot(void *fw_cfg,
     fprintf(stderr, "qemu: I believe we found a multiboot image!\n");
 #endif
     memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
 
     if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
         fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
@@ -566,8 +636,8 @@ 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) {
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, elf_entry, kernel_size) != kernel_size) {
             fprintf(stderr, "Error while fetching elf kernel from rom\n");
             exit(1);
         }
@@ -604,104 +674,104 @@ static int load_multiboot(void *fw_cfg,
                 mb_kernel_size, mh_load_addr);
 #endif
 
-        mb_kernel_data = qemu_malloc(mb_kernel_size);
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
         fseek(f, mb_kernel_text_offset, SEEK_SET);
-        fread(mb_kernel_data, 1, mb_kernel_size, f);
+        fread(mbs.mb_buf, 1, mb_kernel_size, f);
         fclose(f);
     }
 
-    /* blob size is only the kernel for now */
-    mb_mod_end = mh_load_addr + mb_kernel_size;
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while ((r = strchr(r, ','))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    // enlarge mb_buf to hold cmdlines and mb-info structs
+    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
 
-    /* load modules */
-    stl_p(bootinfo + 20, 0x0); /* mods_count */
     if (initrd_filename) {
-        uint32_t mb_mod_info = 0x100;
-        uint32_t mb_mod_cmdline = 0x300;
-        uint32_t mb_mod_start = mh_load_addr;
-        uint32_t mb_mod_length = mb_kernel_size;
         char *next_initrd;
-        char *next_space;
-        int mb_mod_count = 0;
+
+	mbs.offset_mods = mbs.mb_buf_size;
 
         do {
-            if (mb_mod_info + 16 > mb_mod_cmdline) {
-                printf("WARNING: Too many modules loaded, aborting.\n");
-                break;
-            }
+            char *next_space;
+            uint32_t mb_mod_length;
+	    uint32_t offs = mbs.mb_buf_size;
             next_initrd = strchr(initrd_filename, ',');
             if (next_initrd)
                 *next_initrd = '\0';
             /* if a space comes after the module filename, treat everything
                after that as parameters */
-            pstrcpy((char*)bootinfo + mb_mod_cmdline,
-                    sizeof(bootinfo) - mb_mod_cmdline,
-                    initrd_filename);
-            stl_p(bootinfo + mb_mod_info + 8, mb_bootinfo + mb_mod_cmdline); /* string */
-            mb_mod_cmdline += strlen(initrd_filename) + 1;
-            if (mb_mod_cmdline > sizeof(bootinfo)) {
-                mb_mod_cmdline = sizeof(bootinfo);
-                printf("WARNING: Too many module cmdlines loaded, aborting.\n");
-                break;
-            }
+            uint32_t c = mb_add_cmdline(&mbs, initrd_filename);
             if ((next_space = strchr(initrd_filename, ' ')))
                 *next_space = '\0';
 #ifdef DEBUG_MULTIBOOT
             printf("multiboot loading module: %s\n", initrd_filename);
 #endif
-            mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1))
-                         & (TARGET_PAGE_MASK);
             mb_mod_length = get_image_size(initrd_filename);
             if (mb_mod_length < 0) {
                 fprintf(stderr, "failed to get %s image size\n", initrd_filename);
                 exit(1);
             }
-            mb_mod_end = mb_mod_start + mb_mod_length;
-            mb_mod_count++;
-
-            /* append module data at the end of last module */
-            mb_kernel_data = qemu_realloc(mb_kernel_data,
-                                          mb_mod_end - mh_load_addr);
-            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 */
+
+	    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+	    mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
 #ifdef DEBUG_MULTIBOOT
-            printf("mod_start: %#x\nmod_end:   %#x\n", mb_mod_start,
-                   mb_mod_start + mb_mod_length);
+            printf("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
+                   (char *)mbs.mb_buf + offs,
+                   (char *)mbs.mb_buf + offs + mb_mod_length, c);
 #endif
             initrd_filename = next_initrd+1;
-            mb_mod_info += 16;
         } while (next_initrd);
-        stl_p(bootinfo + 20, mb_mod_count); /* mods_count */
-        stl_p(bootinfo + 24, mb_bootinfo + 0x100); /* mods_addr */
     }
 
     /* Commandline support */
-    stl_p(bootinfo + 16, mb_bootinfo + cmdline);
-    snprintf((char*)bootinfo + cmdline, 0x100, "%s %s",
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
              kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
 
     /* the kernel is where we want it to be now */
-#define MULTIBOOT_FLAGS_MEMORY (1 << 0)
-#define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1)
-#define MULTIBOOT_FLAGS_CMDLINE (1 << 2)
-#define MULTIBOOT_FLAGS_MODULES (1 << 3)
-#define MULTIBOOT_FLAGS_MMAP (1 << 6)
-    stl_p(bootinfo, MULTIBOOT_FLAGS_MEMORY
-                  | MULTIBOOT_FLAGS_BOOT_DEVICE
-                  | MULTIBOOT_FLAGS_CMDLINE
-                  | MULTIBOOT_FLAGS_MODULES
-                  | MULTIBOOT_FLAGS_MMAP);
-    stl_p(bootinfo + 4, 640); /* mem_lower */
-    stl_p(bootinfo + 8, ram_size / 1024); /* mem_upper */
-    stl_p(bootinfo + 12, 0x8001ffff); /* XXX: use the -boot switch? */
-    stl_p(bootinfo + 48, mmap_addr); /* mmap_addr */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
 
 #ifdef DEBUG_MULTIBOOT
     fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    fprintf(stderr, "           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
+    fprintf(stderr, "           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
+    fprintf(stderr, "           mb_mods_count = %d\n", mbs.mb_mods_count);
 #endif
 
     /* save bootinfo off the stack */
@@ -711,11 +781,11 @@ static int load_multiboot(void *fw_cfg,
     /* Pass variables to option rom */
     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);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+	             mbs.mb_buf, mbs.mb_buf_size);
 
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
     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));
-- 
1.6.5.3



Adam
-- 
Adam                 adam@os.inf.tu-dresden.de
  Lackorzynski         http://os.inf.tu-dresden.de/~adam/

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

* Re: [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules
  2009-11-30 22:26 ` [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules Adam Lackorzynski
@ 2009-12-01  6:51   ` Alexander Graf
  2009-12-03 20:26   ` Anthony Liguori
  1 sibling, 0 replies; 10+ messages in thread
From: Alexander Graf @ 2009-12-01  6:51 UTC (permalink / raw)
  To: Adam Lackorzynski; +Cc: qemu-devel


On 30.11.2009, at 23:26, Adam Lackorzynski wrote:

> multiboot: Support arbitrary number of modules

Sounds like it's about time to extract the multiboot code from pc.c and move it to multiboot.c. After all, multiboot is supported on non-x86 as well, so maybe we can reuse some code here.

Alex

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

* Re: [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules
  2009-11-30 22:26 ` [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules Adam Lackorzynski
  2009-12-01  6:51   ` Alexander Graf
@ 2009-12-03 20:26   ` Anthony Liguori
  2009-12-03 22:19     ` [Qemu-devel] [PATCH 1/2] " Adam Lackorzynski
  1 sibling, 1 reply; 10+ messages in thread
From: Anthony Liguori @ 2009-12-03 20:26 UTC (permalink / raw)
  To: Adam Lackorzynski; +Cc: qemu-devel

Adam Lackorzynski wrote:
> multiboot: Support arbitrary number of modules
>
>
> Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
> ---
>  hw/pc.c |  216 +++++++++++++++++++++++++++++++++++++++++---------------------
>  1 files changed, 143 insertions(+), 73 deletions(-)
>
> diff --git a/hw/pc.c b/hw/pc.c
> index 6bcfe1b..163bec1 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -507,6 +507,79 @@ static long get_file_size(FILE *f)
>  #error multiboot struct needs to fit in 16 bit real mode
>  #endif
>  
> +enum {
> +    /* Multiboot info */
> +    MBI_FLAGS       = 0,
> +    MBI_MEM_LOWER   = 4,
> +    MBI_MEM_UPPER   = 8,
> +    MBI_BOOT_DEVICE = 12,
> +    MBI_CMDLINE     = 16,
> +    MBI_MODS_COUNT  = 20,
> +    MBI_MODS_ADDR   = 24,
> +    MBI_MMAP_ADDR   = 48,
> +
> +    MBI_SIZE        = 88,
> +
> +    /* Multiboot modules */
> +    MB_MOD_START    = 0,
> +    MB_MOD_END      = 4,
> +    MB_MOD_CMDLINE  = 8,
> +
> +    MB_MOD_SIZE     = 16,
> +
> +    /* Region offsets */
> +    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
> +    ADDR_MBI      = ADDR_E820_MAP + 0x500,
> +
> +    /* Multiboot flags */
> +    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
> +    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
> +    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
> +    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
> +    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
> +};
> +
> +struct mb_state {
> +    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
> +    uint32_t mb_buf_phys; /* address in target */
> +    int mb_buf_size;      /* size of mb_buf in bytes */
> +    int mb_mods_avail;    /* available slots for mb modules infos */
> +    int mb_mods_count;    /* currently used slots of mb modules */
> +    int offset_mbinfo;    /* offset of mb-info's in bytes */
> +    int offset_cmdlines;  /* offset in buffer for cmdlines */
> +    int offset_mods;      /* offset of modules in bytes */
> +};
>   

Should be MultibootState.

> +static uint32_t mb_add_cmdline(struct mb_state *s, const char *cmdline)
> +{
> +    int len = strlen(cmdline) + 1;
> +    uint32_t p = s->offset_cmdlines;
> +
> +    pstrcpy((char *)s->mb_buf + p, len, cmdline);
> +    s->offset_cmdlines += len;
> +    return s->mb_buf_phys + p;
> +}
> +
> +static void mb_add_mod(struct mb_state *s,
> +                       uint32_t start, uint32_t end,
> +                       uint32_t cmdline_phys)
> +{
> +    char *p;
> +    assert(s->mb_mods_count < s->mb_mods_avail);
> +
> +    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
> +
> +    stl_p(p + MB_MOD_START,   start);
> +    stl_p(p + MB_MOD_END,     end);
> +    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
> +
> +#ifdef DEBUG_MULTIBOOT
> +    fprintf(stderr, "mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
> +#endif
>   

A debug macro would be a lot nicer.

> +    s->mb_mods_count++;
> +}
> +
>  static int load_multiboot(void *fw_cfg,
>                            FILE *f,
>                            const char *kernel_filename,
> @@ -519,12 +592,8 @@ static int load_multiboot(void *fw_cfg,
>      uint32_t mh_entry_addr;
>      uint32_t mh_load_addr;
>      uint32_t mb_kernel_size;
> -    uint32_t mmap_addr = MULTIBOOT_STRUCT_ADDR;
> -    uint32_t mb_bootinfo = MULTIBOOT_STRUCT_ADDR + 0x500;
> -    uint32_t mb_mod_end;
> -    uint8_t bootinfo[0x500];
> -    uint32_t cmdline = 0x200;
> -    uint8_t *mb_kernel_data;
> +    struct mb_state mbs;
> +    uint8_t bootinfo[MBI_SIZE];
>      uint8_t *mb_bootinfo_data;
>  
>      /* Ok, let's see if it is a multiboot image.
> @@ -549,6 +618,7 @@ static int load_multiboot(void *fw_cfg,
>      fprintf(stderr, "qemu: I believe we found a multiboot image!\n");
>  #endif
>      memset(bootinfo, 0, sizeof(bootinfo));
> +    memset(&mbs, 0, sizeof(mbs));
>  
>      if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
>          fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
> @@ -566,8 +636,8 @@ 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) {
> +        mbs.mb_buf = qemu_malloc(mb_kernel_size);
> +        if (rom_copy(mbs.mb_buf, elf_entry, kernel_size) != kernel_size) {
>              fprintf(stderr, "Error while fetching elf kernel from rom\n");
>              exit(1);
>          }
> @@ -604,104 +674,104 @@ static int load_multiboot(void *fw_cfg,
>                  mb_kernel_size, mh_load_addr);
>  #endif
>  
> -        mb_kernel_data = qemu_malloc(mb_kernel_size);
> +        mbs.mb_buf = qemu_malloc(mb_kernel_size);
>          fseek(f, mb_kernel_text_offset, SEEK_SET);
> -        fread(mb_kernel_data, 1, mb_kernel_size, f);
> +        fread(mbs.mb_buf, 1, mb_kernel_size, f);
>          fclose(f);
>      }
>  
> -    /* blob size is only the kernel for now */
> -    mb_mod_end = mh_load_addr + mb_kernel_size;
> +    mbs.mb_buf_phys = mh_load_addr;
> +
> +    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
> +    mbs.offset_mbinfo = mbs.mb_buf_size;
> +
> +    /* Calculate space for cmdlines and mb_mods */
> +    mbs.mb_buf_size += strlen(kernel_filename) + 1;
> +    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
> +    if (initrd_filename) {
> +        const char *r = initrd_filename;
> +        mbs.mb_buf_size += strlen(r) + 1;
> +        mbs.mb_mods_avail = 1;
> +        while ((r = strchr(r, ','))) {
> +           mbs.mb_mods_avail++;
> +           r++;
> +        }
> +        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
> +    }
> +
> +    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
> +
> +    // enlarge mb_buf to hold cmdlines and mb-info structs
>   

Please avoid C99 comments.

> +
> +	    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
> +	    mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
> +
> +            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
> +            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
> +                       mbs.mb_buf_phys + offs + mb_mod_length, c);
>   

You've got a mix of tabs and spaces.

Regards,

Anthony Liguori

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

* [Qemu-devel] [PATCH 1/2] multiboot: Support arbitrary number of modules.
  2009-12-03 20:26   ` Anthony Liguori
@ 2009-12-03 22:19     ` Adam Lackorzynski
  2009-12-03 22:23       ` [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file Adam Lackorzynski
  2009-12-03 23:24       ` [Qemu-devel] Re: [PATCH 1/2] multiboot: Support arbitrary number of modules Anthony Liguori
  0 siblings, 2 replies; 10+ messages in thread
From: Adam Lackorzynski @ 2009-12-03 22:19 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

multiboot: Support arbitrary number of modules.

Addressed comments by Anthony.

Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
---
 hw/pc.c |  260 ++++++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 159 insertions(+), 101 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 8c1b7ea..47d7796 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -51,6 +51,12 @@
 /* Show multiboot debug output */
 //#define DEBUG_MULTIBOOT
 
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## a)
+#else
+#define mb_debug(a...)
+#endif
+
 #define BIOS_FILENAME "bios.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -512,6 +518,77 @@ static long get_file_size(FILE *f)
 #error multiboot struct needs to fit in 16 bit real mode
 #endif
 
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+struct MultibootState {
+    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
+    uint32_t mb_buf_phys; /* address in target */
+    int mb_buf_size;      /* size of mb_buf in bytes */
+    int mb_mods_avail;    /* available slots for mb modules infos */
+    int mb_mods_count;    /* currently used slots of mb modules */
+    int offset_mbinfo;    /* offset of mb-info's in bytes */
+    int offset_cmdlines;  /* offset in buffer for cmdlines */
+    int offset_mods;      /* offset of modules in bytes */
+};
+
+static uint32_t mb_add_cmdline(struct MultibootState *s, const char *cmdline)
+{
+    int len = strlen(cmdline) + 1;
+    uint32_t p = s->offset_cmdlines;
+
+    pstrcpy((char *)s->mb_buf + p, len, cmdline);
+    s->offset_cmdlines += len;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(struct MultibootState *s,
+                       uint32_t start, uint32_t end,
+                       uint32_t cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+    mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
+
+    s->mb_mods_count++;
+}
+
 static int load_multiboot(void *fw_cfg,
                           FILE *f,
                           const char *kernel_filename,
@@ -524,12 +601,8 @@ static int load_multiboot(void *fw_cfg,
     uint32_t mh_entry_addr;
     uint32_t mh_load_addr;
     uint32_t mb_kernel_size;
-    uint32_t mmap_addr = MULTIBOOT_STRUCT_ADDR;
-    uint32_t mb_bootinfo = MULTIBOOT_STRUCT_ADDR + 0x500;
-    uint32_t mb_mod_end;
-    uint8_t bootinfo[0x500];
-    uint32_t cmdline = 0x200;
-    uint8_t *mb_kernel_data;
+    struct MultibootState mbs;
+    uint8_t bootinfo[MBI_SIZE];
     uint8_t *mb_bootinfo_data;
 
     /* Ok, let's see if it is a multiboot image.
@@ -550,10 +623,9 @@ static int load_multiboot(void *fw_cfg,
     if (!is_multiboot)
         return 0; /* no multiboot */
 
-#ifdef DEBUG_MULTIBOOT
-    fprintf(stderr, "qemu: I believe we found a multiboot image!\n");
-#endif
+    mb_debug("qemu: I believe we found a multiboot image!\n");
     memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
 
     if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
         fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
@@ -571,24 +643,18 @@ 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) {
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, 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);
-#endif
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                  mb_kernel_size, (size_t)mh_entry_addr);
     } else {
         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
         uint32_t mh_header_addr = ldl_p(header+i+12);
         mh_load_addr = ldl_p(header+i+16);
-#ifdef DEBUG_MULTIBOOT
-        uint32_t mh_load_end_addr = ldl_p(header+i+20);
-        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);
 
         mh_entry_addr = ldl_p(header+i+28);
@@ -600,115 +666,107 @@ static int load_multiboot(void *fw_cfg,
         uint32_t mh_height = ldl_p(header+i+40);
         uint32_t mh_depth = ldl_p(header+i+44); */
 
-#ifdef DEBUG_MULTIBOOT
-        fprintf(stderr, "multiboot: mh_header_addr = %#x\n", mh_header_addr);
-        fprintf(stderr, "multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        fprintf(stderr, "multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
-        fprintf(stderr, "multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
-        fprintf(stderr, "qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                mb_kernel_size, mh_load_addr);
-#endif
+        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+                 mb_kernel_size, mh_load_addr);
 
-        mb_kernel_data = qemu_malloc(mb_kernel_size);
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
         fseek(f, mb_kernel_text_offset, SEEK_SET);
-        fread(mb_kernel_data, 1, mb_kernel_size, f);
+        fread(mbs.mb_buf, 1, mb_kernel_size, f);
         fclose(f);
     }
 
-    /* blob size is only the kernel for now */
-    mb_mod_end = mh_load_addr + mb_kernel_size;
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while ((r = strchr(r, ','))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    /* enlarge mb_buf to hold cmdlines and mb-info structs */
+    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
 
-    /* load modules */
-    stl_p(bootinfo + 20, 0x0); /* mods_count */
     if (initrd_filename) {
-        uint32_t mb_mod_info = 0x100;
-        uint32_t mb_mod_cmdline = 0x300;
-        uint32_t mb_mod_start = mh_load_addr;
-        uint32_t mb_mod_length = mb_kernel_size;
         char *next_initrd;
-        char *next_space;
-        int mb_mod_count = 0;
+
+        mbs.offset_mods = mbs.mb_buf_size;
 
         do {
-            if (mb_mod_info + 16 > mb_mod_cmdline) {
-                printf("WARNING: Too many modules loaded, aborting.\n");
-                break;
-            }
+            char *next_space;
+            uint32_t mb_mod_length;
+            uint32_t offs = mbs.mb_buf_size;
 
             next_initrd = strchr(initrd_filename, ',');
             if (next_initrd)
                 *next_initrd = '\0';
             /* if a space comes after the module filename, treat everything
                after that as parameters */
-            pstrcpy((char*)bootinfo + mb_mod_cmdline,
-                    sizeof(bootinfo) - mb_mod_cmdline,
-                    initrd_filename);
-            stl_p(bootinfo + mb_mod_info + 8, mb_bootinfo + mb_mod_cmdline); /* string */
-            mb_mod_cmdline += strlen(initrd_filename) + 1;
-            if (mb_mod_cmdline > sizeof(bootinfo)) {
-                mb_mod_cmdline = sizeof(bootinfo);
-                printf("WARNING: Too many module cmdlines loaded, aborting.\n");
-                break;
-            }
+            uint32_t c = mb_add_cmdline(&mbs, initrd_filename);
             if ((next_space = strchr(initrd_filename, ' ')))
                 *next_space = '\0';
-#ifdef DEBUG_MULTIBOOT
-            printf("multiboot loading module: %s\n", initrd_filename);
-#endif
-            mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1))
-                         & (TARGET_PAGE_MASK);
+            mb_debug("multiboot loading module: %s\n", initrd_filename);
             mb_mod_length = get_image_size(initrd_filename);
             if (mb_mod_length < 0) {
                 fprintf(stderr, "failed to get %s image size\n", initrd_filename);
                 exit(1);
             }
-            mb_mod_end = mb_mod_start + mb_mod_length;
-            mb_mod_count++;
-
-            /* append module data at the end of last module */
-            mb_kernel_data = qemu_realloc(mb_kernel_data,
-                                          mb_mod_end - mh_load_addr);
-            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 */
-#ifdef DEBUG_MULTIBOOT
-            printf("mod_start: %#x\nmod_end:   %#x\n", mb_mod_start,
-                   mb_mod_start + mb_mod_length);
-#endif
+
+            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
+            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
+                     (char *)mbs.mb_buf + offs,
+                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
             initrd_filename = next_initrd+1;
-            mb_mod_info += 16;
         } while (next_initrd);
-        stl_p(bootinfo + 20, mb_mod_count); /* mods_count */
-        stl_p(bootinfo + 24, mb_bootinfo + 0x100); /* mods_addr */
     }
 
     /* Commandline support */
-    stl_p(bootinfo + 16, mb_bootinfo + cmdline);
-    snprintf((char*)bootinfo + cmdline, 0x100, "%s %s",
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
              kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
 
-    /* the kernel is where we want it to be now */
-#define MULTIBOOT_FLAGS_MEMORY (1 << 0)
-#define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1)
-#define MULTIBOOT_FLAGS_CMDLINE (1 << 2)
-#define MULTIBOOT_FLAGS_MODULES (1 << 3)
-#define MULTIBOOT_FLAGS_MMAP (1 << 6)
-    stl_p(bootinfo, MULTIBOOT_FLAGS_MEMORY
-                  | MULTIBOOT_FLAGS_BOOT_DEVICE
-                  | MULTIBOOT_FLAGS_CMDLINE
-                  | MULTIBOOT_FLAGS_MODULES
-                  | MULTIBOOT_FLAGS_MMAP);
-    stl_p(bootinfo + 4, 640); /* mem_lower */
-    stl_p(bootinfo + 8, ram_size / 1024); /* mem_upper */
-    stl_p(bootinfo + 12, 0x8001ffff); /* XXX: use the -boot switch? */
-    stl_p(bootinfo + 48, mmap_addr); /* mmap_addr */
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
 
-#ifdef DEBUG_MULTIBOOT
-    fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
-#endif
+    /* the kernel is where we want it to be now */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
+
+    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    mb_debug("           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
+    mb_debug("           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
+    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
 
     /* save bootinfo off the stack */
     mb_bootinfo_data = qemu_malloc(sizeof(bootinfo));
@@ -717,11 +775,11 @@ static int load_multiboot(void *fw_cfg,
     /* Pass variables to option rom */
     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);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+                     mbs.mb_buf, mbs.mb_buf_size);
 
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
     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));
-- 
1.6.5.3



Adam
-- 
Adam                 adam@os.inf.tu-dresden.de
  Lackorzynski         http://os.inf.tu-dresden.de/~adam/

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

* [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file
  2009-12-03 22:19     ` [Qemu-devel] [PATCH 1/2] " Adam Lackorzynski
@ 2009-12-03 22:23       ` Adam Lackorzynski
  2009-12-03 23:20         ` Alexander Graf
  2009-12-03 23:24       ` [Qemu-devel] Re: [PATCH 1/2] multiboot: Support arbitrary number of modules Anthony Liguori
  1 sibling, 1 reply; 10+ messages in thread
From: Adam Lackorzynski @ 2009-12-03 22:23 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel

multiboot: Separate multiboot loading into separate file

Move multiboot loading functionality to a separate file as suggested by
Alex Graf.


Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
---
 Makefile.target |    2 +-
 hw/multiboot.c  |  318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/multiboot.h  |   12 ++
 hw/pc.c         |  292 +--------------------------------------------------
 4 files changed, 334 insertions(+), 290 deletions(-)
 create mode 100644 hw/multiboot.c
 create mode 100644 hw/multiboot.h

diff --git a/Makefile.target b/Makefile.target
index 891ea08..20e4145 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -194,7 +194,7 @@ obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
-obj-i386-y += ne2000-isa.o
+obj-i386-y += ne2000-isa.o multiboot.o
 
 # shared objects
 obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
diff --git a/hw/multiboot.c b/hw/multiboot.c
new file mode 100644
index 0000000..bde477d
--- /dev/null
+++ b/hw/multiboot.c
@@ -0,0 +1,318 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "fw_cfg.h"
+#include "multiboot.h"
+#include "loader.h"
+#include "elf.h"
+#include "sysemu.h"
+
+/* Show multiboot debug output */
+#define DEBUG_MULTIBOOT
+
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## a)
+#else
+#define mb_debug(a...)
+#endif
+
+#define MULTIBOOT_STRUCT_ADDR 0x9000
+
+#if MULTIBOOT_STRUCT_ADDR > 0xf0000
+#error multiboot struct needs to fit in 16 bit real mode
+#endif
+
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+struct MultibootState {
+    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
+    uint32_t mb_buf_phys; /* address in target */
+    int mb_buf_size;      /* size of mb_buf in bytes */
+    int mb_mods_avail;    /* available slots for mb modules infos */
+    int mb_mods_count;    /* currently used slots of mb modules */
+    int offset_mbinfo;    /* offset of mb-info's in bytes */
+    int offset_cmdlines;  /* offset in buffer for cmdlines */
+    int offset_mods;      /* offset of modules in bytes */
+};
+
+static uint32_t mb_add_cmdline(struct MultibootState *s, const char *cmdline)
+{
+    int len = strlen(cmdline) + 1;
+    uint32_t p = s->offset_cmdlines;
+
+    pstrcpy((char *)s->mb_buf + p, len, cmdline);
+    s->offset_cmdlines += len;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(struct MultibootState *s,
+                       uint32_t start, uint32_t end,
+                       uint32_t cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+    mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
+
+    s->mb_mods_count++;
+}
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header)
+{
+    int i, is_multiboot = 0;
+    uint32_t flags = 0;
+    uint32_t mh_entry_addr;
+    uint32_t mh_load_addr;
+    uint32_t mb_kernel_size;
+    struct MultibootState mbs;
+    uint8_t bootinfo[MBI_SIZE];
+    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. */
+    for (i = 0; i < (8192 - 48); i += 4) {
+        if (ldl_p(header+i) == 0x1BADB002) {
+            uint32_t checksum = ldl_p(header+i+8);
+            flags = ldl_p(header+i+4);
+            checksum += flags;
+            checksum += (uint32_t)0x1BADB002;
+            if (!checksum) {
+                is_multiboot = 1;
+                break;
+            }
+        }
+    }
+
+    if (!is_multiboot)
+        return 0; /* no multiboot */
+
+    mb_debug("qemu: I believe we found a multiboot image!\n");
+    memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
+
+    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
+        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+    }
+    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
+        uint64_t elf_entry;
+        int kernel_size;
+        fclose(f);
+        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+                               0, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "Error while loading elf kernel\n");
+            exit(1);
+        }
+        mh_load_addr = mh_entry_addr = elf_entry;
+        mb_kernel_size = kernel_size;
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, elf_entry, kernel_size) != kernel_size) {
+            fprintf(stderr, "Error while fetching elf kernel from rom\n");
+            exit(1);
+        }
+
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                  mb_kernel_size, (size_t)mh_entry_addr);
+    } else {
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+        uint32_t mh_header_addr = ldl_p(header+i+12);
+        mh_load_addr = ldl_p(header+i+16);
+        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+
+        mh_entry_addr = ldl_p(header+i+28);
+        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
+        uint32_t mh_mode_type = ldl_p(header+i+32);
+        uint32_t mh_width = ldl_p(header+i+36);
+        uint32_t mh_height = ldl_p(header+i+40);
+        uint32_t mh_depth = ldl_p(header+i+44); */
+
+        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+                 mb_kernel_size, mh_load_addr);
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        fseek(f, mb_kernel_text_offset, SEEK_SET);
+        fread(mbs.mb_buf, 1, mb_kernel_size, f);
+        fclose(f);
+    }
+
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while ((r = strchr(r, ','))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    /* enlarge mb_buf to hold cmdlines and mb-info structs */
+    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
+
+    if (initrd_filename) {
+        char *next_initrd;
+
+        mbs.offset_mods = mbs.mb_buf_size;
+
+        do {
+            char *next_space;
+            uint32_t mb_mod_length;
+            uint32_t offs = mbs.mb_buf_size;
+
+            next_initrd = strchr(initrd_filename, ',');
+            if (next_initrd)
+                *next_initrd = '\0';
+            /* if a space comes after the module filename, treat everything
+               after that as parameters */
+            uint32_t c = mb_add_cmdline(&mbs, initrd_filename);
+            if ((next_space = strchr(initrd_filename, ' ')))
+                *next_space = '\0';
+            mb_debug("multiboot loading module: %s\n", initrd_filename);
+            mb_mod_length = get_image_size(initrd_filename);
+            if (mb_mod_length < 0) {
+                fprintf(stderr, "failed to get %s image size\n", initrd_filename);
+                exit(1);
+            }
+
+            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
+            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
+                     (char *)mbs.mb_buf + offs,
+                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
+            initrd_filename = next_initrd+1;
+        } while (next_initrd);
+    }
+
+    /* Commandline support */
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
+             kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
+
+    /* the kernel is where we want it to be now */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
+
+    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    mb_debug("           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
+    mb_debug("           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
+    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
+
+    /* 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_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, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+                     mbs.mb_buf, mbs.mb_buf_size);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
+    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++;
+
+    return 1; /* yes, we are multiboot */
+}
diff --git a/hw/multiboot.h b/hw/multiboot.h
new file mode 100644
index 0000000..98fb1b7
--- /dev/null
+++ b/hw/multiboot.h
@@ -0,0 +1,12 @@
+#ifndef QEMU_MULTIBOOT_H
+#define QEMU_MULTIBOOT_H
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header);
+
+#endif
diff --git a/hw/pc.c b/hw/pc.c
index 47d7796..f3730dc 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -44,19 +44,11 @@
 #include "ide.h"
 #include "loader.h"
 #include "elf.h"
+#include "multiboot.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
 
-/* Show multiboot debug output */
-//#define DEBUG_MULTIBOOT
-
-#ifdef DEBUG_MULTIBOOT
-#define mb_debug(a...) fprintf(stderr, ## a)
-#else
-#define mb_debug(a...)
-#endif
-
 #define BIOS_FILENAME "bios.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -512,284 +504,6 @@ static long get_file_size(FILE *f)
     return size;
 }
 
-#define MULTIBOOT_STRUCT_ADDR 0x9000
-
-#if MULTIBOOT_STRUCT_ADDR > 0xf0000
-#error multiboot struct needs to fit in 16 bit real mode
-#endif
-
-enum {
-    /* Multiboot info */
-    MBI_FLAGS       = 0,
-    MBI_MEM_LOWER   = 4,
-    MBI_MEM_UPPER   = 8,
-    MBI_BOOT_DEVICE = 12,
-    MBI_CMDLINE     = 16,
-    MBI_MODS_COUNT  = 20,
-    MBI_MODS_ADDR   = 24,
-    MBI_MMAP_ADDR   = 48,
-
-    MBI_SIZE        = 88,
-
-    /* Multiboot modules */
-    MB_MOD_START    = 0,
-    MB_MOD_END      = 4,
-    MB_MOD_CMDLINE  = 8,
-
-    MB_MOD_SIZE     = 16,
-
-    /* Region offsets */
-    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
-    ADDR_MBI      = ADDR_E820_MAP + 0x500,
-
-    /* Multiboot flags */
-    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
-    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
-    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
-    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
-    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
-};
-
-struct MultibootState {
-    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
-    uint32_t mb_buf_phys; /* address in target */
-    int mb_buf_size;      /* size of mb_buf in bytes */
-    int mb_mods_avail;    /* available slots for mb modules infos */
-    int mb_mods_count;    /* currently used slots of mb modules */
-    int offset_mbinfo;    /* offset of mb-info's in bytes */
-    int offset_cmdlines;  /* offset in buffer for cmdlines */
-    int offset_mods;      /* offset of modules in bytes */
-};
-
-static uint32_t mb_add_cmdline(struct MultibootState *s, const char *cmdline)
-{
-    int len = strlen(cmdline) + 1;
-    uint32_t p = s->offset_cmdlines;
-
-    pstrcpy((char *)s->mb_buf + p, len, cmdline);
-    s->offset_cmdlines += len;
-    return s->mb_buf_phys + p;
-}
-
-static void mb_add_mod(struct MultibootState *s,
-                       uint32_t start, uint32_t end,
-                       uint32_t cmdline_phys)
-{
-    char *p;
-    assert(s->mb_mods_count < s->mb_mods_avail);
-
-    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
-
-    stl_p(p + MB_MOD_START,   start);
-    stl_p(p + MB_MOD_END,     end);
-    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
-
-    mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
-
-    s->mb_mods_count++;
-}
-
-static int load_multiboot(void *fw_cfg,
-                          FILE *f,
-                          const char *kernel_filename,
-                          const char *initrd_filename,
-                          const char *kernel_cmdline,
-                          uint8_t *header)
-{
-    int i, is_multiboot = 0;
-    uint32_t flags = 0;
-    uint32_t mh_entry_addr;
-    uint32_t mh_load_addr;
-    uint32_t mb_kernel_size;
-    struct MultibootState mbs;
-    uint8_t bootinfo[MBI_SIZE];
-    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. */
-    for (i = 0; i < (8192 - 48); i += 4) {
-        if (ldl_p(header+i) == 0x1BADB002) {
-            uint32_t checksum = ldl_p(header+i+8);
-            flags = ldl_p(header+i+4);
-            checksum += flags;
-            checksum += (uint32_t)0x1BADB002;
-            if (!checksum) {
-                is_multiboot = 1;
-                break;
-            }
-        }
-    }
-
-    if (!is_multiboot)
-        return 0; /* no multiboot */
-
-    mb_debug("qemu: I believe we found a multiboot image!\n");
-    memset(bootinfo, 0, sizeof(bootinfo));
-    memset(&mbs, 0, sizeof(mbs));
-
-    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
-        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
-    }
-    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
-        uint64_t elf_entry;
-        int kernel_size;
-        fclose(f);
-        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
-                               0, ELF_MACHINE, 0);
-        if (kernel_size < 0) {
-            fprintf(stderr, "Error while loading elf kernel\n");
-            exit(1);
-        }
-        mh_load_addr = mh_entry_addr = elf_entry;
-        mb_kernel_size = kernel_size;
-
-        mbs.mb_buf = qemu_malloc(mb_kernel_size);
-        if (rom_copy(mbs.mb_buf, elf_entry, kernel_size) != kernel_size) {
-            fprintf(stderr, "Error while fetching elf kernel from rom\n");
-            exit(1);
-        }
-
-        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
-                  mb_kernel_size, (size_t)mh_entry_addr);
-    } else {
-        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
-        uint32_t mh_header_addr = ldl_p(header+i+12);
-        mh_load_addr = ldl_p(header+i+16);
-        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
-
-        mh_entry_addr = ldl_p(header+i+28);
-        mb_kernel_size = get_file_size(f) - mb_kernel_text_offset;
-
-        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
-        uint32_t mh_mode_type = ldl_p(header+i+32);
-        uint32_t mh_width = ldl_p(header+i+36);
-        uint32_t mh_height = ldl_p(header+i+40);
-        uint32_t mh_depth = ldl_p(header+i+44); */
-
-        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
-        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
-        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
-        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                 mb_kernel_size, mh_load_addr);
-
-        mbs.mb_buf = qemu_malloc(mb_kernel_size);
-        fseek(f, mb_kernel_text_offset, SEEK_SET);
-        fread(mbs.mb_buf, 1, mb_kernel_size, f);
-        fclose(f);
-    }
-
-    mbs.mb_buf_phys = mh_load_addr;
-
-    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
-    mbs.offset_mbinfo = mbs.mb_buf_size;
-
-    /* Calculate space for cmdlines and mb_mods */
-    mbs.mb_buf_size += strlen(kernel_filename) + 1;
-    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
-    if (initrd_filename) {
-        const char *r = initrd_filename;
-        mbs.mb_buf_size += strlen(r) + 1;
-        mbs.mb_mods_avail = 1;
-        while ((r = strchr(r, ','))) {
-           mbs.mb_mods_avail++;
-           r++;
-        }
-        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
-    }
-
-    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
-
-    /* enlarge mb_buf to hold cmdlines and mb-info structs */
-    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
-    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
-
-    if (initrd_filename) {
-        char *next_initrd;
-
-        mbs.offset_mods = mbs.mb_buf_size;
-
-        do {
-            char *next_space;
-            uint32_t mb_mod_length;
-            uint32_t offs = mbs.mb_buf_size;
-
-            next_initrd = strchr(initrd_filename, ',');
-            if (next_initrd)
-                *next_initrd = '\0';
-            /* if a space comes after the module filename, treat everything
-               after that as parameters */
-            uint32_t c = mb_add_cmdline(&mbs, initrd_filename);
-            if ((next_space = strchr(initrd_filename, ' ')))
-                *next_space = '\0';
-            mb_debug("multiboot loading module: %s\n", initrd_filename);
-            mb_mod_length = get_image_size(initrd_filename);
-            if (mb_mod_length < 0) {
-                fprintf(stderr, "failed to get %s image size\n", initrd_filename);
-                exit(1);
-            }
-
-            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
-            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
-
-            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
-            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
-                       mbs.mb_buf_phys + offs + mb_mod_length, c);
-
-            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
-                     (char *)mbs.mb_buf + offs,
-                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
-            initrd_filename = next_initrd+1;
-        } while (next_initrd);
-    }
-
-    /* Commandline support */
-    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
-    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
-             kernel_filename, kernel_cmdline);
-    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
-
-    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
-    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
-
-    /* the kernel is where we want it to be now */
-    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
-                                | MULTIBOOT_FLAGS_BOOT_DEVICE
-                                | MULTIBOOT_FLAGS_CMDLINE
-                                | MULTIBOOT_FLAGS_MODULES
-                                | MULTIBOOT_FLAGS_MMAP);
-    stl_p(bootinfo + MBI_MEM_LOWER,   640);
-    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
-    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
-    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
-
-    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
-    mb_debug("           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
-    mb_debug("           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
-    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
-
-    /* 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_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, mbs.mb_buf_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
-                     mbs.mb_buf, mbs.mb_buf_size);
-
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
-    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++;
-
-    return 1; /* yes, we are multiboot */
-}
-
 static void load_linux(void *fw_cfg,
                        const char *kernel_filename,
 		       const char *initrd_filename,
@@ -826,8 +540,8 @@ static void load_linux(void *fw_cfg,
     else {
 	/* This looks like a multiboot kernel. If it is, let's stop
 	   treating it like a Linux kernel. */
-	if (load_multiboot(fw_cfg, f, kernel_filename,
-                           initrd_filename, kernel_cmdline, header))
+	if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
+	                   kernel_cmdline, kernel_size, header))
             return;
 	protocol = 0;
     }
-- 
1.6.5.3


Adam
-- 
Adam                 adam@os.inf.tu-dresden.de
  Lackorzynski         http://os.inf.tu-dresden.de/~adam/

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

* Re: [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file
  2009-12-03 22:23       ` [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file Adam Lackorzynski
@ 2009-12-03 23:20         ` Alexander Graf
  0 siblings, 0 replies; 10+ messages in thread
From: Alexander Graf @ 2009-12-03 23:20 UTC (permalink / raw)
  To: Adam Lackorzynski; +Cc: qemu-devel


On 03.12.2009, at 23:23, Adam Lackorzynski wrote:

> multiboot: Separate multiboot loading into separate file
> 
> Move multiboot loading functionality to a separate file as suggested by
> Alex Graf.

Awesome, thanks!

Looks good to me. The code could use some cleanup (magic numbers), but we should keep that for later ;-). 


Alex

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

* [Qemu-devel] Re: [PATCH 1/2] multiboot: Support arbitrary number of modules.
  2009-12-03 22:19     ` [Qemu-devel] [PATCH 1/2] " Adam Lackorzynski
  2009-12-03 22:23       ` [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file Adam Lackorzynski
@ 2009-12-03 23:24       ` Anthony Liguori
  2009-12-06 12:52         ` [Qemu-devel] " Adam Lackorzynski
  1 sibling, 1 reply; 10+ messages in thread
From: Anthony Liguori @ 2009-12-03 23:24 UTC (permalink / raw)
  To: Adam Lackorzynski; +Cc: qemu-devel

Adam Lackorzynski wrote:
> multiboot: Support arbitrary number of modules.
>
> Addressed comments by Anthony.
>
> Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
> ---
>  hw/pc.c |  260 ++++++++++++++++++++++++++++++++++++++------------------------
>  1 files changed, 159 insertions(+), 101 deletions(-)
>
> diff --git a/hw/pc.c b/hw/pc.c
> index 8c1b7ea..47d7796 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -51,6 +51,12 @@
>  /* Show multiboot debug output */
>  //#define DEBUG_MULTIBOOT
>  
> +#ifdef DEBUG_MULTIBOOT
> +#define mb_debug(a...) fprintf(stderr, ## a)
> +#else
> +#define mb_debug(a...)
> +#endif
> +
>  #define BIOS_FILENAME "bios.bin"
>  
>  #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
> @@ -512,6 +518,77 @@ static long get_file_size(FILE *f)
>  #error multiboot struct needs to fit in 16 bit real mode
>  #endif
>  
> +enum {
> +    /* Multiboot info */
> +    MBI_FLAGS       = 0,
> +    MBI_MEM_LOWER   = 4,
> +    MBI_MEM_UPPER   = 8,
> +    MBI_BOOT_DEVICE = 12,
> +    MBI_CMDLINE     = 16,
> +    MBI_MODS_COUNT  = 20,
> +    MBI_MODS_ADDR   = 24,
> +    MBI_MMAP_ADDR   = 48,
> +
> +    MBI_SIZE        = 88,
> +
> +    /* Multiboot modules */
> +    MB_MOD_START    = 0,
> +    MB_MOD_END      = 4,
> +    MB_MOD_CMDLINE  = 8,
> +
> +    MB_MOD_SIZE     = 16,
> +
> +    /* Region offsets */
> +    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
> +    ADDR_MBI      = ADDR_E820_MAP + 0x500,
> +
> +    /* Multiboot flags */
> +    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
> +    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
> +    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
> +    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
> +    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
> +};
> +
> +struct MultibootState {
> +    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
> +    uint32_t mb_buf_phys; /* address in target */
> +    int mb_buf_size;      /* size of mb_buf in bytes */
> +    int mb_mods_avail;    /* available slots for mb modules infos */
> +    int mb_mods_count;    /* currently used slots of mb modules */
> +    int offset_mbinfo;    /* offset of mb-info's in bytes */
> +    int offset_cmdlines;  /* offset in buffer for cmdlines */
> +    int offset_mods;      /* offset of modules in bytes */
> +};
>   

Should be typedef struct MultibootState.  See CODING_STYLE.  Also, 
shouldn't these offsets be something other than int?  Does multiboot 
always load in 32-bit mode (never 64-bit mode?).

mb_buf_phys should not be a u32.  It should be a target address type.

-- 
Regards,

Anthony Liguori

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

* [Qemu-devel] [PATCH 1/2] multiboot: Support arbitrary number of modules.
  2009-12-03 23:24       ` [Qemu-devel] Re: [PATCH 1/2] multiboot: Support arbitrary number of modules Anthony Liguori
@ 2009-12-06 12:52         ` Adam Lackorzynski
  2009-12-06 12:53           ` [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file Adam Lackorzynski
  0 siblings, 1 reply; 10+ messages in thread
From: Adam Lackorzynski @ 2009-12-06 12:52 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel


On Thu Dec 03, 2009 at 17:24:59 -0600, Anthony Liguori wrote:
> >+struct MultibootState {
> >+    void *mb_buf;         /* buffer holding kernel, cmdlines and mb_infos */
> >+    uint32_t mb_buf_phys; /* address in target */
> >+    int mb_buf_size;      /* size of mb_buf in bytes */
> >+    int mb_mods_avail;    /* available slots for mb modules infos */
> >+    int mb_mods_count;    /* currently used slots of mb modules */
> >+    int offset_mbinfo;    /* offset of mb-info's in bytes */
> >+    int offset_cmdlines;  /* offset in buffer for cmdlines */
> >+    int offset_mods;      /* offset of modules in bytes */
> >+};
> 
> Should be typedef struct MultibootState.  See CODING_STYLE.  Also,
> shouldn't these offsets be something other than int?  Does multiboot
> always load in 32-bit mode (never 64-bit mode?).
> 
> mb_buf_phys should not be a u32.  It should be a target address type.

The spec defines all values as u32 but since the offsets are relative to
mb_buf_phys I've made them of type target_phys_addr_t too.


Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
---
 hw/pc.c |  268 +++++++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 167 insertions(+), 101 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 8c1b7ea..44f3193 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -51,6 +51,12 @@
 /* Show multiboot debug output */
 //#define DEBUG_MULTIBOOT
 
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## a)
+#else
+#define mb_debug(a...)
+#endif
+
 #define BIOS_FILENAME "bios.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -512,6 +518,85 @@ static long get_file_size(FILE *f)
 #error multiboot struct needs to fit in 16 bit real mode
 #endif
 
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+typedef struct {
+    /* buffer holding kernel, cmdlines and mb_infos */
+    void *mb_buf;
+    /* address in target */
+    target_phys_addr_t mb_buf_phys;
+    /* size of mb_buf in bytes */
+    unsigned mb_buf_size;
+    /* offset of mb-info's in bytes */
+    target_phys_addr_t offset_mbinfo;
+    /* offset in buffer for cmdlines in bytes */
+    target_phys_addr_t offset_cmdlines;
+    /* offset of modules in bytes */
+    target_phys_addr_t offset_mods;
+    /* available slots for mb modules infos */
+    int mb_mods_avail;
+    /* currently used slots of mb modules */
+    int mb_mods_count;
+} MultibootState;
+
+static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
+{
+    int len = strlen(cmdline) + 1;
+    target_phys_addr_t p = s->offset_cmdlines;
+
+    pstrcpy((char *)s->mb_buf + p, len, cmdline);
+    s->offset_cmdlines += len;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(MultibootState *s,
+                       target_phys_addr_t start, target_phys_addr_t end,
+                       target_phys_addr_t cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+    mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
+
+    s->mb_mods_count++;
+}
+
 static int load_multiboot(void *fw_cfg,
                           FILE *f,
                           const char *kernel_filename,
@@ -524,12 +609,8 @@ static int load_multiboot(void *fw_cfg,
     uint32_t mh_entry_addr;
     uint32_t mh_load_addr;
     uint32_t mb_kernel_size;
-    uint32_t mmap_addr = MULTIBOOT_STRUCT_ADDR;
-    uint32_t mb_bootinfo = MULTIBOOT_STRUCT_ADDR + 0x500;
-    uint32_t mb_mod_end;
-    uint8_t bootinfo[0x500];
-    uint32_t cmdline = 0x200;
-    uint8_t *mb_kernel_data;
+    MultibootState mbs;
+    uint8_t bootinfo[MBI_SIZE];
     uint8_t *mb_bootinfo_data;
 
     /* Ok, let's see if it is a multiboot image.
@@ -550,10 +631,9 @@ static int load_multiboot(void *fw_cfg,
     if (!is_multiboot)
         return 0; /* no multiboot */
 
-#ifdef DEBUG_MULTIBOOT
-    fprintf(stderr, "qemu: I believe we found a multiboot image!\n");
-#endif
+    mb_debug("qemu: I believe we found a multiboot image!\n");
     memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
 
     if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
         fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
@@ -571,24 +651,18 @@ 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) {
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, 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);
-#endif
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                  mb_kernel_size, (size_t)mh_entry_addr);
     } else {
         /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
         uint32_t mh_header_addr = ldl_p(header+i+12);
         mh_load_addr = ldl_p(header+i+16);
-#ifdef DEBUG_MULTIBOOT
-        uint32_t mh_load_end_addr = ldl_p(header+i+20);
-        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);
 
         mh_entry_addr = ldl_p(header+i+28);
@@ -600,115 +674,107 @@ static int load_multiboot(void *fw_cfg,
         uint32_t mh_height = ldl_p(header+i+40);
         uint32_t mh_depth = ldl_p(header+i+44); */
 
-#ifdef DEBUG_MULTIBOOT
-        fprintf(stderr, "multiboot: mh_header_addr = %#x\n", mh_header_addr);
-        fprintf(stderr, "multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        fprintf(stderr, "multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
-        fprintf(stderr, "multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
-        fprintf(stderr, "qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                mb_kernel_size, mh_load_addr);
-#endif
+        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+                 mb_kernel_size, mh_load_addr);
 
-        mb_kernel_data = qemu_malloc(mb_kernel_size);
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
         fseek(f, mb_kernel_text_offset, SEEK_SET);
-        fread(mb_kernel_data, 1, mb_kernel_size, f);
+        fread(mbs.mb_buf, 1, mb_kernel_size, f);
         fclose(f);
     }
 
-    /* blob size is only the kernel for now */
-    mb_mod_end = mh_load_addr + mb_kernel_size;
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while ((r = strchr(r, ','))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    /* enlarge mb_buf to hold cmdlines and mb-info structs */
+    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
 
-    /* load modules */
-    stl_p(bootinfo + 20, 0x0); /* mods_count */
     if (initrd_filename) {
-        uint32_t mb_mod_info = 0x100;
-        uint32_t mb_mod_cmdline = 0x300;
-        uint32_t mb_mod_start = mh_load_addr;
-        uint32_t mb_mod_length = mb_kernel_size;
         char *next_initrd;
-        char *next_space;
-        int mb_mod_count = 0;
+
+        mbs.offset_mods = mbs.mb_buf_size;
 
         do {
-            if (mb_mod_info + 16 > mb_mod_cmdline) {
-                printf("WARNING: Too many modules loaded, aborting.\n");
-                break;
-            }
+            char *next_space;
+            uint32_t mb_mod_length;
+            uint32_t offs = mbs.mb_buf_size;
 
             next_initrd = strchr(initrd_filename, ',');
             if (next_initrd)
                 *next_initrd = '\0';
             /* if a space comes after the module filename, treat everything
                after that as parameters */
-            pstrcpy((char*)bootinfo + mb_mod_cmdline,
-                    sizeof(bootinfo) - mb_mod_cmdline,
-                    initrd_filename);
-            stl_p(bootinfo + mb_mod_info + 8, mb_bootinfo + mb_mod_cmdline); /* string */
-            mb_mod_cmdline += strlen(initrd_filename) + 1;
-            if (mb_mod_cmdline > sizeof(bootinfo)) {
-                mb_mod_cmdline = sizeof(bootinfo);
-                printf("WARNING: Too many module cmdlines loaded, aborting.\n");
-                break;
-            }
+            target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
             if ((next_space = strchr(initrd_filename, ' ')))
                 *next_space = '\0';
-#ifdef DEBUG_MULTIBOOT
-            printf("multiboot loading module: %s\n", initrd_filename);
-#endif
-            mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1))
-                         & (TARGET_PAGE_MASK);
+            mb_debug("multiboot loading module: %s\n", initrd_filename);
             mb_mod_length = get_image_size(initrd_filename);
             if (mb_mod_length < 0) {
                 fprintf(stderr, "failed to get %s image size\n", initrd_filename);
                 exit(1);
             }
-            mb_mod_end = mb_mod_start + mb_mod_length;
-            mb_mod_count++;
-
-            /* append module data at the end of last module */
-            mb_kernel_data = qemu_realloc(mb_kernel_data,
-                                          mb_mod_end - mh_load_addr);
-            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 */
-#ifdef DEBUG_MULTIBOOT
-            printf("mod_start: %#x\nmod_end:   %#x\n", mb_mod_start,
-                   mb_mod_start + mb_mod_length);
-#endif
+
+            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
+            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
+                     (char *)mbs.mb_buf + offs,
+                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
             initrd_filename = next_initrd+1;
-            mb_mod_info += 16;
         } while (next_initrd);
-        stl_p(bootinfo + 20, mb_mod_count); /* mods_count */
-        stl_p(bootinfo + 24, mb_bootinfo + 0x100); /* mods_addr */
     }
 
     /* Commandline support */
-    stl_p(bootinfo + 16, mb_bootinfo + cmdline);
-    snprintf((char*)bootinfo + cmdline, 0x100, "%s %s",
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
              kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
 
-    /* the kernel is where we want it to be now */
-#define MULTIBOOT_FLAGS_MEMORY (1 << 0)
-#define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1)
-#define MULTIBOOT_FLAGS_CMDLINE (1 << 2)
-#define MULTIBOOT_FLAGS_MODULES (1 << 3)
-#define MULTIBOOT_FLAGS_MMAP (1 << 6)
-    stl_p(bootinfo, MULTIBOOT_FLAGS_MEMORY
-                  | MULTIBOOT_FLAGS_BOOT_DEVICE
-                  | MULTIBOOT_FLAGS_CMDLINE
-                  | MULTIBOOT_FLAGS_MODULES
-                  | MULTIBOOT_FLAGS_MMAP);
-    stl_p(bootinfo + 4, 640); /* mem_lower */
-    stl_p(bootinfo + 8, ram_size / 1024); /* mem_upper */
-    stl_p(bootinfo + 12, 0x8001ffff); /* XXX: use the -boot switch? */
-    stl_p(bootinfo + 48, mmap_addr); /* mmap_addr */
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
 
-#ifdef DEBUG_MULTIBOOT
-    fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
-#endif
+    /* the kernel is where we want it to be now */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
+
+    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    mb_debug("           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
+    mb_debug("           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
+    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
 
     /* save bootinfo off the stack */
     mb_bootinfo_data = qemu_malloc(sizeof(bootinfo));
@@ -717,11 +783,11 @@ static int load_multiboot(void *fw_cfg,
     /* Pass variables to option rom */
     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);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+                     mbs.mb_buf, mbs.mb_buf_size);
 
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
     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));
-- 
1.6.5.3




Adam
-- 
Adam                 adam@os.inf.tu-dresden.de
  Lackorzynski         http://os.inf.tu-dresden.de/~adam/

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

* [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file
  2009-12-06 12:52         ` [Qemu-devel] " Adam Lackorzynski
@ 2009-12-06 12:53           ` Adam Lackorzynski
  0 siblings, 0 replies; 10+ messages in thread
From: Adam Lackorzynski @ 2009-12-06 12:53 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel


Move multiboot loading code into a separate files as suggested by Alex Graf.

Signed-off-by: Adam Lackorzynski <adam@os.inf.tu-dresden.de>
---
 Makefile.target |    2 +-
 hw/multiboot.c  |  326 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/multiboot.h  |   12 ++
 hw/pc.c         |  300 +--------------------------------------------------
 4 files changed, 342 insertions(+), 298 deletions(-)
 create mode 100644 hw/multiboot.c
 create mode 100644 hw/multiboot.h

diff --git a/Makefile.target b/Makefile.target
index 7c1f30c..7f3e497 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -194,7 +194,7 @@ obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
 obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
 obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
-obj-i386-y += ne2000-isa.o
+obj-i386-y += ne2000-isa.o multiboot.o
 
 # shared objects
 obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
diff --git a/hw/multiboot.c b/hw/multiboot.c
new file mode 100644
index 0000000..04d224e
--- /dev/null
+++ b/hw/multiboot.c
@@ -0,0 +1,326 @@
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "fw_cfg.h"
+#include "multiboot.h"
+#include "loader.h"
+#include "elf.h"
+#include "sysemu.h"
+
+/* Show multiboot debug output */
+//#define DEBUG_MULTIBOOT
+
+#ifdef DEBUG_MULTIBOOT
+#define mb_debug(a...) fprintf(stderr, ## a)
+#else
+#define mb_debug(a...)
+#endif
+
+#define MULTIBOOT_STRUCT_ADDR 0x9000
+
+#if MULTIBOOT_STRUCT_ADDR > 0xf0000
+#error multiboot struct needs to fit in 16 bit real mode
+#endif
+
+enum {
+    /* Multiboot info */
+    MBI_FLAGS       = 0,
+    MBI_MEM_LOWER   = 4,
+    MBI_MEM_UPPER   = 8,
+    MBI_BOOT_DEVICE = 12,
+    MBI_CMDLINE     = 16,
+    MBI_MODS_COUNT  = 20,
+    MBI_MODS_ADDR   = 24,
+    MBI_MMAP_ADDR   = 48,
+
+    MBI_SIZE        = 88,
+
+    /* Multiboot modules */
+    MB_MOD_START    = 0,
+    MB_MOD_END      = 4,
+    MB_MOD_CMDLINE  = 8,
+
+    MB_MOD_SIZE     = 16,
+
+    /* Region offsets */
+    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
+    ADDR_MBI      = ADDR_E820_MAP + 0x500,
+
+    /* Multiboot flags */
+    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
+    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
+    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
+    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
+    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
+};
+
+typedef struct {
+    /* buffer holding kernel, cmdlines and mb_infos */
+    void *mb_buf;
+    /* address in target */
+    target_phys_addr_t mb_buf_phys;
+    /* size of mb_buf in bytes */
+    unsigned mb_buf_size;
+    /* offset of mb-info's in bytes */
+    target_phys_addr_t offset_mbinfo;
+    /* offset in buffer for cmdlines in bytes */
+    target_phys_addr_t offset_cmdlines;
+    /* offset of modules in bytes */
+    target_phys_addr_t offset_mods;
+    /* available slots for mb modules infos */
+    int mb_mods_avail;
+    /* currently used slots of mb modules */
+    int mb_mods_count;
+} MultibootState;
+
+static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
+{
+    int len = strlen(cmdline) + 1;
+    target_phys_addr_t p = s->offset_cmdlines;
+
+    pstrcpy((char *)s->mb_buf + p, len, cmdline);
+    s->offset_cmdlines += len;
+    return s->mb_buf_phys + p;
+}
+
+static void mb_add_mod(MultibootState *s,
+                       target_phys_addr_t start, target_phys_addr_t end,
+                       target_phys_addr_t cmdline_phys)
+{
+    char *p;
+    assert(s->mb_mods_count < s->mb_mods_avail);
+
+    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
+
+    stl_p(p + MB_MOD_START,   start);
+    stl_p(p + MB_MOD_END,     end);
+    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+
+    mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
+
+    s->mb_mods_count++;
+}
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header)
+{
+    int i, is_multiboot = 0;
+    uint32_t flags = 0;
+    uint32_t mh_entry_addr;
+    uint32_t mh_load_addr;
+    uint32_t mb_kernel_size;
+    MultibootState mbs;
+    uint8_t bootinfo[MBI_SIZE];
+    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. */
+    for (i = 0; i < (8192 - 48); i += 4) {
+        if (ldl_p(header+i) == 0x1BADB002) {
+            uint32_t checksum = ldl_p(header+i+8);
+            flags = ldl_p(header+i+4);
+            checksum += flags;
+            checksum += (uint32_t)0x1BADB002;
+            if (!checksum) {
+                is_multiboot = 1;
+                break;
+            }
+        }
+    }
+
+    if (!is_multiboot)
+        return 0; /* no multiboot */
+
+    mb_debug("qemu: I believe we found a multiboot image!\n");
+    memset(bootinfo, 0, sizeof(bootinfo));
+    memset(&mbs, 0, sizeof(mbs));
+
+    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
+        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+    }
+    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
+        uint64_t elf_entry;
+        int kernel_size;
+        fclose(f);
+        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+                               0, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            fprintf(stderr, "Error while loading elf kernel\n");
+            exit(1);
+        }
+        mh_load_addr = mh_entry_addr = elf_entry;
+        mb_kernel_size = kernel_size;
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        if (rom_copy(mbs.mb_buf, elf_entry, kernel_size) != kernel_size) {
+            fprintf(stderr, "Error while fetching elf kernel from rom\n");
+            exit(1);
+        }
+
+        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
+                  mb_kernel_size, (size_t)mh_entry_addr);
+    } else {
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
+        uint32_t mh_header_addr = ldl_p(header+i+12);
+        mh_load_addr = ldl_p(header+i+16);
+        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+
+        mh_entry_addr = ldl_p(header+i+28);
+        mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+
+        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
+        uint32_t mh_mode_type = ldl_p(header+i+32);
+        uint32_t mh_width = ldl_p(header+i+36);
+        uint32_t mh_height = ldl_p(header+i+40);
+        uint32_t mh_depth = ldl_p(header+i+44); */
+
+        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
+        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
+        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
+        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+                 mb_kernel_size, mh_load_addr);
+
+        mbs.mb_buf = qemu_malloc(mb_kernel_size);
+        fseek(f, mb_kernel_text_offset, SEEK_SET);
+        fread(mbs.mb_buf, 1, mb_kernel_size, f);
+        fclose(f);
+    }
+
+    mbs.mb_buf_phys = mh_load_addr;
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
+    mbs.offset_mbinfo = mbs.mb_buf_size;
+
+    /* Calculate space for cmdlines and mb_mods */
+    mbs.mb_buf_size += strlen(kernel_filename) + 1;
+    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
+    if (initrd_filename) {
+        const char *r = initrd_filename;
+        mbs.mb_buf_size += strlen(r) + 1;
+        mbs.mb_mods_avail = 1;
+        while ((r = strchr(r, ','))) {
+           mbs.mb_mods_avail++;
+           r++;
+        }
+        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
+    }
+
+    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
+
+    /* enlarge mb_buf to hold cmdlines and mb-info structs */
+    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
+
+    if (initrd_filename) {
+        char *next_initrd;
+
+        mbs.offset_mods = mbs.mb_buf_size;
+
+        do {
+            char *next_space;
+            uint32_t mb_mod_length;
+            uint32_t offs = mbs.mb_buf_size;
+
+            next_initrd = strchr(initrd_filename, ',');
+            if (next_initrd)
+                *next_initrd = '\0';
+            /* if a space comes after the module filename, treat everything
+               after that as parameters */
+            target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
+            if ((next_space = strchr(initrd_filename, ' ')))
+                *next_space = '\0';
+            mb_debug("multiboot loading module: %s\n", initrd_filename);
+            mb_mod_length = get_image_size(initrd_filename);
+            if (mb_mod_length < 0) {
+                fprintf(stderr, "failed to get %s image size\n", initrd_filename);
+                exit(1);
+            }
+
+            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
+            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
+
+            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
+            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
+                       mbs.mb_buf_phys + offs + mb_mod_length, c);
+
+            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
+                     (char *)mbs.mb_buf + offs,
+                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
+            initrd_filename = next_initrd+1;
+        } while (next_initrd);
+    }
+
+    /* Commandline support */
+    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
+    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
+             kernel_filename, kernel_cmdline);
+    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+
+    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
+    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
+
+    /* the kernel is where we want it to be now */
+    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+                                | MULTIBOOT_FLAGS_BOOT_DEVICE
+                                | MULTIBOOT_FLAGS_CMDLINE
+                                | MULTIBOOT_FLAGS_MODULES
+                                | MULTIBOOT_FLAGS_MMAP);
+    stl_p(bootinfo + MBI_MEM_LOWER,   640);
+    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
+    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
+
+    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
+    mb_debug("           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
+    mb_debug("           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
+    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
+
+    /* 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_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, mbs.mb_buf_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
+                     mbs.mb_buf, mbs.mb_buf_size);
+
+    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
+    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++;
+
+    return 1; /* yes, we are multiboot */
+}
diff --git a/hw/multiboot.h b/hw/multiboot.h
new file mode 100644
index 0000000..98fb1b7
--- /dev/null
+++ b/hw/multiboot.h
@@ -0,0 +1,12 @@
+#ifndef QEMU_MULTIBOOT_H
+#define QEMU_MULTIBOOT_H
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header);
+
+#endif
diff --git a/hw/pc.c b/hw/pc.c
index 44f3193..b058acc 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -44,19 +44,11 @@
 #include "ide.h"
 #include "loader.h"
 #include "elf.h"
+#include "multiboot.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
 
-/* Show multiboot debug output */
-//#define DEBUG_MULTIBOOT
-
-#ifdef DEBUG_MULTIBOOT
-#define mb_debug(a...) fprintf(stderr, ## a)
-#else
-#define mb_debug(a...)
-#endif
-
 #define BIOS_FILENAME "bios.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -512,292 +504,6 @@ static long get_file_size(FILE *f)
     return size;
 }
 
-#define MULTIBOOT_STRUCT_ADDR 0x9000
-
-#if MULTIBOOT_STRUCT_ADDR > 0xf0000
-#error multiboot struct needs to fit in 16 bit real mode
-#endif
-
-enum {
-    /* Multiboot info */
-    MBI_FLAGS       = 0,
-    MBI_MEM_LOWER   = 4,
-    MBI_MEM_UPPER   = 8,
-    MBI_BOOT_DEVICE = 12,
-    MBI_CMDLINE     = 16,
-    MBI_MODS_COUNT  = 20,
-    MBI_MODS_ADDR   = 24,
-    MBI_MMAP_ADDR   = 48,
-
-    MBI_SIZE        = 88,
-
-    /* Multiboot modules */
-    MB_MOD_START    = 0,
-    MB_MOD_END      = 4,
-    MB_MOD_CMDLINE  = 8,
-
-    MB_MOD_SIZE     = 16,
-
-    /* Region offsets */
-    ADDR_E820_MAP = MULTIBOOT_STRUCT_ADDR + 0,
-    ADDR_MBI      = ADDR_E820_MAP + 0x500,
-
-    /* Multiboot flags */
-    MULTIBOOT_FLAGS_MEMORY      = 1 << 0,
-    MULTIBOOT_FLAGS_BOOT_DEVICE = 1 << 1,
-    MULTIBOOT_FLAGS_CMDLINE     = 1 << 2,
-    MULTIBOOT_FLAGS_MODULES     = 1 << 3,
-    MULTIBOOT_FLAGS_MMAP        = 1 << 6,
-};
-
-typedef struct {
-    /* buffer holding kernel, cmdlines and mb_infos */
-    void *mb_buf;
-    /* address in target */
-    target_phys_addr_t mb_buf_phys;
-    /* size of mb_buf in bytes */
-    unsigned mb_buf_size;
-    /* offset of mb-info's in bytes */
-    target_phys_addr_t offset_mbinfo;
-    /* offset in buffer for cmdlines in bytes */
-    target_phys_addr_t offset_cmdlines;
-    /* offset of modules in bytes */
-    target_phys_addr_t offset_mods;
-    /* available slots for mb modules infos */
-    int mb_mods_avail;
-    /* currently used slots of mb modules */
-    int mb_mods_count;
-} MultibootState;
-
-static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
-{
-    int len = strlen(cmdline) + 1;
-    target_phys_addr_t p = s->offset_cmdlines;
-
-    pstrcpy((char *)s->mb_buf + p, len, cmdline);
-    s->offset_cmdlines += len;
-    return s->mb_buf_phys + p;
-}
-
-static void mb_add_mod(MultibootState *s,
-                       target_phys_addr_t start, target_phys_addr_t end,
-                       target_phys_addr_t cmdline_phys)
-{
-    char *p;
-    assert(s->mb_mods_count < s->mb_mods_avail);
-
-    p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
-
-    stl_p(p + MB_MOD_START,   start);
-    stl_p(p + MB_MOD_END,     end);
-    stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
-
-    mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
-
-    s->mb_mods_count++;
-}
-
-static int load_multiboot(void *fw_cfg,
-                          FILE *f,
-                          const char *kernel_filename,
-                          const char *initrd_filename,
-                          const char *kernel_cmdline,
-                          uint8_t *header)
-{
-    int i, is_multiboot = 0;
-    uint32_t flags = 0;
-    uint32_t mh_entry_addr;
-    uint32_t mh_load_addr;
-    uint32_t mb_kernel_size;
-    MultibootState mbs;
-    uint8_t bootinfo[MBI_SIZE];
-    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. */
-    for (i = 0; i < (8192 - 48); i += 4) {
-        if (ldl_p(header+i) == 0x1BADB002) {
-            uint32_t checksum = ldl_p(header+i+8);
-            flags = ldl_p(header+i+4);
-            checksum += flags;
-            checksum += (uint32_t)0x1BADB002;
-            if (!checksum) {
-                is_multiboot = 1;
-                break;
-            }
-        }
-    }
-
-    if (!is_multiboot)
-        return 0; /* no multiboot */
-
-    mb_debug("qemu: I believe we found a multiboot image!\n");
-    memset(bootinfo, 0, sizeof(bootinfo));
-    memset(&mbs, 0, sizeof(mbs));
-
-    if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
-        fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
-    }
-    if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
-        uint64_t elf_entry;
-        int kernel_size;
-        fclose(f);
-        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
-                               0, ELF_MACHINE, 0);
-        if (kernel_size < 0) {
-            fprintf(stderr, "Error while loading elf kernel\n");
-            exit(1);
-        }
-        mh_load_addr = mh_entry_addr = elf_entry;
-        mb_kernel_size = kernel_size;
-
-        mbs.mb_buf = qemu_malloc(mb_kernel_size);
-        if (rom_copy(mbs.mb_buf, elf_entry, kernel_size) != kernel_size) {
-            fprintf(stderr, "Error while fetching elf kernel from rom\n");
-            exit(1);
-        }
-
-        mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
-                  mb_kernel_size, (size_t)mh_entry_addr);
-    } else {
-        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
-        uint32_t mh_header_addr = ldl_p(header+i+12);
-        mh_load_addr = ldl_p(header+i+16);
-        uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
-
-        mh_entry_addr = ldl_p(header+i+28);
-        mb_kernel_size = get_file_size(f) - mb_kernel_text_offset;
-
-        /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
-        uint32_t mh_mode_type = ldl_p(header+i+32);
-        uint32_t mh_width = ldl_p(header+i+36);
-        uint32_t mh_height = ldl_p(header+i+40);
-        uint32_t mh_depth = ldl_p(header+i+44); */
-
-        mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
-        mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
-        mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
-        mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
-        mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
-                 mb_kernel_size, mh_load_addr);
-
-        mbs.mb_buf = qemu_malloc(mb_kernel_size);
-        fseek(f, mb_kernel_text_offset, SEEK_SET);
-        fread(mbs.mb_buf, 1, mb_kernel_size, f);
-        fclose(f);
-    }
-
-    mbs.mb_buf_phys = mh_load_addr;
-
-    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_kernel_size);
-    mbs.offset_mbinfo = mbs.mb_buf_size;
-
-    /* Calculate space for cmdlines and mb_mods */
-    mbs.mb_buf_size += strlen(kernel_filename) + 1;
-    mbs.mb_buf_size += strlen(kernel_cmdline) + 1;
-    if (initrd_filename) {
-        const char *r = initrd_filename;
-        mbs.mb_buf_size += strlen(r) + 1;
-        mbs.mb_mods_avail = 1;
-        while ((r = strchr(r, ','))) {
-           mbs.mb_mods_avail++;
-           r++;
-        }
-        mbs.mb_buf_size += MB_MOD_SIZE * mbs.mb_mods_avail;
-    }
-
-    mbs.mb_buf_size = TARGET_PAGE_ALIGN(mbs.mb_buf_size);
-
-    /* enlarge mb_buf to hold cmdlines and mb-info structs */
-    mbs.mb_buf          = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
-    mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
-
-    if (initrd_filename) {
-        char *next_initrd;
-
-        mbs.offset_mods = mbs.mb_buf_size;
-
-        do {
-            char *next_space;
-            uint32_t mb_mod_length;
-            uint32_t offs = mbs.mb_buf_size;
-
-            next_initrd = strchr(initrd_filename, ',');
-            if (next_initrd)
-                *next_initrd = '\0';
-            /* if a space comes after the module filename, treat everything
-               after that as parameters */
-            target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
-            if ((next_space = strchr(initrd_filename, ' ')))
-                *next_space = '\0';
-            mb_debug("multiboot loading module: %s\n", initrd_filename);
-            mb_mod_length = get_image_size(initrd_filename);
-            if (mb_mod_length < 0) {
-                fprintf(stderr, "failed to get %s image size\n", initrd_filename);
-                exit(1);
-            }
-
-            mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
-            mbs.mb_buf = qemu_realloc(mbs.mb_buf, mbs.mb_buf_size);
-
-            load_image(initrd_filename, (unsigned char *)mbs.mb_buf + offs);
-            mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
-                       mbs.mb_buf_phys + offs + mb_mod_length, c);
-
-            mb_debug("mod_start: %p\nmod_end:   %p\n  cmdline: %#x\n",
-                     (char *)mbs.mb_buf + offs,
-                     (char *)mbs.mb_buf + offs + mb_mod_length, c);
-            initrd_filename = next_initrd+1;
-        } while (next_initrd);
-    }
-
-    /* Commandline support */
-    char kcmdline[strlen(kernel_filename) + strlen(kernel_cmdline) + 2];
-    snprintf(kcmdline, sizeof(kcmdline), "%s %s",
-             kernel_filename, kernel_cmdline);
-    stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
-
-    stl_p(bootinfo + MBI_MODS_ADDR,  mbs.mb_buf_phys + mbs.offset_mbinfo);
-    stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
-
-    /* the kernel is where we want it to be now */
-    stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
-                                | MULTIBOOT_FLAGS_BOOT_DEVICE
-                                | MULTIBOOT_FLAGS_CMDLINE
-                                | MULTIBOOT_FLAGS_MODULES
-                                | MULTIBOOT_FLAGS_MMAP);
-    stl_p(bootinfo + MBI_MEM_LOWER,   640);
-    stl_p(bootinfo + MBI_MEM_UPPER,   ram_size / 1024);
-    stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
-    stl_p(bootinfo + MBI_MMAP_ADDR,   ADDR_E820_MAP);
-
-    mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
-    mb_debug("           mb_buf_phys   = %x\n", mbs.mb_buf_phys);
-    mb_debug("           mod_start     = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
-    mb_debug("           mb_mods_count = %d\n", mbs.mb_mods_count);
-
-    /* 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_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, mbs.mb_buf_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA,
-                     mbs.mb_buf, mbs.mb_buf_size);
-
-    fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, ADDR_MBI);
-    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++;
-
-    return 1; /* yes, we are multiboot */
-}
-
 static void load_linux(void *fw_cfg,
                        const char *kernel_filename,
 		       const char *initrd_filename,
@@ -834,8 +540,8 @@ static void load_linux(void *fw_cfg,
     else {
 	/* This looks like a multiboot kernel. If it is, let's stop
 	   treating it like a Linux kernel. */
-	if (load_multiboot(fw_cfg, f, kernel_filename,
-                           initrd_filename, kernel_cmdline, header))
+        if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename,
+                           kernel_cmdline, kernel_size, header))
             return;
 	protocol = 0;
     }
-- 
1.6.5.3


Adam
-- 
Adam                 adam@os.inf.tu-dresden.de
  Lackorzynski         http://os.inf.tu-dresden.de/~adam/

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

end of thread, other threads:[~2009-12-06 12:54 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-30 22:25 [Qemu-devel] [PATCH 1/2] multiboot: Fix module loading and setting of mmap Adam Lackorzynski
2009-11-30 22:26 ` [Qemu-devel] [PATCH 2/2] multiboot: Support arbitrary number of modules Adam Lackorzynski
2009-12-01  6:51   ` Alexander Graf
2009-12-03 20:26   ` Anthony Liguori
2009-12-03 22:19     ` [Qemu-devel] [PATCH 1/2] " Adam Lackorzynski
2009-12-03 22:23       ` [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file Adam Lackorzynski
2009-12-03 23:20         ` Alexander Graf
2009-12-03 23:24       ` [Qemu-devel] Re: [PATCH 1/2] multiboot: Support arbitrary number of modules Anthony Liguori
2009-12-06 12:52         ` [Qemu-devel] " Adam Lackorzynski
2009-12-06 12:53           ` [Qemu-devel] [PATCH 2/2] multiboot: Separate multiboot loading into separate file Adam Lackorzynski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.