[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [Xen-devel] RFC/Patch: Support for other bootloaders



Here's a revised patch.

I've eliminated support for trying to combine two modules into one
loadable image.  As per previous  discussions, I think in these
circumstances if a ramdisk is required it is adequate for it to be
built-in to the dom0 image (e.g. embedded initramfs).

Also included the agreed-upon cmdline hack, and SMP booting has been
verified and fixed.

(Not "signed-off" because I don't think it is ready just yet.)

-- 
Michal Ostrowski <mostrows@xxxxxxxxxxxxxx>


# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/24 09:19:31-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx 
#   Support for non-grub boot-loaders.
# 
# BitKeeper/etc/logging_ok
#   2005/03/24 09:19:31-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +1 -0
#   Logging to logging@xxxxxxxxxxxxxxx accepted
# 
# xen/arch/x86/mkzen
#   2005/03/24 09:19:28-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +76 -0
# 
# xen/include/xen/multiboot.h
#   2005/03/24 09:19:28-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +4 -0
#   Define reasonable max number of modules.
# 
# xen/arch/x86/mkzen
#   2005/03/24 09:19:28-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +0 -0
#   BitKeeper file /home/mostrows/xen/xen.base/xen/arch/x86/mkzen
# 
# xen/include/xen/lib.h
#   2005/03/24 09:19:27-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +2 -1
#   Return pointer to unparse portion of command line.
#   Stop parsing command line at "--".
# 
# xen/common/kernel.c
#   2005/03/24 09:19:27-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +9 -2
#   Return pointer to unparse portion of command line.
#   Stop parsing command line at "--".
# 
# xen/arch/x86/setup.c
#   2005/03/24 09:19:27-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +166 -52
#   Handle Linux-style boot-params structure if multi-boot headers not
present.
# 
# xen/arch/x86/boot/x86_32.S
#   2005/03/24 09:19:27-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +13 -7
#   Detect Linux-style boot-params in %ebx if no multi-boot magic number
present.
# 
# xen/arch/x86/Makefile
#   2005/03/24 09:19:27-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +42 -0
#   Add rules to build a zenImg (which incorporates Linux bzImage
binaries). 
#    Depends on LINUX_BUILD being defined to point to a linux build
tree.
# 
diff -Nru a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile     2005-03-24 09:20:15 -05:00
+++ b/xen/arch/x86/Makefile     2005-03-24 09:20:15 -05:00
@@ -15,7 +15,11 @@
 OBJS := $(patsubst cdb%.o,,$(OBJS))
 endif
 
+ifdef LINUX_BUILD
+default: $(TARGET) zenImg
+else
 default: $(TARGET)
+endif
 
 $(TARGET): $(TARGET)-syms boot/mkelf32
        ./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000
@@ -32,6 +36,44 @@
 
 boot/mkelf32: boot/mkelf32.c
        $(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+
+
+ifdef LINUX_BUILD
+
+#
+# Check Makefile in Linux build dir.  If it contains KERNELSRC, then
use
+# that as source dir, otherwise build==source dir
+LINUX_SRC:= $(shell if grep -q KERNELSRC $(LINUX_BUILD)/Makefile ; then
\
+                       sed -e '/^KERNELSRC/!d' $(LINUX_BUILD)/Makefile | \
+                       bash -c '( read A B C ; echo -n $$C)' ; \
+                   else \
+                       echo -n $(LINUX_BUILD); \
+                   fi )
+
+$(TARGET).bin: $(TARGET)
+       $(OBJCOPY) -O binary -R .note -R .comment -S  $^ $@
+
+$(TARGET).bin.gz: $(TARGET).bin
+       gzip -f -9 < $< > $@
+
+piggy.o: $(TARGET).bin.gz
+       $(LD) -m elf_i386  -r --format binary --oformat elf32-i386 \
+       -T $(LINUX_SRC)/arch/i386/boot/compressed/vmlinux.scr $< -o $@
+
+zen:   $(LINUX_BUILD)/arch/i386/boot/compressed/head.o \
+       $(LINUX_BUILD)/arch/i386/boot/compressed/misc.o \
+       piggy.o
+       $(LD) -m elf_i386  -Ttext 0x100000 -e startup_32 $^ -o $@
+
+zenImg: zen
+       $(OBJCOPY) -O binary -R .note -R .comment -S  $^ $@.tmp
+       $(LINUX_BUILD)/arch/i386/boot/tools/build \
+               -b $(LINUX_BUILD)/arch/i386/boot/bootsect \
+               $(LINUX_BUILD)/arch/i386/boot/setup $@.tmp > $@
+
+
+endif
+
 
 clean:
        rm -f *.o *.s *~ core boot/*.o boot/*~ boot/core boot/mkelf32
diff -Nru a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S
--- a/xen/arch/x86/boot/x86_32.S        2005-03-24 09:20:15 -05:00
+++ b/xen/arch/x86/boot/x86_32.S        2005-03-24 09:20:15 -05:00
@@ -55,7 +55,7 @@
         mov     %ecx,%gs
         ljmp    $(__HYPERVISOR_CS),$(1f)-__PAGE_OFFSET
 1:      lss     stack_start-__PAGE_OFFSET,%esp
-
+       
         /* Reset EFLAGS (subsumes CLI and CLD). */
        pushl   $0
        popf
@@ -82,15 +82,21 @@
         and     $0x7f,%cl   # CR4.PGE (global enable)
         mov     %ecx,%cr4
                 
-        cmp     $(SECONDARY_CPU_FLAG),%ebx
-        je      start_paging
-                
         /* Check for Multiboot bootloader */
         cmp     $0x2BADB002,%eax
-        jne     not_multiboot
+        je     1f
 
-        /* Save the Multiboot info structure for later use. */
-       add     $__PAGE_OFFSET,%ebx
+       /* No multi-boot?  Hope that we've got a Linux boot-params */
+       /* stashed in esi. Save in %ebx until stack is ready. */
+       /* But do this only if this isn't a secondary cpu. */
+        cmp     $(SECONDARY_CPU_FLAG),%ebx
+       je      1f
+       movl    %esi, %ebx
+1:
+        cmp     $(SECONDARY_CPU_FLAG),%ebx
+        je      start_paging
+                
+       /* Stack is now ready, so store boot parameter pointer */
         push    %ebx
 
         /* Initialize BSS (no nasty surprises!) */
diff -Nru a/xen/arch/x86/mkzen b/xen/arch/x86/mkzen
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/xen/arch/x86/mkzen        2005-03-24 09:20:15 -05:00
@@ -0,0 +1,76 @@
+#!/bin/bash
+#
+# Copyright (C) 2005 Michal Ostrowski <mostrows@xxxxxxxxxxxxxx>, 
+#                                        IBM Corporation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
USA
+#
+
+
+# Reaches into a Linux build tree and uses objects and scripts from
+# linux to wrap a Xen ELF image in the Linuz bzImage machinery,
+# allowing the resulting "zen" image to be booted using any
+# boot-loader thant can load a Linux bzImage.
+
+#
+# Usage: mkzen <LINUX_BUILD> <XEN IMAGE> <ZEN>
+
+set -e
+LINUX_BUILD=$1
+XEN=$2
+ZEN=$3
+
+: ${CROSS_COMPILE:=}
+: ${OBJCOPY:=${CROSS_COMPILE}objcopy}
+: ${LD:=${CROSS_COMPILE}ld}
+
+function cleanup(){
+    rm -f ${XEN}.bin.$$ ${XEN}.bin.gz.$$ ${XEN}.piggy.o.$$
+    rm -f ${ZEN}.1.$$ ${ZEN}.2.$$
+}
+
+trap cleanup ERR
+
+#
+# Check Makefile in Linux build dir.  If it contains KERNELSRC, then
use
+# that as source dir, otherwise build==source dir
+#
+LINUX_SRC=`sed -e '/^KERNELSRC/!d;s/^.*:=[ ]*//'  <
${LINUX_BUILD}/Makefile`
+if [ -z "${LINUX_SRC}" ]; then
+    LINUX_SRC=${LINUX_BUILD};
+fi
+
+${OBJCOPY} -O binary -R .note -R .comment -S ${XEN} ${XEN}.bin.$$
+
+gzip -f -9 < ${XEN}.bin.$$ > ${XEN}.bin.gz.$$
+
+${LD} -m elf_i386  -r --format binary --oformat elf32-i386 \
+    -T ${LINUX_SRC}/arch/i386/boot/compressed/vmlinux.scr \
+    ${XEN}.bin.gz -o ${XEN}.piggy.o.$$
+
+
+${LD} -m elf_i386  -Ttext 0x100000 -e startup_32 \
+    ${LINUX_BUILD}/arch/i386/boot/compressed/head.o \
+    ${LINUX_BUILD}/arch/i386/boot/compressed/misc.o ${XEN}.piggy.o.$$ \
+    -o ${ZEN}.1.$$
+
+${OBJCOPY} -O binary -R .note -R .comment -S  ${ZEN}.1.$$ ${ZEN}.2.$$
+
+${LINUX_BUILD}/arch/i386/boot/tools/build \
+    -b ${LINUX_BUILD}/arch/i386/boot/bootsect \
+    ${LINUX_BUILD}/arch/i386/boot/setup ${ZEN}.2.$$ > ${ZEN}
+
+
+cleanup
\ No newline at end of file
diff -Nru a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c      2005-03-24 09:20:15 -05:00
+++ b/xen/arch/x86/setup.c      2005-03-24 09:20:15 -05:00
@@ -86,6 +86,22 @@
 int phys_proc_id[NR_CPUS];
 int logical_proc_id[NR_CPUS];
 
+
+/* Details about what is found where in the Linux boot parameters area.
*/
+/* Put into a seperate header if it grows much more. */
+#define PARAM_SIZE              2048
+#define COMMAND_LINE_SIZE       256
+#define NEW_CL_POINTER          0x228
+#define E820NR                  0x1e8
+#define E820MAP                 0x2d0
+#define INITRD_START            0x218
+#define INITRD_SIZE             0x21c
+
+static unsigned char boot_params[PARAM_SIZE];
+static module_t boot_modules[MAX_MBI_MODULES];
+
+
+
 /* Standard macro to see if a specific flag is changeable. */
 static inline int flag_is_changeable_p(unsigned long flag)
 {
@@ -453,36 +469,19 @@
 #endif
 }
 
-void __init __start_xen(multiboot_info_t *mbi)
+static int __init boot_param_e820_setup(unsigned char *boot_params, 
+                                        struct e820entry *e820raw)
 {
-    char *cmdline;
-    module_t *mod = (module_t *)__va(mbi->mods_addr);
-    void *heap_start;
-    unsigned long firsthole_start, nr_pages;
-    unsigned long initial_images_start, initial_images_end;
-    struct e820entry e820_raw[E820MAX];
-    int i, e820_raw_nr = 0, bytes = 0;
-
-    /* Parse the command-line options. */
-    if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) )
-        cmdline_parse(__va(mbi->cmdline));
-
-    /* Must do this early -- e.g., spinlocks rely on get_current(). */
-    set_current(&idle0_exec_domain);
-
-    /* We initialise the serial devices very early so we can get
debugging. */
-    serial_init_stage1();
-
-    init_console();
-
-    /* Check that we have at least one Multiboot module. */
-    if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) )
-    {
-        printk("FATAL ERROR: Require at least one Multiboot
module.\n");
-        for ( ; ; ) ;
-    }
+    int e820_raw_nr = *(int*)&boot_params[E820NR];
+    memcpy(e820raw, boot_params + E820MAP, e820_raw_nr *
sizeof(*e820raw));
+    return e820_raw_nr;
+}
 
-    xenheap_phys_end = opt_xenheap_megabytes << 20;
+static int __init mbi_e820_setup(multiboot_info_t *mbi, 
+                                 struct e820entry *e820_raw)
+{
+    int bytes = 0;
+    int e820_raw_nr = 0;
 
     if ( mbi->flags & MBI_MEMMAP )
     {
@@ -509,14 +508,134 @@
         e820_raw[1].type = E820_RAM;
         e820_raw_nr = 2;
     }
+    return e820_raw_nr;
+}
+
+int __init mbi_boot_modules(multiboot_info_t *mbi)
+{
+    /* Check that we have at least one Multiboot module. */
+    if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) )
+    {
+        printk("FATAL ERROR: Require at least one Multiboot
module.\n");
+        for ( ; ; ) ;
+    }
+
+    memcpy(&boot_modules, __va(mbi->mods_addr), 
+           sizeof(module_t) * mbi->mods_count);
+    return mbi->mods_count;
+}
+
+int __init boot_param_modules(unsigned char *params)
+{
+    u32 rd = *(u32*)&boot_params[INITRD_START];
+    int size = *(int*)&boot_params[INITRD_SIZE];
+
+    boot_modules[0].mod_start = rd;
+    boot_modules[0].mod_end = rd + size;
+    boot_modules[0].string = 0;
+    boot_modules[0].reserved = 0;
+
+    return 1;
+}
+
+void __init __start_xen(void *params)
+{
+    void *heap_start;
+    unsigned long firsthole_start, nr_pages;
+    unsigned long initial_images_start, initial_images_end;
+    struct e820entry e820_raw[E820MAX];
+    int i, e820_raw_nr = 0;
+    int num_mods = 0;
+    multiboot_info_t *mbi = NULL;
+    char *leftover;
+    unsigned char cmdline[COMMAND_LINE_SIZE + 1];
+    unsigned char dom0_cmdline[COMMAND_LINE_SIZE + 1];
+    
+    /* Forces correct empty-string and null-termination behavior */
+    memset(cmdline, 0, sizeof(cmdline));
+    memset(dom0_cmdline, 0, sizeof(dom0_cmdline));
+    
+    if (MULTIBOOT_BOOTLOADER_MAGIC == *(u32*)__va(params) ) 
+    {
+        mbi = (struct multiboot_info_t*)__va(mbi);
+        if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) ) 
+        {
+            memcpy(cmdline, __va(mbi->cmdline), COMMAND_LINE_SIZE);
+        }
+    } 
+    else 
+    {
+        /* Hope it is a Linux boot parameters area. */
+        unsigned char* orig_cmd_line;
+        memcpy(boot_params, __va(((char*)params)), PARAM_SIZE);
+        
+        orig_cmd_line = __va(*(unsigned
char**)&boot_params[NEW_CL_POINTER]);
+
+        memcpy(cmdline, orig_cmd_line, COMMAND_LINE_SIZE);
+    }
+
+    /* Parse the command-line options. */
+    leftover = cmdline_parse(cmdline);
+    
+    /* Must do this early -- e.g., spinlocks rely on get_current(). */
+    set_current(&idle0_exec_domain);
+
+    /* We initialise the serial devices very early so we can get
debugging. */
+    serial_init_stage1();
+
+    init_console();
+    
+    xenheap_phys_end = opt_xenheap_megabytes << 20;
+
+    if ( mbi != NULL ) 
+    {
+        e820_raw_nr = mbi_e820_setup(mbi, e820_raw);
+    }
     else
     {
+        e820_raw_nr = boot_param_e820_setup(boot_params, e820_raw);
+    }
+
+    if (e820_raw_nr == 0) 
+    {
         printk("FATAL ERROR: Bootloader provided no memory
information.\n");
         for ( ; ; ) ;
     }
 
     max_page = init_e820(e820_raw, e820_raw_nr);
 
+    if (mbi != NULL)
+    {
+        num_mods = mbi_boot_modules(mbi);        
+    }
+    else
+    {
+        num_mods = boot_param_modules(boot_params);
+    }
+
+    /* Save dom0 cmd line to a known place. */
+    if ( boot_modules[0].string )
+    {
+#if defined(__i386__)
+        char *cmdline = (char *)boot_modules[0].string;
+#elif defined(__x86_64__)
+        char *cmdline = (char *)__va(boot_modules[0].string);
+#endif        
+        /* Skip past the image name. */
+        int  i = 0;
+        while ( cmdline[i] && cmdline[i] == ' ' ) ++i;
+        while ( cmdline[i] && cmdline[i] != ' ') ++i;
+        while ( cmdline[i] && cmdline[i] == ' ' ) ++i;
+  
+        memcpy(dom0_cmdline, cmdline, COMMAND_LINE_SIZE - i);
+    } 
+    else if ( leftover )
+    {
+        /* NULL termination is guaranteed on the cmdline buffer, */
+        /* and leftover is a pointer into that. */
+        strcpy(dom0_cmdline, leftover);
+    }
+
     /* Find the first high-memory RAM hole. */
     for ( i = 0; i < e820.nr_map; i++ )
         if ( (e820.map[i].type == E820_RAM) &&
@@ -527,7 +646,7 @@
     /* Relocate the Multiboot modules. */
     initial_images_start = xenheap_phys_end;
     initial_images_end   = initial_images_start + 
-        (mod[mbi->mods_count-1].mod_end - mod[0].mod_start);
+        (boot_modules[num_mods - 1].mod_end -
boot_modules[0].mod_start);
     if ( initial_images_end > firsthole_start )
     {
         printk("Not enough memory to stash the DOM0 kernel image.\n");
@@ -535,14 +654,14 @@
     }
 #if defined(__i386__)
     memmove((void *)initial_images_start,  /* use low mapping */
-            (void *)mod[0].mod_start,      /* use low mapping */
-            mod[mbi->mods_count-1].mod_end - mod[0].mod_start);
+            (void *)boot_modules[0].mod_start,      /* use low mapping
*/
+            boot_modules[num_mods - 1].mod_end -
boot_modules[0].mod_start);
 #elif defined(__x86_64__)
     memmove(__va(initial_images_start),
-            __va(mod[0].mod_start),
-            mod[mbi->mods_count-1].mod_end - mod[0].mod_start);
+            __va(boot_modules[0].mod_start),
+            boot_modules[num_mods-1].mod_end -
boot_modules[0].mod_start);
 #endif
-
+    
     /* Initialise boot-time allocator with all RAM situated after
modules. */
     heap_start = memguard_init(&_end);
     heap_start = __va(init_boot_allocator(__pa(heap_start)));
@@ -586,28 +705,23 @@
 
     set_bit(DF_PRIVILEGED, &dom0->d_flags);
 
-    /* Grab the DOM0 command line. Skip past the image name. */
-    cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL);
-    if ( cmdline != NULL )
-    {
-        while ( *cmdline == ' ' ) cmdline++;
-        if ( (cmdline = strchr(cmdline, ' ')) != NULL )
-            while ( *cmdline == ' ' ) cmdline++;
-    }
-
     /*
      * We're going to setup domain0 using the module(s) that we stashed
safely
      * above our heap. The second module, if present, is an initrd
ramdisk.
      */
-    if ( construct_dom0(dom0,
-                        initial_images_start, 
-                        mod[0].mod_end-mod[0].mod_start,
-                        (mbi->mods_count == 1) ? 0 :
-                        initial_images_start + 
-                        (mod[1].mod_start-mod[0].mod_start),
-                        (mbi->mods_count == 1) ? 0 :
-                        mod[mbi->mods_count-1].mod_end -
mod[1].mod_start,
-                        cmdline) != 0)
+    u32 img_size = boot_modules[0].mod_end - boot_modules[0].mod_start;
+    u32 rd_start = 0;
+    u32 rd_size = 0;
+    if ( num_mods > 1 ) 
+    {
+        rd_start = initial_images_start
+                   + boot_modules[1].mod_start -
boot_modules[0].mod_start;
+
+        rd_size = boot_modules[num_mods-1].mod_end -
boot_modules[1].mod_start;
+    }
+
+    if ( construct_dom0(dom0, initial_images_start, img_size,
+                        rd_start, rd_size, dom0_cmdline) != 0)
         panic("Could not set up DOM0 guest OS\n");
 
     /* Scrub RAM that is still free and so may go to an unprivileged
domain. */
diff -Nru a/xen/common/kernel.c b/xen/common/kernel.c
--- a/xen/common/kernel.c       2005-03-24 09:20:15 -05:00
+++ b/xen/common/kernel.c       2005-03-24 09:20:15 -05:00
@@ -14,13 +14,14 @@
 #include <xen/compile.h>
 #include <xen/sched.h>
 
-void cmdline_parse(char *cmdline)
+/* Returns pointer to unparsed portion of command line. */
+char* cmdline_parse(char *cmdline)
 {
     char *opt_end, *opt;
     struct kernel_param *param;
     
     if ( cmdline == NULL )
-        return;
+        return NULL;
 
     while ( *cmdline == ' ' )
         cmdline++;
@@ -31,6 +32,11 @@
             cmdline++;
         if ( *cmdline == '\0' )
             break;
+        
+        /* Pass all options after -- to dom0 */
+        if ( *cmdline == '-' && ( cmdline[1] == '-' || cmdline[1] ==
'\0' ) )
+            return cmdline + 2;
+            
         opt_end = strchr(cmdline, ' ');
         if ( opt_end != NULL )
             *opt_end++ = '\0';
@@ -62,6 +68,7 @@
         }
         cmdline = opt_end;
     }
+    return NULL;
 }
 
 /*
diff -Nru a/xen/include/xen/lib.h b/xen/include/xen/lib.h
--- a/xen/include/xen/lib.h     2005-03-24 09:20:15 -05:00
+++ b/xen/include/xen/lib.h     2005-03-24 09:20:15 -05:00
@@ -29,7 +29,8 @@
 
 struct domain;
 
-void cmdline_parse(char *cmdline);
+/* Returns pointer to unparsed portion of command line. */
+char* cmdline_parse(char *cmdline);
 
 #ifndef NDEBUG
 extern int debugtrace_send_to_console;
diff -Nru a/xen/include/xen/multiboot.h b/xen/include/xen/multiboot.h
--- a/xen/include/xen/multiboot.h       2005-03-24 09:20:15 -05:00
+++ b/xen/include/xen/multiboot.h       2005-03-24 09:20:15 -05:00
@@ -28,6 +28,10 @@
 #define MBI_MEMMAP     (1<<6)
 #define MBI_LOADERNAME (1<<9)
 
+/* Make up some reasonable maximum that we support. */
+#define MAX_MBI_MODULES 4
+
+
 /* The symbol table for a.out.  */
 typedef struct {
     u32 tabsize;

Attachment: signature.asc
Description: This is a digitally signed message part


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.