[ipxe-devel] [RFC PATCH] ipxe/autoboot: Boot only from requested device

Alex Williamson alex.williamson at redhat.com
Tue Feb 4 23:30:41 UTC 2014


The BIOS makes two calls into the iPXE ROM, once for PnP option ROM
initialization and a second for the Bootstrap Entry Vector (BEV).  The
first call provides the device to initialize and the BEV expects the
ROM to store that away and use it when called for BEV.  iPXE does
store it, but it's trapped in the real-mode code and only gets used
for superficial printing.  When trying to find a device to boot, iPXE
tries every device available and may only get to the one asked for
after trying several others.

This change passes the requested device through to the protected-mode
code using the real-mode registers, which are already provided to the
main() entrypoint.  We define %al as the bus_type storage, where 0x0
is unspecified and %bx as the location, which is only defined for PCI.
autoboot() will then attempt to match these and boot only from that
device, or from no device if a device is specified but not found.

I sent a query[1] about this a few months ago, but it didn't generate
any discussion or interest.  I believe a change like this is necessary
for iPXE to properly support booting from a specific device, but I'm
sending this as an RFC because I imagine there are better ways to
handle the assembly and pass the data between real and protected modes
(I don't claim to know x86 assembly).

[1] http://lists.ipxe.org/pipermail/ipxe-devel/2013-November/002944.html

Signed-off-by: Alex Williamson <alex.williamson at redhat.com>
---
 src/arch/i386/prefix/romprefix.S |   21 +++++++++++++++++++++
 src/core/main.c                  |   11 ++++++++++-
 src/include/ipxe/device.h        |    2 ++
 src/usr/autoboot.c               |   26 ++++++++++++++++----------
 4 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/src/arch/i386/prefix/romprefix.S b/src/arch/i386/prefix/romprefix.S
index 091673d..8421c65 100644
--- a/src/arch/i386/prefix/romprefix.S
+++ b/src/arch/i386/prefix/romprefix.S
@@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
 #define PMM_HANDLE_BASE_DECOMPRESS_TO \
 	( PMM_HANDLE_BASE | 0x00002000 )
 #define PCI_FUNC_MASK 0x07
+#define BUS_TYPE_PCI 1
 
 /* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
  * config.h, but converted to a number of (18Hz) timer ticks, and
@@ -224,6 +225,10 @@ init:
 
 	/* Store PCI bus:dev.fn address */
 	movw	%ax, init_pci_busdevfn
+	testw	$0xffff, init_pci_busdevfn
+	jz	no_pciinfo
+	movb	$BUS_TYPE_PCI, init_bustype
+no_pciinfo:
 
 	/* Print message as early as possible */
 	movw	$init_message, %si
@@ -599,6 +604,14 @@ init_message_done:
 	.asciz	"\n\n"
 	.size	init_message_done, . - init_message_done
 
+/* Bus type
+ *
+ * Currently only supports BUS_TYPE_PCI
+ */
+init_bustype:
+	.byte	0
+	.size	init_bustype, . - init_bustype
+
 /* PCI bus:dev.fn
  *
  */
@@ -745,6 +758,14 @@ exec:	/* Set %ds = %cs */
 1:	/* Call main() */
 	pushl	$main
 	pushw	%cs
+
+	/* Store boot bus type and location for iPXE */
+	movb	init_bustype, %al
+	testb	$BUS_TYPE_PCI, init_bustype
+	jz	no_location
+	movw	init_pci_busdevfn, %bx
+no_location:
+
 	call	prot_call
 	popl	%eax /* discard */
 
diff --git a/src/core/main.c b/src/core/main.c
index c55ca26..12de18c 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -16,16 +16,25 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stddef.h>
 #include <stdio.h>
+#include <ipxe/device.h>
 #include <ipxe/init.h>
 #include <usr/autoboot.h>
 #include <config/general.h>
+#include <registers.h>
+
+struct device_description boot_device_desc;
 
 /**
  * Main entry point
  *
  * @ret rc		Return status code
  */
-__asmcall int main ( void ) {
+__asmcall int main ( struct i386_all_regs *ix86 ) {
+
+	/* Retrieve boot device info from real-mode registers */
+	boot_device_desc.bus_type = ix86->regs.al;
+	if ( boot_device_desc.bus_type == BUS_TYPE_PCI )
+		boot_device_desc.location = ix86->regs.bx;
 
 	/* Perform one-time-only initialisation (e.g. heap) */
 	initialise();
diff --git a/src/include/ipxe/device.h b/src/include/ipxe/device.h
index c59697c..7c593a9 100644
--- a/src/include/ipxe/device.h
+++ b/src/include/ipxe/device.h
@@ -139,4 +139,6 @@ extern struct device * identify_device ( struct interface *intf );
 #define identify_device_TYPE( object_type ) \
 	typeof ( struct device * ( object_type ) )
 
+extern struct device_description boot_device_desc;
+
 #endif /* _IPXE_DEVICE_H */
diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c
index c95a256..972e3bf 100644
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdio.h>
 #include <errno.h>
 #include <ipxe/netdevice.h>
+#include <ipxe/device.h>
 #include <ipxe/dhcp.h>
 #include <ipxe/settings.h>
 #include <ipxe/image.h>
@@ -79,6 +80,13 @@ __weak int pxe_menu_boot ( struct net_device *netdev __unused ) {
  * @ret netdev		Boot network device
  */
 static struct net_device * find_boot_netdev ( void ) {
+	struct net_device *netdev;
+
+	for_each_netdev ( netdev ) {
+		if ( netdev->dev->desc.bus_type == boot_device_desc.bus_type &&
+		     netdev->dev->desc.location == boot_device_desc.location )
+			return netdev;
+	}
 	return NULL;
 }
 
@@ -440,20 +448,18 @@ int netboot ( struct net_device *netdev ) {
  * Boot the system
  */
 int autoboot ( void ) {
-	struct net_device *boot_netdev;
-	struct net_device *netdev;
+	struct net_device *netdev = find_boot_netdev();
 	int rc = -ENODEV;
 
-	/* If we have an identifable boot device, try that first */
-	if ( ( boot_netdev = find_boot_netdev() ) )
-		rc = netboot ( boot_netdev );
+	/* If a boot device is specified, boot only from that device */
+	if ( netdev )
+		return netboot ( netdev );
+	else if ( boot_device_desc.bus_type )
+		return rc;
 
-	/* If that fails, try booting from any of the other devices */
-	for_each_netdev ( netdev ) {
-		if ( netdev == boot_netdev )
-			continue;
+	/* Otherwise, try booting from any device */
+	for_each_netdev ( netdev )
 		rc = netboot ( netdev );
-	}
 
 	printf ( "No more network devices\n" );
 	return rc;




More information about the ipxe-devel mailing list