mboot: fix cmdline; a few more layout tweaks
authorH. Peter Anvin <hpa@zytor.com>
Mon, 27 Apr 2009 02:29:33 +0000 (19:29 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 27 Apr 2009 02:29:33 +0000 (19:29 -0700)
Fix module command lines (it was overwriting the main kernel command
line); a few minor layout tweaks.  In particular, we require the
section header to be page-aligned, but not the subsequent sections.

With this, I can get Xen to boot.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
com32/mboot/map.c
com32/mboot/mboot.c
com32/mboot/mboot.h
com32/mboot/mem.c

index d872d90..b134a55 100644 (file)
@@ -37,7 +37,7 @@
 static struct syslinux_movelist *ml = NULL;
 static struct syslinux_memmap *mmap = NULL, *amap = NULL;
 static struct multiboot_header *mbh;
-static addr_t mboot_high_water_mark = 0;
+static addr_t mboot_high_water_mark = 0x100000;
 
 /*
  * Note: although there is no such thing in the spec, at least Xen makes
@@ -48,11 +48,11 @@ static addr_t mboot_high_water_mark = 0;
  * As a precaution, this also pads the data with zero up to the next
  * alignment datum.
  */
-addr_t map_data(const void *data, size_t len, int align, bool high)
+addr_t map_data(const void *data, size_t len, size_t align, int flags)
 {
-  addr_t start = high ? mboot_high_water_mark : 0x800;
-  addr_t pad = -len & (align-1);
-  addr_t xlen = len+pad;
+  addr_t start = (flags & MAP_HIGH) ? mboot_high_water_mark : 0x2000;
+  addr_t pad   = (flags & MAP_NOPAD) ? 0 : -len & (align-1);
+  addr_t xlen  = len+pad;
 
   if (syslinux_memmap_find(amap, SMT_FREE, &start, &xlen, align) ||
       syslinux_add_memmap(&amap, start, len+pad, SMT_ALLOC) ||
@@ -75,7 +75,7 @@ addr_t map_string(const char *string)
   if (!string)
     return 0;
   else
-    return map_data(string, strlen(string)+1, 4, true);
+    return map_data(string, strlen(string)+1, 1, 0);
 }
 
 int map_image(void *ptr, size_t len)
@@ -217,7 +217,11 @@ int map_image(void *ptr, size_t len)
       sh = (Elf32_Shdr *)((char *)eh + eh->e_shoff);
 
       len = eh->e_shentsize * eh->e_shnum;
-      addr = map_data(sh, len, 4096, true);
+      /*
+       * Align this, but don't pad -- in general this means a bunch of
+       * smaller sections gets packed into a single page.
+       */
+      addr = map_data(sh, len, 4096, MAP_HIGH|MAP_NOPAD);
       if (!addr) {
        error("Failed to map symbol table\n");
        goto bail;
@@ -239,7 +243,7 @@ int map_image(void *ptr, size_t len)
 
        align = sh[i].sh_addralign ? sh[i].sh_addralign : 0;
        addr = map_data((char *)ptr + sh[i].sh_offset, sh[i].sh_size,
-                       align, true);
+                       align, MAP_HIGH);
        if (!addr) {
          error("Failed to map symbol section\n");
          goto bail;
index fcde53d..3b42093 100644 (file)
@@ -56,13 +56,21 @@ static int map_modules(struct module_data *modules, int nmodules)
     return -1;
   }
 
+  map_list = map_data(mod_list, list_size, 16, 0);
+  if (!map_list) {
+    printf("Cannot map module list\n");
+    return -1;
+  }
+
   for (i = 0; i < nmodules; i++) {
     addr_t mod_map = 0;
     addr_t cmd_map = 0;
 
+    dprintf("Module %d cmdline: \"%s\"\n", i, modules[i].cmdline);
+
     cmd_map = map_string(modules[i].cmdline);
 
-    mod_map = map_data(modules[i].data, modules[i].len, 4096, true);
+    mod_map = map_data(modules[i].data, modules[i].len, 4096, MAP_HIGH);
     if (!mod_map) {
       printf("Failed to map module (memory fragmentation issue?)\n");
       return -1;
@@ -73,12 +81,6 @@ static int map_modules(struct module_data *modules, int nmodules)
     mod_list[i].pad = 0;
   }
 
-  map_list = map_data(mod_list, list_size, 16, false);
-  if (!map_list) {
-    printf("Cannot map module list\n");
-    return -1;
-  }
-
   mbinfo.flags |= MB_INFO_MODS;
   mbinfo.mods_count = nmodules;
   mbinfo.mods_addr = map_list;
@@ -88,7 +90,7 @@ static int map_modules(struct module_data *modules, int nmodules)
 static int get_modules(char **argv, struct module_data **mdp)
 {
   char **argp, **argx;
-  struct module_data *md, *mp;
+  struct module_data *mp;
   int rv;
   int module_count = 1;
   int arglen;
@@ -99,13 +101,12 @@ static int get_modules(char **argv, struct module_data **mdp)
       module_count++;
   }
 
-  *mdp = md = malloc(module_count * sizeof(struct module_data));
-  if (!md) {
+  *mdp = mp = malloc(module_count * sizeof(struct module_data));
+  if (!mp) {
     error("Out of memory!\n");
     return -1;
   }
 
-  mp = md;
   argp = argv;
   while (*argp) {
     /* Note: it seems Grub transparently decompresses all compressed files,
@@ -125,10 +126,10 @@ static int get_modules(char **argv, struct module_data **mdp)
       arglen += strlen(*argx)+1;
 
     if (arglen == 0) {
-      mp->cmdline = NULL;
+      mp->cmdline = strdup("");
     } else {
       char *p;
-      md->cmdline = p = malloc(arglen);
+      mp->cmdline = p = malloc(arglen);
       for ( ; *argp && strcmp(*argp, module_separator); argp++) {
        p = strpcpy(p, *argp);
        *p++ = ' ';
@@ -170,14 +171,8 @@ int main(int argc, char *argv[])
   if (map_image(modules[0].data, modules[0].len))
     return 1;
 
-  /* Map auxilliary images */
-  if (nmodules > 1) {
-    if (map_modules(modules+1, nmodules-1))
-      return 1;
-  }
-
   /* Map the mbinfo structure */
-  regs.ebx = map_data(&mbinfo, sizeof mbinfo, 4, false);
+  regs.ebx = map_data(&mbinfo, sizeof mbinfo, 4, 0);
   if (!regs.ebx) {
     error("Failed to map Multiboot info structure!\n");
     return 1;
@@ -186,10 +181,17 @@ int main(int argc, char *argv[])
   /* Map the primary command line */
   if (modules[0].cmdline) {
     mbinfo.cmdline = map_string(modules[0].cmdline);
+    dprintf("Main cmdline: \"%s\"\n", modules[0].cmdline);
     if (mbinfo.cmdline)
       mbinfo.flags |= MB_INFO_CMDLINE;
   }
 
+  /* Map auxilliary images */
+  if (nmodules > 1) {
+    if (map_modules(modules+1, nmodules-1))
+      return 1;
+  }
+
   /* Add auxilliary information */
   mboot_make_memmap();
   mboot_apm();
index bf5d81c..0f33a51 100644 (file)
@@ -71,7 +71,9 @@ extern struct multiboot_info mbinfo;
 extern struct syslinux_pm_regs regs;
 
 /* map.c */
-addr_t map_data(const void *data, size_t len, int align, bool high);
+#define MAP_HIGH       1
+#define MAP_NOPAD      2
+addr_t map_data(const void *data, size_t len, size_t align, int flags);
 addr_t map_string(const char *string);
 int map_image(void *ptr, size_t len);
 void mboot_run(int bootflags);
index ecbf5c1..e9d8bbd 100644 (file)
@@ -206,7 +206,7 @@ void mboot_make_memmap(void)
   mbinfo.mem_upper = (highmem - 0x100000) >> 10;
   mbinfo.flags |= MB_INFO_MEMORY;
 
-  /* XXX: Should this be +4? */
+  /* The spec says this address should be +4, but Grub disagrees */
   mbinfo.mmap_addr = map_data(ard, nmap*sizeof *ard, 4, false);
   if (mbinfo.mmap_addr) {
     mbinfo.mmap_length = nmap*sizeof *ard;