[ipxe-devel] [PATCH 3/7] ipxe: add local patches

Gerd Hoffmann kraxel at redhat.com
Fri Apr 10 14:17:08 UTC 2015


There are two ipxe patches needed to make efi pxe boots work.
They didn't made it upstream yet, and I don't want to wait any
longer with updating qemu.  So add them here, with some logic
to apply them before building ipxe.

/me still hopes I can revert that patch some day.

Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
---
 roms/Makefile                                      |  12 +-
 ...rove-compliance-with-the-EFI_SIMPLE_NETWO.patch | 160 +++++++++++++++++++++
 ...0002-efi-make-load-file-protocol-optional.patch | 102 +++++++++++++
 3 files changed, 271 insertions(+), 3 deletions(-)
 create mode 100644 roms/ipxe-patches/0001-efi_snp-improve-compliance-with-the-EFI_SIMPLE_NETWO.patch
 create mode 100644 roms/ipxe-patches/0002-efi-make-load-file-protocol-optional.patch

diff --git a/roms/Makefile b/roms/Makefile
index 461cb49..ab4532c 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -115,12 +115,12 @@ efi-rom-%: build-pxe-roms build-efi-roms
 		-ec ipxe/src/bin-x86_64-efi/$(VID)$(DID).efidrv \
 		-o ../pc-bios/efi-$*.rom
 
-build-pxe-roms: ipxe/src/config/local/general.h
+build-pxe-roms: ipxe/qemu-patches ipxe/src/config/local/general.h
 	$(MAKE) -C ipxe/src GITVERSION="" \
 		CROSS_COMPILE=$(x86_64_cross_prefix) \
 		$(patsubst %,bin/%.rom,$(pxerom_targets))
 
-build-efi-roms: build-pxe-roms ipxe/src/config/local/general.h
+build-efi-roms: ipxe/qemu-patches build-pxe-roms ipxe/src/config/local/general.h
 	$(MAKE) -C ipxe/src GITVERSION="" \
 		CROSS_COMPILE=$(x86_64_cross_prefix) \
 		$(patsubst %,bin-i386-efi/%.efidrv,$(pxerom_targets)) \
@@ -129,6 +129,12 @@ build-efi-roms: build-pxe-roms ipxe/src/config/local/general.h
 ipxe/src/config/local/%: config.ipxe.%
 	cp $< $@
 
+ipxe/qemu-patches:
+	for patch in ipxe-patches/*; do \
+		echo "# applying $$patch"; \
+		cat $$patch | (cd ipxe; patch -p1); \
+	done
+	touch $@
 
 slof:
 	$(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
@@ -148,6 +154,6 @@ clean:
 	$(MAKE) -C sgabios clean
 	rm -f sgabios/.depend
 	$(MAKE) -C ipxe/src veryclean
-	(cd ipxe; rm -f src/config/local/*.h)
+	(cd ipxe; git reset --hard; rm -f qemu-patches src/config/local/*.h)
 	$(MAKE) -C SLOF clean
 	rm -rf u-boot/build.e500
diff --git a/roms/ipxe-patches/0001-efi_snp-improve-compliance-with-the-EFI_SIMPLE_NETWO.patch b/roms/ipxe-patches/0001-efi_snp-improve-compliance-with-the-EFI_SIMPLE_NETWO.patch
new file mode 100644
index 0000000..7f6febf
--- /dev/null
+++ b/roms/ipxe-patches/0001-efi_snp-improve-compliance-with-the-EFI_SIMPLE_NETWO.patch
@@ -0,0 +1,160 @@
+From 9e870d92035ec7ca946e702236bfe104e964f8c6 Mon Sep 17 00:00:00 2001
+From: Laszlo Ersek <lersek at redhat.com>
+Date: Thu, 22 Jan 2015 22:05:35 +0100
+Subject: [PATCH 1/2] efi_snp: improve compliance with the
+ EFI_SIMPLE_NETWORK_PROTOCOL spec
+
+The efi_snp interface dates back to 2008, when the GetStatus() interface
+must have been seriously under-specified. The UEFI Specification (2.4)
+specifies EFI_SIMPLE_NETWORK_PROTOCOL in detail however. In short:
+
+- the Transmit() interface is assumed to link (not copy) the SNP client's
+  buffer and return at once (without blocking), taking ownership of the
+  buffer temporarily;
+
+- the GetStatus() interface releases one of the completed (transmitted or
+  internally copied) buffers back to the caller. If there are several
+  completed buffers, it is unspecified which one is returned.
+
+The EFI build of the grub boot loader actually verifies the buffer address
+returned by GetStatus(), therefore in efi_snp we must at least fake the
+queueing of client buffers. This patch doesn't track client buffers
+together with the internally queued io_buffer structures, we consider a
+client buffer recyclable as soon as we make a deep copy of it and queue
+the copy internally.
+
+Signed-off-by: Laszlo Ersek <lersek at redhat.com>
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+---
+ src/include/ipxe/efi/efi_snp.h |  6 +++++
+ src/interface/efi/efi_snp.c    | 54 ++++++++++++++++++++++++------------------
+ 2 files changed, 37 insertions(+), 23 deletions(-)
+
+diff --git a/src/include/ipxe/efi/efi_snp.h b/src/include/ipxe/efi/efi_snp.h
+index a18bced..863a81a 100644
+--- a/src/include/ipxe/efi/efi_snp.h
++++ b/src/include/ipxe/efi/efi_snp.h
+@@ -18,6 +18,8 @@
+ #include <ipxe/efi/Protocol/HiiDatabase.h>
+ #include <ipxe/efi/Protocol/LoadFile.h>
+ 
++#define MAX_RECYCLED_TXBUFS 64
++
+ /** An SNP device */
+ struct efi_snp_device {
+ 	/** List of SNP devices */
+@@ -44,6 +46,10 @@ struct efi_snp_device {
+ 	 * Used in order to generate TX completions.
+ 	 */
+ 	unsigned int tx_count_txbufs;
++	/** Holds the addresses of recycled SNP client buffers; a ring. */
++	void *tx_recycled_txbufs[MAX_RECYCLED_TXBUFS];
++	/** The index of the first buffer to return to the SNP client. */
++	unsigned tx_first_txbuf;
+ 	/** Outstanding RX packet count (via "interrupt status") */
+ 	unsigned int rx_count_interrupts;
+ 	/** Outstanding RX packet count (via WaitForPacket event) */
+diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
+index 67fba34..c21af33 100644
+--- a/src/interface/efi/efi_snp.c
++++ b/src/interface/efi/efi_snp.c
+@@ -68,6 +68,14 @@ static void efi_snp_set_state ( struct efi_snp_device *snpdev ) {
+ 		 */
+ 		mode->State = EfiSimpleNetworkInitialized;
+ 	}
++
++	if (mode->State != EfiSimpleNetworkInitialized) {
++		/* Zero the number of recycled buffers when moving to any other
++		 * state than Initialized. Transmit() and GetStatus() are only
++		 * valid in Initialized.
++		 */
++		snpdev->tx_count_txbufs = 0;
++	}
+ }
+ 
+ /**
+@@ -446,12 +454,12 @@ efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
+  *
+  * @v snp		SNP interface
+  * @v interrupts	Interrupt status, or NULL
+- * @v txbufs		Recycled transmit buffer address, or NULL
++ * @v txbuf		Recycled transmit buffer address, or NULL
+  * @ret efirc		EFI status code
+  */
+ static EFI_STATUS EFIAPI
+ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+-		     UINT32 *interrupts, VOID **txbufs ) {
++		     UINT32 *interrupts, VOID **txbuf ) {
+ 	struct efi_snp_device *snpdev =
+ 		container_of ( snp, struct efi_snp_device, snp );
+ 
+@@ -485,30 +493,22 @@ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ 		DBGC2 ( snpdev, " INTS:%02x", *interrupts );
+ 	}
+ 
+-	/* TX completions.  It would be possible to design a more
+-	 * idiotic scheme for this, but it would be a challenge.
+-	 * According to the UEFI header file, txbufs will be filled in
+-	 * with a list of "recycled transmit buffers" (i.e. completed
+-	 * TX buffers).  Observant readers may care to note that
+-	 * *txbufs is a void pointer.  Precisely how a list of
+-	 * completed transmit buffers is meant to be represented as an
+-	 * array of voids is left as an exercise for the reader.
+-	 *
+-	 * The only users of this interface (MnpDxe/MnpIo.c and
+-	 * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
+-	 * seeing a non-NULL result return in txbufs.  This is valid
+-	 * provided that they do not ever attempt to transmit more
+-	 * than one packet concurrently (and that TX never times out).
++	/* In efi_snp_transmit() we enqueue packets by copying them (not by
++	 * linking them), hence we can recycle them immediately to the SNP
++	 * client.
+ 	 */
+-	if ( txbufs ) {
+-		if ( snpdev->tx_count_txbufs &&
+-		     list_empty ( &snpdev->netdev->tx_queue ) ) {
+-			*txbufs = "Which idiot designed this API?";
++	if ( txbuf ) {
++		if ( snpdev->tx_count_txbufs ) {
++			unsigned first;
++
++			first = snpdev->tx_first_txbuf++;
++			snpdev->tx_first_txbuf %= MAX_RECYCLED_TXBUFS;
++			*txbuf = snpdev->tx_recycled_txbufs[first];
+ 			snpdev->tx_count_txbufs--;
+ 		} else {
+-			*txbufs = NULL;
++			*txbuf = NULL;
+ 		}
+-		DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
++		DBGC2 ( snpdev, " TX:%p", *txbuf );
+ 	}
+ 
+ 	DBGC2 ( snpdev, "\n" );
+@@ -560,6 +560,12 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ 	if ( efi_snp_claimed )
+ 		return EFI_NOT_READY;
+ 
++	assert ( snpdev->tx_count_txbufs <= MAX_RECYCLED_TXBUFS );
++	if ( snpdev->tx_count_txbufs == MAX_RECYCLED_TXBUFS ) {
++		/* No room to recycle another buffer. */
++		return EFI_NOT_READY;
++	}
++
+ 	/* Sanity checks */
+ 	if ( ll_header_len ) {
+ 		if ( ll_header_len != ll_protocol->ll_header_len ) {
+@@ -626,7 +632,9 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
+ 
+ 	/* Record transmission as outstanding */
+ 	snpdev->tx_count_interrupts++;
+-	snpdev->tx_count_txbufs++;
++	snpdev->tx_recycled_txbufs[(snpdev->tx_first_txbuf +
++				    snpdev->tx_count_txbufs++
++				   ) % MAX_RECYCLED_TXBUFS] = data;
+ 
+ 	return 0;
+ 
+-- 
+1.8.3.1
+
diff --git a/roms/ipxe-patches/0002-efi-make-load-file-protocol-optional.patch b/roms/ipxe-patches/0002-efi-make-load-file-protocol-optional.patch
new file mode 100644
index 0000000..f921a3b
--- /dev/null
+++ b/roms/ipxe-patches/0002-efi-make-load-file-protocol-optional.patch
@@ -0,0 +1,102 @@
+From 2daea2b8dd2c504a4f76a6b0b67bd3c4a2957fc7 Mon Sep 17 00:00:00 2001
+From: Gerd Hoffmann <kraxel at redhat.com>
+Date: Tue, 10 Feb 2015 14:28:09 +0100
+Subject: [PATCH 2/2] [efi] make load file protocol optional
+
+The load file implementation added by commit
+c7c3d839fc9120aee28de9aabe452dc85ad91502 doesn't support loading
+arbitrary files from the tftp server, so efi applications trying
+to do exactly that fail to boot:
+
+  iPXE 1.0.0+ (17ace) -- Open Source Network Boot Firmware -- http://ipxe.org
+  Features: HTTP DNS TFTP EFI Menu
+
+  net0: 52:54:00:47:d3:07 using virtio-net on PCI00:09.0 (open)
+    [Link:up, TX:0 TXE:0 RX:13 RXE:2]
+    [RXE: 2 x "Operation not supported (http://ipxe.org/3c086083)"]
+  Configuring (net0 52:54:00:47:d3:07)...... ok
+  net0: 192.168.132.93/255.255.255.0 gw 192.168.132.1
+  Next server: 192.168.132.1
+  Filename: shim.efi
+  tftp://192.168.132.1/shim.efi... ok
+  Failed to open grubx64.efi - Not Found
+  Failed to load image grubx64.efi: Not Found
+  Failed to open MokManager.efi - Not Found
+  Failed to load image MokManager.efi: Not Found
+  Could not boot image: Error 0x7f04828e (http://ipxe.org/7f04828e)
+
+  Boot Failed. EFI Network
+
+This is not acceptable for qemu.  efi pxe configurations which work
+just fine with real hardware must work with qemu virtual machines too.
+
+This patch adds a config option for the load file protocol
+implementation, to allow it being disabled, so we can turn it off
+for the pxe roms shipped with qemu.
+
+The default for the new option maintains current behavior, i.e.
+load file is enabled unless you override it in config/local/general.h
+
+Suggested-by: Laszlo Ersek <lersek at redhat.com>
+
+See discussion here:
+  http://lists.ipxe.org/pipermail/ipxe-devel/2015-February/003979.html
+
+Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
+---
+ src/config/general.h        | 6 ++++++
+ src/interface/efi/efi_snp.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/src/config/general.h b/src/config/general.h
+index 65c1f85..8c91601 100644
+--- a/src/config/general.h
++++ b/src/config/general.h
+@@ -142,6 +142,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+ #undef	NONPNP_HOOK_INT19	/* Hook INT19 on non-PnP BIOSes */
+ 
+ /*
++ * EFI specific options
++ *
++ */
++#define EFI_PROTO_LOAD_FILE	/* register LOAD_FILE protocol */
++
++/*
+  * Error message tables to include
+  *
+  */
+diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
+index c21af33..85f4fa0 100644
+--- a/src/interface/efi/efi_snp.c
++++ b/src/interface/efi/efi_snp.c
+@@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
+ #include <ipxe/efi/efi_utils.h>
+ #include <ipxe/efi/efi_snp.h>
+ #include <usr/autoboot.h>
++#include <config/general.h>
+ 
+ /** List of SNP devices */
+ static LIST_HEAD ( efi_snp_devices );
+@@ -1033,7 +1034,9 @@ static int efi_snp_probe ( struct net_device *netdev ) {
+ 			&efi_nii_protocol_guid, &snpdev->nii,
+ 			&efi_nii31_protocol_guid, &snpdev->nii,
+ 			&efi_component_name2_protocol_guid, &snpdev->name2,
++#ifdef EFI_PROTO_LOAD_FILE
+ 			&efi_load_file_protocol_guid, &snpdev->load_file,
++#endif
+ 			NULL ) ) != 0 ) {
+ 		rc = -EEFI ( efirc );
+ 		DBGC ( snpdev, "SNPDEV %p could not install protocols: "
+@@ -1082,7 +1085,9 @@ static int efi_snp_probe ( struct net_device *netdev ) {
+ 			&efi_nii_protocol_guid, &snpdev->nii,
+ 			&efi_nii31_protocol_guid, &snpdev->nii,
+ 			&efi_component_name2_protocol_guid, &snpdev->name2,
++#ifdef EFI_PROTO_LOAD_FILE
+ 			&efi_load_file_protocol_guid, &snpdev->load_file,
++#endif
+ 			NULL );
+  err_install_protocol_interface:
+ 	free ( snpdev->path );
+-- 
+1.8.3.1
+
-- 
1.8.3.1




More information about the ipxe-devel mailing list