[ipxe-devel] [PATCH] make iPXE run the string from the bootloader

Dave Hansen dave at sr71.net
Thu Jan 27 20:14:09 UTC 2011


I always forget to compile in a custom embedded script image into iPXE,
and I also don't have full control over my DHCP server in some cases so
I can't set $file.

If you are booting ipxe.lkrn, this _effectively_ lets you do is pass in
a tiny script via the boot command-line.  I use iPXE to compile kernels
on one system and then boot them elsewhere.  The reboot cycles are
*SLOW*, and I like to speed them up.  This should let me do something
like the following in GRUB's menu.lst:

	title           iPXE
	kernel          /boot/ipxe.lkrn dhcp && kernel http://1.2.3.4/~vmlinuz root=UUID=ce4190bb-bdee-48e0-8e47-7e71d167c4ac ro profile=2 single

Previously, I would either have a custom copy of ipxe for each system,
or a custom script on a server, indexed by the system's MAC.  It's
*MUCH* nicer to just keep all of the root= or serial console arguments
all in one file (menu.lst).

This could also be used to anything that the embedded scripts were, like
setting static IPs.

I'm still a bit shaky on whether the assembly here is "right" or whether
it just happens to be cobbled together enough to happen to work.
Michael, thanks for basically writing this for me.  :)  I'm happy to
clean it up some more.
---
 src/arch/i386/prefix/lkrnprefix.S |   10 ++++++
 src/core/cmdline.c                |   56 +++++++++++++++++++++++++++++++++++++
 src/core/main.c                   |    4 ++
 src/include/ipxe/shell.h          |    1 +
 4 files changed, 71 insertions(+), 0 deletions(-)
 create mode 100644 src/core/cmdline.c

diff --git a/src/arch/i386/prefix/lkrnprefix.S b/src/arch/i386/prefix/lkrnprefix.S
index 3be43ae..fe8a25a 100644
--- a/src/arch/i386/prefix/lkrnprefix.S
+++ b/src/arch/i386/prefix/lkrnprefix.S
@@ -178,6 +178,7 @@ setup_code:
 	 * in the prefix, it doesn't matter: we just have to ensure that
 	 * %cs:0000 is where the start of the image *would* be.
 	 */
+	movl	%es:cmd_line_ptr, %edx 
 	ljmp	$(SYSSEG-(PREFIXSIZE/16)), $run_ipxe
 
 
@@ -196,8 +197,12 @@ run_ipxe:
 
 	/* Set up real-mode stack */
 	movw	%bx, %ss
+	movw	%bx, %ds
 	movw	$_estack16, %sp
 
+	/* cmdline */
+	movl    %edx, cmdline
+
 	/* Jump to .text16 segment */
 	pushw	%ax
 	pushw	$1f
@@ -214,3 +219,8 @@ run_ipxe:
 
 	/* Boot next device */
 	int $0x18
+
+.section ".bss16", "aw", @nobits
+.globl cmdline
+cmdline:
+	.long 0
diff --git a/src/core/cmdline.c b/src/core/cmdline.c
new file mode 100644
index 0000000..7439f6e
--- /dev/null
+++ b/src/core/cmdline.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Michael Brown <mbrown at fensystems.co.uk>.
+ * Copyright (C) 2010 Dave Hansen <dave at sr71.net>.
+ *
+ * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ipxe/shell.h>
+#include <ipxe/image.h>
+
+/*
+ * Bootloaders can pass parameters in to the images being booted
+ * via a string.  This fetches that string from where the bootloader
+ * stashed it, and interprets it as a single iPXE command-line
+ * statement.  You may chain statements with &&
+ */
+
+extern uint32_t __data16 ( cmdline );
+#define cmdline __use_data16 ( cmdline )
+
+void run_cmdline ( void )
+{
+	userptr_t cmdline_user;
+	int cmdline_len;
+	char *cmdline_copy;
+
+	if ( ! cmdline )
+		return;
+
+	cmdline_user = phys_to_user ( cmdline );
+	cmdline_len = strlen_user ( cmdline_user, 0 );
+
+	cmdline_copy = malloc(cmdline_len + 1);
+	copy_from_user ( cmdline_copy, cmdline_user, 0, cmdline_len );
+	cmdline_copy [cmdline_len] = '\0';
+
+	printf("interpreting bootloader command line: '%s'\n", &cmdline_copy[0]);
+	system(cmdline_copy);
+	free(cmdline_copy);
+}
diff --git a/src/core/main.c b/src/core/main.c
index a1128dd..e129a5f 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -27,6 +27,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define BOLD	"\033[1m"
 #define CYAN	"\033[36m"
 
+extern uint32_t __data16 ( cmdline );
+#define cmdline __use_data16 ( cmdline )
+
 /**
  * Main entry point
  *
@@ -72,6 +75,7 @@ __asmcall int main ( void ) {
 		 * booting fails for any reason, offer a second chance
 		 * to enter the shell for diagnostics.
 		 */
+		run_cmdline();
 		if ( have_images() ) {
 			for_each_image ( image ) {
 				image_exec ( image );
diff --git a/src/include/ipxe/shell.h b/src/include/ipxe/shell.h
index 635de24..c790cf5 100644
--- a/src/include/ipxe/shell.h
+++ b/src/include/ipxe/shell.h
@@ -10,5 +10,6 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 extern void shell ( void );
+extern void run_cmdline ( void );
 
 #endif /* _IPXE_SHELL_H */
-- 
1.7.4.rc3




More information about the ipxe-devel mailing list