Allow passing command line parameters to gpxe.lkrn. For example,

pxelinux.cfg: (just a demo, we already have gpxelinux)

        LABEL gpxe
        KERNEL gpxe.lkrn
        APPEND kernel http://somewhere/~wfg/cgi-bin/gpxe.cgi?mac=${mac}

/boot/grub/grub.cfg: (this use case should be valuable)

        menuentry "gPXE" {
          echo     Loading gPXE ...
          linux16  /boot/gpxe.lkrn kernel http://somewhere/rip/kernel64 
root=/dev/ram0 \
                                   initrd http://somewhere/rip/rootfs.cgz
        }

The command line syntax is "kernel URL [initrd URL]". One may add ';'
to truncate extra parameters. For example:
gpxe cmdline                              linux /proc/cmdline
-------------------------------------------------------------------
kernel URL root=/dev/ram0 initrd URL      root=/dev/ram0 initrd URL
kernel URL; root=/dev/ram0 initrd URL     root=/dev/ram0

Note that the auto-added BOOT_IMAGE=xxx may be dropped by the simple
cmdline parsing.

Also allow passing ramdisk script to gpxe: (we can already _embed_ the
script into gpxe.lkrn, however it's much more convenient for end user)

/boot/grub/grub.cfg:

        menuentry "gPXE" {
                echo          Loading gPXE ...
                linux16       /boot/gpxe.lkrn
                initrd16      /boot/bee.gpxe
        }

/boot/bee.gpxe:

        #!gpxe
        dhcp net0
        kernel http://somewhere/~wfg/cgi-bin/gpxe.cgi?mac=${net0/mac}
        boot

The ramdisk memory is hidden to avoid it being overwritten.
The cmdline memory is unattended, otherwise it will break meme820()'s
assumption that the _second_ e820 memory region starts at 0x100000.
And I guess it's safe to leave it unattended.

Tested OK with GRUB2, PXELinux and KVM.

Signed-off-by: Wu Fengguang <[email protected]>
---
 src/arch/i386/core/relocate.c               |   23 +++++++--
 src/arch/i386/firmware/pcbios/e820mangler.S |    4 +
 src/arch/i386/firmware/pcbios/hidemem.c     |   12 +++++
 src/arch/i386/prefix/libprefix.S            |    7 +++
 src/arch/i386/prefix/lkrnprefix.S           |    5 +-
 src/image/embedded.c                        |   19 ++++++++
 src/include/gpxe/hidemem.h                  |    1 
 src/include/gpxe/image.h                    |   11 ++++
 src/usr/autoboot.c                          |   42 ++++++++++++++++++
 9 files changed, 118 insertions(+), 6 deletions(-)

--- gpxe.orig/src/arch/i386/prefix/lkrnprefix.S 2010-05-31 15:40:17.000000000 
+0800
+++ gpxe/src/arch/i386/prefix/lkrnprefix.S      2010-05-31 15:40:18.000000000 
+0800
@@ -134,8 +134,10 @@ setup_move_size:
        .word   0
 code32_start:
        .long   0
+.globl ramdisk_image
 ramdisk_image:
        .long   0
+.globl ramdisk_size
 ramdisk_size:
        .long   0
 bootsect_kludge:
@@ -144,6 +146,7 @@ heap_end_ptr:
        .word   0
 pad1:
        .word   0
+.globl cmd_line_ptr
 cmd_line_ptr:
        .long   0
 initrd_addr_max:
@@ -158,7 +161,7 @@ relocatable_kernel:
 pad2:
        .byte   0, 0, 0
 cmdline_size:
-       .long   0
+       .long   255
 hardware_subarch:
        .long   0
 hardware_subarch_data:
--- gpxe.orig/src/image/embedded.c      2010-05-31 15:40:17.000000000 +0800
+++ gpxe/src/image/embedded.c   2010-05-31 15:40:18.000000000 +0800
@@ -50,6 +50,15 @@ static struct image embedded_images[] = 
        EMBED_ALL
 };
 
+unsigned long  __data16 ( linux_cmdline      ) = 0;
+unsigned long  __data16 ( linux_ramdisk      ) = 0;
+unsigned long  __data16 ( linux_ramdisk_size ) = 0;
+
+static struct image preloaded_image = {
+       .refcnt =  { .free = embedded_image_free, },
+       .name = "initrd",
+};
+
 /**
  * Register all embedded images
  */
@@ -59,6 +68,16 @@ static void embedded_init ( void ) {
        void *data;
        int rc;
 
+       if (linux_ramdisk && linux_ramdisk_size) {
+               DBG ("Found ramdisk at %lx size %ld\n",
+                    linux_ramdisk, linux_ramdisk_size);
+               preloaded_image.data = phys_to_user( linux_ramdisk );
+               preloaded_image.len = linux_ramdisk_size;
+               if ( ! register_image ( &preloaded_image ) &&
+                       ! image_autoload ( &preloaded_image ) )
+                       return;
+       }
+
        /* Skip if we have no embedded images */
        if ( ! sizeof ( embedded_images ) )
                return;
--- gpxe.orig/src/include/gpxe/image.h  2010-05-31 15:40:17.000000000 +0800
+++ gpxe/src/include/gpxe/image.h       2010-05-31 15:40:18.000000000 +0800
@@ -191,4 +191,15 @@ static inline int image_set_name ( struc
        return 0;
 }
 
+extern char preloaded_ramdisk[128];
+extern char *userimage_addr;
+extern unsigned long userimage_size;
+
+extern unsigned long   __data16 ( linux_cmdline );
+extern unsigned long   __data16 ( linux_ramdisk );
+extern unsigned long   __data16 ( linux_ramdisk_size );
+#define linux_cmdline          __use_data16 ( linux_cmdline )
+#define linux_ramdisk          __use_data16 ( linux_ramdisk )
+#define linux_ramdisk_size     __use_data16 ( linux_ramdisk_size )
+
 #endif /* _GPXE_IMAGE_H */
--- gpxe.orig/src/arch/i386/prefix/libprefix.S  2010-05-31 15:40:17.000000000 
+0800
+++ gpxe/src/arch/i386/prefix/libprefix.S       2010-05-31 15:40:18.000000000 
+0800
@@ -704,6 +704,13 @@ install_prealloc:
        /* Set up %ds for access to .data16 */
        movw    %bx, %ds
 
+       movl    %es:cmd_line_ptr, %ecx
+       movl    %ecx, linux_cmdline
+       movl    %es:ramdisk_image, %ecx
+       movl    %ecx, linux_ramdisk
+       movl    %es:ramdisk_size, %ecx
+       movl    %ecx, linux_ramdisk_size
+
 #ifdef KEEP_IT_REAL
        /* Initialise libkir */
        movw    %ax, (init_libkir_vector+2)
--- gpxe.orig/src/usr/autoboot.c        2010-05-31 15:40:17.000000000 +0800
+++ gpxe/src/usr/autoboot.c     2010-05-31 15:53:30.000000000 +0800
@@ -122,6 +122,30 @@ int boot_root_path ( const char *root_pa
        return -ENOTSUP;
 }
 
+int exec_cmdline ( const char *buf, const char *prefix, int *match ) {
+       char *p, *q;
+       char cmd[256];
+
+       p = strstr ( buf, prefix );
+       if ( ! p )
+               return 0;
+
+       for ( q = cmd; *p && *p != ';'; )
+               *q++ = *p++;
+       *q = '\0';
+
+       /* truncate the PXELinux appended BOOT_IMAGE= */
+       if ( *match ) {
+               p = strstr ( cmd, "BOOT_IMAGE=" );
+               if ( p )
+                       *( p - 1 ) = '\0';
+       }
+
+       ( *match )++;
+
+       return system( cmd );
+}
+
 /**
  * Boot from a network device
  *
@@ -163,6 +187,24 @@ static int netboot ( struct net_device *
                return pxe_menu_boot ( netdev );
        }
 
+       if ( linux_cmdline ) {
+               int match = 0;
+
+               DBG ( "Found cmdline at %lx: ", linux_cmdline );
+               copy_from_user ( buf, phys_to_user( linux_cmdline ),
+                                0, sizeof ( buf ) );
+               buf[sizeof ( buf ) - 1] = '\0';
+
+               rc = exec_cmdline( buf, "kernel ", &match );
+               if ( rc )
+                       return rc;
+               rc = exec_cmdline( buf, "initrd ", &match );
+               if ( rc )
+                       return rc;
+               if ( match )
+                       return system( "boot" );
+       }
+
        /* Try to download and boot whatever we are given as a filename */
        fetch_ipv4_setting ( NULL, &next_server_setting, &next_server );
        fetch_string_setting ( NULL, &filename_setting, buf, sizeof ( buf ) );
--- gpxe.orig/src/arch/i386/core/relocate.c     2010-05-31 15:40:17.000000000 
+0800
+++ gpxe/src/arch/i386/core/relocate.c  2010-05-31 15:40:18.000000000 +0800
@@ -1,6 +1,8 @@
 #include <gpxe/io.h>
 #include <registers.h>
 #include <gpxe/memmap.h>
+#include <gpxe/image.h>
+#include <gpxe/hidemem.h>
 
 /*
  * Originally by Eric Biederman
@@ -46,6 +48,7 @@ __asmcall void relocate ( struct i386_al
        unsigned long start, end, size, padded_size;
        unsigned long new_start, new_end;
        unsigned i;
+       unsigned long top = MAX_ADDR;
 
        /* Get memory map and current location */
        get_memmap ( &memmap );
@@ -58,6 +61,16 @@ __asmcall void relocate ( struct i386_al
              "...need %lx bytes for %d-byte alignment\n",
              start, end, padded_size, max_align );
 
+       if (linux_ramdisk && linux_ramdisk_size) {
+               hide_ramdisk(linux_ramdisk, linux_ramdisk + linux_ramdisk_size);
+
+               /* hide_ramdisk() takes effect in future.
+                * For now simply lower the top location to hide it.
+                */
+               if (top > linux_ramdisk)
+                       top = linux_ramdisk & ~0xfffff;
+       }
+
        /* Walk through the memory map and find the highest address
         * below 4GB that etherboot will fit into.  Ensure etherboot
         * lies entirely within a range with A20=0.  This means that
@@ -76,14 +89,14 @@ __asmcall void relocate ( struct i386_al
                 * 4GB, which means that we can get away with using
                 * just 32-bit arithmetic after this stage.
                 */
-               if ( region->start > MAX_ADDR ) {
-                       DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
+               if ( region->start > top ) {
+                       DBG ( "...starts after top=%lx\n", top );
                        continue;
                }
                r_start = region->start;
-               if ( region->end > MAX_ADDR ) {
-                       DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
-                       r_end = MAX_ADDR;
+               if ( region->end > top ) {
+                       DBG ( "...end truncated to top=%lx\n", top );
+                       r_end = top;
                } else {
                        r_end = region->end;
                }
--- gpxe.orig/src/arch/i386/firmware/pcbios/e820mangler.S       2010-05-31 
15:40:17.000000000 +0800
+++ gpxe/src/arch/i386/firmware/pcbios/e820mangler.S    2010-05-31 
15:40:18.000000000 +0800
@@ -66,6 +66,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
        .globl hidemem_base
        .globl hidemem_umalloc
        .globl hidemem_textdata
+       .globl hidemem_ramdisk
 memory_windows:
 base_memory_window:    .long 0x00000000, 0x00000000 /* Start of memory */
 
@@ -78,6 +79,9 @@ hidemem_umalloc:      .long 0xffffffff, 0xfff
 hidemem_textdata:      .long 0xffffffff, 0xffffffff /* Changes at runtime */
                        .long 0xffffffff, 0xffffffff /* Changes at runtime */
 
+hidemem_ramdisk:       .long 0xffffffff, 0xffffffff /* Changes at runtime */
+                       .long 0xffffffff, 0xffffffff /* Changes at runtime */
+
                        .long 0xffffffff, 0xffffffff /* End of memory */
 memory_windows_end:
 
--- gpxe.orig/src/include/gpxe/hidemem.h        2010-05-31 15:40:17.000000000 
+0800
+++ gpxe/src/include/gpxe/hidemem.h     2010-05-31 15:40:18.000000000 +0800
@@ -13,5 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdint.h>
 
 extern void hide_umalloc ( physaddr_t start, physaddr_t end );
+extern void hide_ramdisk ( physaddr_t start, physaddr_t end );
 
 #endif /* _GPXE_HIDEMEM_H */
--- gpxe.orig/src/arch/i386/firmware/pcbios/hidemem.c   2010-05-31 
15:40:17.000000000 +0800
+++ gpxe/src/arch/i386/firmware/pcbios/hidemem.c        2010-05-31 
15:40:18.000000000 +0800
@@ -60,6 +60,10 @@ extern struct hidden_region __data16 ( h
 extern struct hidden_region __data16 ( hidemem_textdata );
 #define hidemem_textdata __use_data16 ( hidemem_textdata )
 
+/** Hidden ramdisk memory */
+extern struct hidden_region __data16 ( hidemem_ramdisk );
+#define hidemem_ramdisk __use_data16 ( hidemem_ramdisk )
+
 /** Assembly routine in e820mangler.S */
 extern void int15();
 
@@ -126,6 +130,14 @@ void hide_textdata ( void ) {
 }
 
 /**
+ * Hide linux ramdisk
+ *
+ */
+void hide_ramdisk ( physaddr_t start, physaddr_t end ) {
+       hide_region ( &hidemem_ramdisk, start, end );
+}
+
+/**
  * Hide Etherboot
  *
  * Installs an INT 15 handler to edit Etherboot out of the memory map
_______________________________________________
gPXE-devel mailing list
[email protected]
http://etherboot.org/mailman/listinfo/gpxe-devel

Reply via email to