uncommitted - ipxe

Ready changes

Summary

Import uploads missing from VCS:

Diff

diff --git a/.pc/.quilt_patches b/.pc/.quilt_patches
new file mode 100644
index 00000000..6857a8d4
--- /dev/null
+++ b/.pc/.quilt_patches
@@ -0,0 +1 @@
+debian/patches
diff --git a/.pc/.quilt_series b/.pc/.quilt_series
new file mode 100644
index 00000000..c2067066
--- /dev/null
+++ b/.pc/.quilt_series
@@ -0,0 +1 @@
+series
diff --git a/.pc/.version b/.pc/.version
new file mode 100644
index 00000000..0cfbf088
--- /dev/null
+++ b/.pc/.version
@@ -0,0 +1 @@
+2
diff --git a/.pc/applied-patches b/.pc/applied-patches
new file mode 100644
index 00000000..e95da723
--- /dev/null
+++ b/.pc/applied-patches
@@ -0,0 +1,2 @@
+debian-changes
+f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch
diff --git a/.pc/debian-changes/src/arch/x86/prefix/romprefix.S b/.pc/debian-changes/src/arch/x86/prefix/romprefix.S
new file mode 100644
index 00000000..3abef0ea
--- /dev/null
+++ b/.pc/debian-changes/src/arch/x86/prefix/romprefix.S
@@ -0,0 +1,911 @@
+/* At entry, the processor is in 16 bit real mode and the code is being
+ * executed from an address it was not linked to. Code must be pic and
+ * 32 bit sensitive until things are fixed up.
+ *
+ * Also be very careful as the stack is at the rear end of the interrupt
+ * table so using a noticeable amount of stack space is a no-no.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+
+#include <librm.h>
+#include <config/general.h>
+#include <config/branding.h>
+
+#define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
+#define PMM_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'M' << 16 ) + ( 'M' << 24 ) )
+#define PCI_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( ' ' << 24 ) )
+#define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
+#define PMM_ALLOCATE 0x0000
+#define PMM_FIND 0x0001
+#define PMM_HANDLE_BASE ( ( ( 'F' - 'A' + 1 ) << 26 ) + \
+			  ( ( 'E' - 'A' + 1 ) << 21 ) + \
+			  ( ( 'N' - 'A' + 1 ) << 16 ) )
+#define PMM_HANDLE_BASE_IMAGE_SOURCE \
+	( PMM_HANDLE_BASE | 0x00001000 )
+#define PMM_HANDLE_BASE_DECOMPRESS_TO \
+	( PMM_HANDLE_BASE | 0x00002000 )
+#define PCI_FUNC_MASK 0x07
+
+/* ROM banner timeout, converted to a number of (18Hz) timer ticks. */
+#define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 )
+
+/* Allow payload to be excluded from ROM size
+ */
+#if ROMPREFIX_EXCLUDE_PAYLOAD
+#define	ZINFO_TYPE_ADxB "ADHB"
+#define	ZINFO_TYPE_ADxW "ADHW"
+#else
+#define	ZINFO_TYPE_ADxB "ADDB"
+#define	ZINFO_TYPE_ADxW "ADDW"
+#endif
+
+/* Allow ROM to be marked as containing multiple images
+ */
+#if ROMPREFIX_MORE_IMAGES
+#define INDICATOR 0x00
+#else
+#define INDICATOR 0x80
+#endif
+
+/* Default to building a PCI ROM if no bus type is specified
+ */
+#ifndef BUSTYPE
+#define BUSTYPE "PCIR"
+#endif
+
+	.text
+	.code16
+	.arch i386
+	.section ".prefix", "ax", @progbits
+	.globl	_rom_start
+_rom_start:
+	
+	.org	0x00
+romheader:
+	.word	0xAA55			/* BIOS extension signature */
+romheader_size:	.byte 0			/* Size in 512-byte blocks */
+	jmp	init			/* Initialisation vector */
+checksum:
+	.byte	0
+	.org	0x10
+	.word	ipxeheader
+	.org	0x16
+	.word	undiheader
+.ifeqs	BUSTYPE, "PCIR"
+	.org	0x18
+	.word	pciheader
+.endif
+	.org	0x1a
+	.word	pnpheader
+	.size romheader, . - romheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	ZINFO_TYPE_ADxB
+	.long	romheader_size
+	.long	512
+	.long	0
+	.previous
+
+.ifeqs	BUSTYPE, "PCIR"
+	.align	4
+pciheader:
+	.ascii	"PCIR"			/* Signature */
+	.word	pci_vendor_id		/* Vendor identification */ 
+	.word	pci_device_id		/* Device identification */
+	.word	( pci_devlist - pciheader ) /* Device list pointer */
+	.word	pciheader_len		/* PCI data structure length */
+	.byte	0x03			/* PCI data structure revision */
+	.byte	0x00, 0x00, 0x02	/* Class code */
+pciheader_image_length:
+	.word	0			/* Image length */
+	.word	0x0001			/* Revision level */
+	.byte	0x00			/* Code type */
+	.byte	INDICATOR		/* Last image indicator */
+pciheader_runtime_length:
+	.word	0			/* Maximum run-time image length */
+	.word	0x0000			/* Configuration utility code header */
+	.word	0x0000			/* DMTF CLP entry point */
+	.equ pciheader_len, . - pciheader
+	.size pciheader, . - pciheader
+
+	/* PCI additional device list (filled in by linker) */
+	.section ".pci_devlist.00000000", "a", @progbits
+pci_devlist:
+	.previous
+	.section ".pci_devlist.ffffffff", "a", @progbits
+pci_devlist_end:
+	.short	0x0000 /* List terminator */
+	.previous
+	/* Ensure that terminator is always present */
+	.reloc pciheader, RELOC_TYPE_NONE, pci_devlist_end
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	ZINFO_TYPE_ADxW
+	.long	pciheader_image_length
+	.long	512
+	.long	0
+	.ascii	"ADHW"
+	.long	pciheader_runtime_length
+	.long	512
+	.long	0
+	.previous
+.endif	/* PCIR */
+
+	/* PnP doesn't require any particular alignment, but IBM
+	 * BIOSes will scan on 16-byte boundaries rather than using
+	 * the offset stored at 0x1a
+	 */
+	.align	16
+pnpheader:
+	.ascii	"$PnP"			/* Signature */
+	.byte	0x01			/* Structure revision */
+	.byte	( pnpheader_len	/ 16 )	/* Length (in 16 byte increments) */
+	.word	0x0000			/* Offset of next header */
+	.byte	0x00			/* Reserved */
+	.byte	0x00			/* Checksum */
+	.long	0x00000000		/* Device identifier */
+	.word	mfgstr			/* Manufacturer string */
+	.word	prodstr			/* Product name */
+	.byte	0x02			/* Device base type code */
+	.byte	0x00			/* Device sub-type code */
+	.byte	0x00			/* Device interface type code */
+	.byte	0xf4			/* Device indicator */
+	.word	0x0000			/* Boot connection vector */
+	.word	0x0000			/* Disconnect vector */
+	.word	bev_entry		/* Boot execution vector */
+	.word	0x0000			/* Reserved */
+	.word	0x0000			/* Static resource information vector*/
+	.equ pnpheader_len, . - pnpheader
+	.size pnpheader, . - pnpheader
+
+/* Manufacturer string */
+mfgstr:
+	.asciz	"http://ipxe.org"
+	.size mfgstr, . - mfgstr
+
+/* Product string
+ *
+ * Defaults to PRODUCT_SHORT_NAME.  If the ROM image is writable at
+ * initialisation time, it will be filled in to include the PCI
+ * bus:dev.fn number of the card as well.
+ */
+prodstr:
+	.ascii	PRODUCT_SHORT_NAME
+.ifeqs	BUSTYPE, "PCIR"
+prodstr_separator:
+	.byte	0
+	.ascii	"(PCI "
+prodstr_pci_id:
+	.ascii	"xx:xx.x)"		/* Filled in by init code */
+.endif	/* PCIR */
+	.byte	0
+	.size prodstr, . - prodstr
+
+	.globl	undiheader	
+	.weak	undiloader
+	.align	4
+undiheader:
+	.ascii	"UNDI"			/* Signature */
+	.byte	undiheader_len		/* Length of structure */
+	.byte	0			/* Checksum */
+	.byte	0			/* Structure revision */
+	.byte	0,1,2			/* PXE version: 2.1.0 */
+	.word	undiloader		/* Offset to loader routine */
+	.word	_data16_memsz		/* Stack segment size */
+	.word	_data16_memsz		/* Data segment size */
+	.word	_text16_memsz		/* Code segment size */
+	.ascii	BUSTYPE			/* Bus type */
+	.equ undiheader_len, . - undiheader
+	.size undiheader, . - undiheader
+
+	.align	4
+ipxeheader:
+	.ascii	"iPXE"			/* Signature */
+	.byte	ipxeheader_len		/* Length of structure */
+	.byte	0			/* Checksum */
+shrunk_rom_size:
+	.byte	0			/* Shrunk size (in 512-byte blocks) */
+	.byte	0			/* Reserved */
+build_id:
+	.long	_build_id		/* Randomly-generated build ID */
+	.equ ipxeheader_len, . - ipxeheader
+	.size ipxeheader, . - ipxeheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADHB"
+	.long	shrunk_rom_size
+	.long	512
+	.long	0
+	.previous
+
+/* Initialisation (called once during POST)
+ *
+ * Determine whether or not this is a PnP system via a signature
+ * check.  If it is PnP, return to the PnP BIOS indicating that we are
+ * a boot-capable device; the BIOS will call our boot execution vector
+ * if it wants to boot us.  If it is not PnP, hook INT 19.
+ */
+init:
+	/* Preserve registers, clear direction flag, set %ds=%cs */
+	pushaw
+	pushw	%ds
+	pushw	%es
+	pushw	%fs
+	pushw	%gs
+	cld
+	pushw	%cs
+	popw	%ds
+
+	/* Print message as early as possible */
+	movw	$init_message, %si
+	xorw	%di, %di
+	call	print_message
+
+	/* Store PCI 3.0 runtime segment address for later use, if
+	 * applicable.
+	 */
+.ifeqs	BUSTYPE, "PCIR"
+	movw	%bx, %gs
+.endif
+
+	/* Store PCI bus:dev.fn address, print PCI bus:dev.fn, and add
+	 * PCI bus:dev.fn to product name string, if applicable.
+	 */
+.ifeqs	BUSTYPE, "PCIR"
+	xorw	%di, %di
+	call	print_space
+	movw	%ax, init_pci_busdevfn
+	call	print_pci_busdevfn
+	movw	$prodstr_pci_id, %di
+	call	print_pci_busdevfn
+	movb	$( ' ' ), prodstr_separator
+.endif
+
+	/* Print segment address */
+	xorw	%di, %di
+	call	print_space
+	movw	%cs, %ax
+	call	print_hex_word
+
+	/* Check for PCI BIOS version, if applicable */
+.ifeqs	BUSTYPE, "PCIR"
+	pushl	%ebx
+	pushl	%edx
+	pushl	%edi
+	stc
+	movw	$0xb101, %ax
+	int	$0x1a
+	jc	no_pci3
+	cmpl	$PCI_SIGNATURE, %edx
+	jne	no_pci3
+	testb	%ah, %ah
+	jnz	no_pci3
+	movw	$init_message_pci, %si
+	xorw	%di, %di
+	call	print_message
+	movb	%bh, %al
+	call	print_hex_nibble
+	movb	$( '.' ), %al
+	call	print_character
+	movb	%bl, %al
+	call	print_hex_byte
+	cmpb	$3, %bh
+	jb	no_pci3
+	/* PCI >=3.0: leave %gs as-is if sane */
+	movw	%gs, %ax
+	cmpw	$0xa000, %ax	/* Insane if %gs < 0xa000 */
+	jb	pci3_insane
+	movw	%cs, %bx	/* Sane if %cs == %gs */
+	cmpw	%bx, %ax
+	je	1f
+	movzbw	romheader_size, %cx /* Sane if %cs+len <= %gs */
+	shlw	$5, %cx
+	addw	%cx, %bx
+	cmpw	%bx, %ax
+	jae	1f
+	movw	%cs, %bx	/* Sane if %gs+len <= %cs */
+	addw	%cx, %ax
+	cmpw	%bx, %ax
+	jbe	1f
+pci3_insane: /* PCI 3.0 with insane %gs value: print error and ignore %gs */
+	movb	$( '!' ), %al
+	call	print_character
+	movw	%gs, %ax
+	call	print_hex_word
+no_pci3:
+	/* PCI <3.0: set %gs (runtime segment) = %cs (init-time segment) */
+	pushw	%cs
+	popw	%gs
+1:	popl	%edi
+	popl	%edx
+	popl	%ebx
+.endif	/* PCIR */
+
+	/* Check for PnP BIOS.  Although %es:di should point to the
+	 * PnP BIOS signature on entry, some BIOSes fail to do this.
+	 */
+	movw	$( 0xf000 - 1 ), %bx
+pnp_scan:
+	incw	%bx
+	jz	no_pnp
+	movw	%bx, %es
+	cmpl	$PNP_SIGNATURE, %es:0
+	jne	pnp_scan
+	xorw	%dx, %dx
+	xorw	%si, %si
+	movzbw	%es:5, %cx
+1:	es lodsb
+	addb	%al, %dl
+	loop	1b
+	jnz	pnp_scan
+	/* Is PnP: print PnP message */
+	movw	$init_message_pnp, %si
+	xorw	%di, %di
+	call	print_message
+	jmp	pnp_done
+no_pnp:	/* Not PnP-compliant - hook INT 19 */
+#ifdef NONPNP_HOOK_INT19
+	movw	$init_message_int19, %si
+	xorw	%di, %di
+	call	print_message
+	xorw	%ax, %ax
+	movw	%ax, %es
+	pushl	%es:( 0x19 * 4 )
+	popl	orig_int19
+	pushw	%gs /* %gs contains runtime %cs */
+	pushw	$int19_entry
+	popl	%es:( 0x19 * 4 )
+#endif /* NONPNP_HOOK_INT19 */
+pnp_done:
+
+	/* Check for PMM */
+	movw	$( 0xe000 - 1 ), %bx
+pmm_scan:
+	incw	%bx
+	jz	no_pmm
+	movw	%bx, %es
+	cmpl	$PMM_SIGNATURE, %es:0
+	jne	pmm_scan
+	xorw	%dx, %dx
+	xorw	%si, %si
+	movzbw	%es:5, %cx
+1:	es lodsb
+	addb	%al, %dl
+	loop	1b
+	jnz	pmm_scan
+	/* PMM found: print PMM message */
+	movw	$init_message_pmm, %si
+	xorw	%di, %di
+	call	print_message
+	/* We have PMM and so a 1kB stack: preserve whole registers */
+	pushal
+	/* Allocate image source PMM block.  Round up the size to the
+	 * nearest 4kB (8 512-byte sectors) to work around AMI BIOS bugs.
+	 */
+	movzbl	romheader_size, %ecx
+	addw	extra_size, %cx
+	addw	$0x0007, %cx	/* Round up to multiple of 8 512-byte sectors */
+	andw	$0xfff8, %cx
+	shll	$5, %ecx
+	movl	$PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
+	movw	$get_pmm_image_source, %bp
+	call	get_pmm
+	movl	%esi, image_source
+	jz	1f
+	/* Copy ROM to image source PMM block */
+	pushw	%es
+	xorw	%ax, %ax
+	movw	%ax, %es
+	movl	%esi, %edi
+	xorl	%esi, %esi
+	movzbl	romheader_size, %ecx
+	shll	$7, %ecx
+	addr32 rep movsl	/* PMM presence implies flat real mode */
+	popw	%es
+	/* Shrink ROM */
+	movb	shrunk_rom_size, %al
+	movb	%al, romheader_size
+1:	/* Allocate decompression PMM block.  Allow 4kB for page
+	 * alignment and round up the size to the nearest 128kB, then
+	 * use the size within the PMM handle; this allows the same
+	 * decompression area to be shared between multiple iPXE ROMs
+	 * even with differing build IDs
+	 */
+	movl	$_textdata_memsz_pgh, %ecx
+	addl	$( 0x00000100 /* 4kB */ + 0x00001fff /* 128kB - 1 */ ), %ecx
+	andl	$( 0xffffe000 /* ~( 128kB - 1 ) */ ), %ecx
+	movl	%ecx, %ebx
+	shrw	$12, %bx
+	orl	$PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
+	movw	$get_pmm_decompress_to, %bp
+	call	get_pmm
+	addl	$( 0x00000fff /* 4kB - 1 */ ), %esi
+	andl	$( 0xfffff000 /* ~( 4kB - 1 ) */ ), %esi
+	movl	%esi, decompress_to
+	/* Restore registers */
+	popal
+no_pmm:
+
+	/* Update checksum */
+	xorw	%bx, %bx
+	xorw	%si, %si
+	movzbw	romheader_size, %cx
+	shlw	$9, %cx
+1:	lodsb
+	addb	%al, %bl
+	loop	1b
+	subb	%bl, checksum
+
+	/* Copy self to option ROM space, if applicable.  Required for
+	 * PCI3.0, which loads us to a temporary location in low
+	 * memory.  Will be a no-op for lower PCI versions.
+	 */
+.ifeqs	BUSTYPE, "PCIR"
+	/* Get runtime segment address and length */
+	movw	%gs, %ax
+	movw	%ax, %es
+	movzbw	romheader_size, %cx
+	/* Print runtime segment address */
+	xorw	%di, %di
+	call	print_space
+	call	print_hex_word
+	/* Fail if we have insufficient space in final location */
+	movw	%cs, %si
+	cmpw	%si, %ax
+	je	1f
+	cmpw	pciheader_runtime_length, %cx
+	jbe	1f
+	movb	$( '!' ), %al
+	call	print_character
+	xorw	%cx, %cx
+1:	/* Copy to final location */
+	shlw	$9, %cx
+	xorw	%si, %si
+	xorw	%di, %di
+	cs rep	movsb
+.endif
+
+	/* Skip prompt if this is not the first PCI function, if applicable */
+.ifeqs	BUSTYPE, "PCIR"
+	testb	$PCI_FUNC_MASK, init_pci_busdevfn
+	jnz	no_shell
+.endif
+	/* Prompt for POST-time shell */
+	movw	$init_message_prompt, %si
+	xorw	%di, %di
+	call	print_message
+	movw	$prodstr, %si
+	call	print_message
+	movw	$init_message_dots, %si
+	call	print_message
+	/* Wait for Ctrl-B */
+	movw	$0xff02, %bx
+	call	wait_for_key
+	/* Clear prompt */
+	pushf
+	xorw	%di, %di
+	call	print_kill_line
+	movw	$init_message_done, %si
+	call	print_message
+	popf
+	jnz	no_shell
+	/* Ctrl-B was pressed: invoke iPXE.  The keypress will be
+	 * picked up by the initial shell prompt, and we will drop
+	 * into a shell.
+	 */
+	xorl	%ebp, %ebp	/* Inhibit use of INT 15,e820 and INT 15,e801 */
+	pushw	%cs
+	call	exec
+no_shell:
+	movb	$( '\n' ), %al
+	xorw	%di, %di
+	call	print_character
+
+	/* Restore registers */
+	popw	%gs
+	popw	%fs
+	popw	%es
+	popw	%ds
+	popaw
+
+	/* Indicate boot capability to PnP BIOS, if present */
+	movw	$0x20, %ax
+	lret
+	.size init, . - init
+
+/* Attempt to find or allocate PMM block
+ *
+ * Parameters:
+ *  %ecx : size of block to allocate, in paragraphs
+ *  %ebx : PMM handle base
+ *  %bp : routine to check acceptability of found blocks
+ *  %es:0000 : PMM structure
+ * Returns:
+ *  %ebx : PMM handle
+ *  %esi : allocated block address, or zero (with ZF set) if allocation failed
+ */
+get_pmm:
+	/* Preserve registers */
+	pushl	%eax
+	pushw	%di
+	movw	$( ' ' ), %di
+get_pmm_find:
+	/* Try to find existing block */
+	pushl	%ebx		/* PMM handle */
+	pushw	$PMM_FIND
+	lcall	*%es:7
+	addw	$6, %sp
+	pushw	%dx
+	pushw	%ax
+	popl	%esi
+	/* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
+	incl	%esi
+	jz	get_pmm_allocate
+	decl	%esi
+	jz	get_pmm_allocate
+	/* Block found - check acceptability */
+	call	*%bp
+	jnc	get_pmm_done
+	/* Block not acceptable - increment handle and retry */
+	incl	%ebx
+	jmp	get_pmm_find
+get_pmm_allocate:
+	/* Block not found - try to allocate new block */
+	pushw	$0x0002		/* Extended memory */
+	pushl	%ebx		/* PMM handle */
+	pushl	%ecx		/* Length */
+	pushw	$PMM_ALLOCATE
+	lcall	*%es:7
+	addw	$12, %sp
+	pushw	%dx
+	pushw	%ax
+	popl	%esi
+	movw	$( '+' ), %di	/* Indicate allocation attempt */
+get_pmm_done:
+	/* Print block address */
+	movw	%di, %ax
+	xorw	%di, %di
+	call	print_character
+	movl	%esi, %eax
+	call	print_hex_dword
+	/* Treat 0xffffffff (not supported) as 0x00000000 (allocation
+	 * failed), and set ZF to indicate a zero result.
+	 */
+	incl	%esi
+	jz	1f
+	decl	%esi
+1:	/* Restore registers and return */
+	popw	%di
+	popl	%eax
+	ret
+	.size	get_pmm, . - get_pmm
+
+	/* Check acceptability of image source block */
+get_pmm_image_source:
+	pushw	%es
+	xorw	%ax, %ax
+	movw	%ax, %es
+	movl	build_id, %eax
+	addr32 cmpl %es:build_id(%esi), %eax
+	je	1f
+	stc
+1:	popw	%es
+	ret
+	.size	get_pmm_image_source, . - get_pmm_image_source
+
+	/* Check acceptability of decompression block */
+get_pmm_decompress_to:
+	clc
+	ret
+	.size	get_pmm_decompress_to, . - get_pmm_decompress_to
+
+/*
+ * Note to hardware vendors:
+ *
+ * If you wish to brand this boot ROM, please do so by defining the
+ * strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
+ *
+ * While nothing in the GPL prevents you from removing all references
+ * to iPXE or http://ipxe.org, we prefer you not to do so.
+ *
+ * If you have an OEM-mandated branding requirement that cannot be
+ * satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
+ * please contact us.
+ *
+ * [ Including an ASCII NUL in PRODUCT_NAME is considered to be
+ *   bypassing the spirit of this request! ]
+ */
+init_message:
+	.ascii	"\n"
+	.ascii	PRODUCT_NAME
+	.ascii	"\n"
+	.ascii	PRODUCT_SHORT_NAME
+	.ascii	" ("
+	.ascii	PRODUCT_URI
+	.asciz	")"
+	.size	init_message, . - init_message
+.ifeqs	BUSTYPE, "PCIR"
+init_message_pci:
+	.asciz	" PCI"
+	.size	init_message_pci, . - init_message_pci
+.endif	/* PCIR */
+init_message_pnp:
+	.asciz	" PnP"
+	.size	init_message_pnp, . - init_message_pnp
+init_message_pmm:
+	.asciz	" PMM"
+	.size	init_message_pmm, . - init_message_pmm
+init_message_int19:
+	.asciz	" INT19"
+	.size	init_message_int19, . - init_message_int19
+init_message_prompt:
+	.asciz	"\nPress Ctrl-B to configure "
+	.size	init_message_prompt, . - init_message_prompt
+init_message_dots:
+	.asciz	"..."
+	.size	init_message_dots, . - init_message_dots
+init_message_done:
+	.asciz	"\n\n"
+	.size	init_message_done, . - init_message_done
+
+/* PCI bus:dev.fn
+ *
+ */
+.ifeqs	BUSTYPE, "PCIR"
+init_pci_busdevfn:
+	.word	0
+	.size	init_pci_busdevfn, . - init_pci_busdevfn
+.endif	/* PCIR */
+
+/* Image source area
+ *
+ * May be either zero (indicating to use option ROM space as source),
+ * or within a PMM-allocated block.
+ */
+	.globl	image_source
+image_source:
+	.long	0
+	.size	image_source, . - image_source
+
+/* Additional image source size (in 512-byte sectors)
+ *
+ */
+extra_size:
+	.word	0
+	.size	extra_size, . - extra_size
+
+/* Temporary decompression area
+ *
+ * May be either zero (indicating to use default decompression area in
+ * high memory), or within a PMM-allocated block.
+ */
+	.globl	decompress_to
+decompress_to:
+	.long	0
+	.size	decompress_to, . - decompress_to
+
+/* Boot Execution Vector entry point
+ *
+ * Called by the PnP BIOS when it wants to boot us.
+ */
+bev_entry:
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
+	pushw	%cs
+	call	exec
+	lret
+	.size	bev_entry, . - bev_entry
+
+/* INT19 entry point
+ *
+ * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
+ * attempt to return via the original INT 19 vector (if we were able
+ * to store it).
+ */
+int19_entry:
+	pushw	%cs
+	popw	%ds
+	/* Prompt user to press B to boot */
+	movw	$int19_message_prompt, %si
+	xorw	%di, %di
+	call	print_message
+	movw	$prodstr, %si
+	call	print_message
+	movw	$int19_message_dots, %si
+	call	print_message
+	movw	$0xdf4e, %bx
+	call	wait_for_key
+	pushf
+	xorw	%di, %di
+	call	print_kill_line
+	movw	$int19_message_done, %si
+	call	print_message
+	popf
+	jz	1f
+	/* Leave keypress in buffer and start iPXE.  The keypress will
+	 * cause the usual initial Ctrl-B prompt to be skipped.
+	 */
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
+	pushw	%cs
+	call	exec
+1:	/* Try to call original INT 19 vector */
+	movl	%cs:orig_int19, %eax
+	testl	%eax, %eax
+	je	2f
+	ljmp	*%cs:orig_int19
+2:	/* No chained vector: issue INT 18 as a last resort */
+	int	$0x18
+	.size	int19_entry, . - int19_entry
+orig_int19:
+	.long	0
+	.size	orig_int19, . - orig_int19
+
+int19_message_prompt:
+	.asciz	"Press N to skip booting from "
+	.size	int19_message_prompt, . - int19_message_prompt
+int19_message_dots:
+	.asciz	"..."
+	.size	int19_message_dots, . - int19_message_dots
+int19_message_done:
+	.asciz	"\n\n"
+	.size	int19_message_done, . - int19_message_done
+	
+/* Execute as a boot device
+ *
+ */
+exec:	/* Set %ds = %cs */
+	pushw	%cs
+	popw	%ds
+
+	/* Print message as soon as possible */
+	movw	$prodstr, %si
+	xorw	%di, %di
+	call	print_message
+	movw	$exec_message_pre_install, %si
+	call	print_message
+
+	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
+	pushl	$STACK_MAGIC
+	movw	%ss, %cx
+	movw	%sp, %dx
+
+	/* Obtain a reasonably-sized temporary stack */
+	xorw	%bx, %bx
+	movw	%bx, %ss
+	movw	$0x7c00, %sp
+
+	/* Install iPXE */
+	call	alloc_basemem
+	movl	image_source, %esi
+	movl	decompress_to, %edi
+	call	install_prealloc
+
+	/* Print message indicating successful installation */
+	movw	$exec_message_post_install, %si
+	xorw	%di, %di
+	call	print_message
+
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
+	/* Jump to .text16 segment */
+	pushw	%ax
+	pushw	$1f
+	lret
+	.section ".text16", "awx", @progbits
+1:
+	/* Retrieve PCI bus:dev.fn, if applicable */
+.ifeqs	BUSTYPE, "PCIR"
+	movw	init_pci_busdevfn, %ax
+.endif
+
+	/* Set up %ds for access to .data16 */
+	movw	%bx, %ds
+
+	/* Store PCI bus:dev.fn, if applicable */
+.ifeqs	BUSTYPE, "PCIR"
+#ifdef AUTOBOOT_ROM_FILTER
+	movw	%ax, autoboot_busdevfn
+#endif /* AUTOBOOT_ROM_FILTER */
+.endif
+
+	/* Run iPXE */
+	virtcall main
+
+	/* Set up flat real mode for return to BIOS */
+	call	flatten_real_mode
+
+	/* Uninstall iPXE */
+	call	uninstall
+
+	/* Restore BIOS stack */
+	movw	%cx, %ss
+	movw	%dx, %sp
+
+	/* Check magic word on BIOS stack */
+	popl	%eax
+	cmpl	$STACK_MAGIC, %eax
+	jne	1f
+	/* BIOS stack OK: return to caller */
+	lret
+1:	/* BIOS stack corrupt: use INT 18 */
+	int	$0x18
+	.previous
+
+exec_message_pre_install:
+	.asciz	" starting execution..."
+	.size exec_message_pre_install, . - exec_message_pre_install
+exec_message_post_install:
+	.asciz	"ok\n"
+	.size exec_message_post_install, . - exec_message_post_install
+
+/* Wait for key press specified by %bl (masked by %bh)
+ *
+ * Used by init and INT19 code when prompting user.  If the specified
+ * key is pressed, it is left in the keyboard buffer.
+ *
+ * Returns with ZF set iff specified key is pressed.
+ */
+wait_for_key:
+	/* Preserve registers */
+	pushw	%cx
+	pushw	%ax
+1:	/* Empty the keyboard buffer before waiting for input */
+	movb	$0x01, %ah
+	int	$0x16
+	jz	2f
+	xorw	%ax, %ax
+	int	$0x16
+	jmp	1b
+2:	/* Wait for a key press */
+	movw	$ROM_BANNER_TIMEOUT_TICKS, %cx
+3:	decw	%cx
+	js	99f		/* Exit with ZF clear */
+	/* Wait for timer tick to be updated */
+	call	wait_for_tick
+	/* Check to see if a key was pressed */
+	movb	$0x01, %ah
+	int	$0x16
+	jz	3b
+	/* Check to see if key was the specified key */
+	andb	%bh, %al
+	cmpb	%al, %bl
+	je	99f		/* Exit with ZF set */
+	/* Not the specified key: remove from buffer and stop waiting */
+	pushfw
+	xorw	%ax, %ax
+	int	$0x16
+	popfw			/* Exit with ZF clear */
+99:	/* Restore registers and return */
+	popw	%ax
+	popw	%cx
+	ret
+	.size wait_for_key, . - wait_for_key
+
+/* Wait for timer tick
+ *
+ * Used by wait_for_key
+ */
+wait_for_tick:
+	pushl	%eax
+	pushw	%fs
+	movw	$0x40, %ax
+	movw	%ax, %fs
+	movl	%fs:(0x6c), %eax
+1:	pushf
+	sti
+	hlt
+	popf
+	cmpl	%fs:(0x6c), %eax
+	je	1b
+	popw	%fs
+	popl	%eax
+	ret
+	.size wait_for_tick, . - wait_for_tick
+
+/* Drag in objects via _rom_start */
+REQUIRING_SYMBOL ( _rom_start )
+
+/* Drag in ROM configuration */
+REQUIRE_OBJECT ( config_romprefix )
diff --git a/.pc/debian-changes/src/bin/.gitignore b/.pc/debian-changes/src/bin/.gitignore
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/.pc/debian-changes/src/bin/.gitignore
@@ -0,0 +1 @@
+*
diff --git a/.pc/debian-changes/src/util/elf2efi.c b/.pc/debian-changes/src/util/elf2efi.c
new file mode 100644
index 00000000..2c5b9df8
--- /dev/null
+++ b/.pc/debian-changes/src/util/elf2efi.c
@@ -0,0 +1,1033 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define FILE_LICENCE(...) extern void __file_licence ( void )
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <elf.h>
+#include <libgen.h>
+#include <ipxe/efi/Uefi.h>
+#include <ipxe/efi/IndustryStandard/PeImage.h>
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#ifdef EFI_TARGET32
+
+#define EFI_IMAGE_NT_HEADERS		EFI_IMAGE_NT_HEADERS32
+#define EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC	EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+#define EFI_IMAGE_FILE_MACHINE		EFI_IMAGE_FILE_32BIT_MACHINE
+#define ELFCLASS   ELFCLASS32
+#define Elf_Ehdr   Elf32_Ehdr
+#define Elf_Shdr   Elf32_Shdr
+#define Elf_Sym    Elf32_Sym
+#define Elf_Addr   Elf32_Addr
+#define Elf_Rel    Elf32_Rel
+#define Elf_Rela   Elf32_Rela
+#define ELF_R_TYPE ELF32_R_TYPE
+#define ELF_R_SYM  ELF32_R_SYM
+
+#elif defined(EFI_TARGET64)
+
+#define EFI_IMAGE_NT_HEADERS		EFI_IMAGE_NT_HEADERS64
+#define EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC	EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+#define EFI_IMAGE_FILE_MACHINE		0
+#define ELFCLASS   ELFCLASS64
+#define Elf_Ehdr   Elf64_Ehdr
+#define Elf_Shdr   Elf64_Shdr
+#define Elf_Sym    Elf64_Sym
+#define Elf_Addr   Elf64_Addr
+#define Elf_Rel    Elf64_Rel
+#define Elf_Rela   Elf64_Rela
+#define ELF_R_TYPE ELF64_R_TYPE
+#define ELF_R_SYM  ELF64_R_SYM
+
+#endif
+
+#define ELF_MREL( mach, type ) ( (mach) | ( (type) << 16 ) )
+
+/* Allow for building with older versions of elf.h */
+#ifndef EM_AARCH64
+#define EM_AARCH64 183
+#define R_AARCH64_NONE 0
+#define R_AARCH64_ABS64 257
+#define R_AARCH64_CALL26 283
+#define R_AARCH64_JUMP26 282
+#define R_AARCH64_ADR_PREL_LO21 274
+#define R_AARCH64_ADR_PREL_PG_HI21 275
+#define R_AARCH64_ADD_ABS_LO12_NC 277
+#define R_AARCH64_LDST8_ABS_LO12_NC 278
+#define R_AARCH64_LDST16_ABS_LO12_NC 284
+#define R_AARCH64_LDST32_ABS_LO12_NC 285
+#define R_AARCH64_LDST64_ABS_LO12_NC 286
+#endif /* EM_AARCH64 */
+#ifndef R_ARM_CALL
+#define R_ARM_CALL 28
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_V4BX
+#define R_ARM_V4BX 40
+#endif
+
+/* Seems to be missing from elf.h */
+#ifndef R_AARCH64_NULL
+#define R_AARCH64_NULL 256
+#endif
+
+#define EFI_FILE_ALIGN 0x20
+
+struct elf_file {
+	void *data;
+	size_t len;
+	const Elf_Ehdr *ehdr;
+};
+
+struct pe_section {
+	struct pe_section *next;
+	EFI_IMAGE_SECTION_HEADER hdr;
+	void ( * fixup ) ( struct pe_section *section );
+	uint8_t contents[0];
+};
+
+struct pe_relocs {
+	struct pe_relocs *next;
+	unsigned long start_rva;
+	unsigned int used_relocs;
+	unsigned int total_relocs;
+	uint16_t *relocs;
+};
+
+struct pe_header {
+	EFI_IMAGE_DOS_HEADER dos;
+	uint8_t padding[128];
+	EFI_IMAGE_NT_HEADERS nt;
+};
+
+static struct pe_header efi_pe_header = {
+	.dos = {
+		.e_magic = EFI_IMAGE_DOS_SIGNATURE,
+		.e_lfanew = offsetof ( typeof ( efi_pe_header ), nt ),
+	},
+	.nt = {
+		.Signature = EFI_IMAGE_NT_SIGNATURE,
+		.FileHeader = {
+			.TimeDateStamp = 0x10d1a884,
+			.SizeOfOptionalHeader =
+				sizeof ( efi_pe_header.nt.OptionalHeader ),
+			.Characteristics = ( EFI_IMAGE_FILE_DLL |
+					     EFI_IMAGE_FILE_MACHINE |
+					     EFI_IMAGE_FILE_EXECUTABLE_IMAGE ),
+		},
+		.OptionalHeader = {
+			.Magic = EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC,
+			.MajorLinkerVersion = 42,
+			.MinorLinkerVersion = 42,
+			.SectionAlignment = EFI_FILE_ALIGN,
+			.FileAlignment = EFI_FILE_ALIGN,
+			.SizeOfImage = sizeof ( efi_pe_header ),
+			.SizeOfHeaders = sizeof ( efi_pe_header ),
+			.NumberOfRvaAndSizes =
+				EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES,
+		},
+	},
+};
+
+/** Command-line options */
+struct options {
+	unsigned int subsystem;
+};
+
+/**
+ * Allocate memory
+ *
+ * @v len		Length of memory to allocate
+ * @ret ptr		Pointer to allocated memory
+ */
+static void * xmalloc ( size_t len ) {
+	void *ptr;
+
+	ptr = malloc ( len );
+	if ( ! ptr ) {
+		eprintf ( "Could not allocate %zd bytes\n", len );
+		exit ( 1 );
+	}
+
+	return ptr;
+}
+
+/**
+ * Align section within PE file
+ *
+ * @v offset		Unaligned offset
+ * @ret aligned_offset	Aligned offset
+ */
+static unsigned long efi_file_align ( unsigned long offset ) {
+	return ( ( offset + EFI_FILE_ALIGN - 1 ) & ~( EFI_FILE_ALIGN - 1 ) );
+}
+
+/**
+ * Generate entry in PE relocation table
+ *
+ * @v pe_reltab		PE relocation table
+ * @v rva		RVA
+ * @v size		Size of relocation entry
+ */
+static void generate_pe_reloc ( struct pe_relocs **pe_reltab,
+				unsigned long rva, size_t size ) {
+	unsigned long start_rva;
+	uint16_t reloc;
+	struct pe_relocs *pe_rel;
+	uint16_t *relocs;
+
+	/* Construct */
+	start_rva = ( rva & ~0xfff );
+	reloc = ( rva & 0xfff );
+	switch ( size ) {
+	case 8:
+		reloc |= 0xa000;
+		break;
+	case 4:
+		reloc |= 0x3000;
+		break;
+	case 2:
+		reloc |= 0x2000;
+		break;
+	default:
+		eprintf ( "Unsupported relocation size %zd\n", size );
+		exit ( 1 );
+	}
+
+	/* Locate or create PE relocation table */
+	for ( pe_rel = *pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+		if ( pe_rel->start_rva == start_rva )
+			break;
+	}
+	if ( ! pe_rel ) {
+		pe_rel = xmalloc ( sizeof ( *pe_rel ) );
+		memset ( pe_rel, 0, sizeof ( *pe_rel ) );
+		pe_rel->next = *pe_reltab;
+		*pe_reltab = pe_rel;
+		pe_rel->start_rva = start_rva;
+	}
+
+	/* Expand relocation list if necessary */
+	if ( pe_rel->used_relocs < pe_rel->total_relocs ) {
+		relocs = pe_rel->relocs;
+	} else {
+		pe_rel->total_relocs = ( pe_rel->total_relocs ?
+					 ( pe_rel->total_relocs * 2 ) : 256 );
+		relocs = xmalloc ( pe_rel->total_relocs *
+				   sizeof ( pe_rel->relocs[0] ) );
+		memset ( relocs, 0,
+			 pe_rel->total_relocs * sizeof ( pe_rel->relocs[0] ) );
+		memcpy ( relocs, pe_rel->relocs,
+			 pe_rel->used_relocs * sizeof ( pe_rel->relocs[0] ) );
+		free ( pe_rel->relocs );
+		pe_rel->relocs = relocs;
+	}
+
+	/* Store relocation */
+	pe_rel->relocs[ pe_rel->used_relocs++ ] = reloc;
+}
+
+/**
+ * Calculate size of binary PE relocation table
+ *
+ * @v pe_reltab		PE relocation table
+ * @v buffer		Buffer to contain binary table, or NULL
+ * @ret size		Size of binary table
+ */
+static size_t output_pe_reltab ( struct pe_relocs *pe_reltab,
+				 void *buffer ) {
+	struct pe_relocs *pe_rel;
+	unsigned int num_relocs;
+	size_t size;
+	size_t total_size = 0;
+
+	for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) {
+		num_relocs = ( ( pe_rel->used_relocs + 1 ) & ~1 );
+		size = ( sizeof ( uint32_t ) /* VirtualAddress */ +
+			 sizeof ( uint32_t ) /* SizeOfBlock */ +
+			 ( num_relocs * sizeof ( uint16_t ) ) );
+		if ( buffer ) {
+			*( (uint32_t *) ( buffer + total_size + 0 ) )
+				= pe_rel->start_rva;
+			*( (uint32_t *) ( buffer + total_size + 4 ) ) = size;
+			memcpy ( ( buffer + total_size + 8 ), pe_rel->relocs,
+				 ( num_relocs * sizeof ( uint16_t ) ) );
+		}
+		total_size += size;
+	}
+
+	return total_size;
+}
+
+/**
+ * Read input ELF file
+ *
+ * @v name		File name
+ * @v elf		ELF file
+ */
+static void read_elf_file ( const char *name, struct elf_file *elf ) {
+	static const unsigned char ident[] = {
+		ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS, ELFDATA2LSB
+	};
+	struct stat stat;
+	const Elf_Ehdr *ehdr;
+	const Elf_Shdr *shdr;
+	void *data;
+	size_t offset;
+	unsigned int i;
+	int fd;
+
+	/* Open file */
+	fd = open ( name, O_RDONLY );
+	if ( fd < 0 ) {
+		eprintf ( "Could not open %s: %s\n", name, strerror ( errno ) );
+		exit ( 1 );
+	}
+
+	/* Get file size */
+	if ( fstat ( fd, &stat ) < 0 ) {
+		eprintf ( "Could not get size of %s: %s\n",
+			  name, strerror ( errno ) );
+		exit ( 1 );
+	}
+	elf->len = stat.st_size;
+
+	/* Map file */
+	data = mmap ( NULL, elf->len, PROT_READ, MAP_SHARED, fd, 0 );
+	if ( data == MAP_FAILED ) {
+		eprintf ( "Could not map %s: %s\n", name, strerror ( errno ) );
+		exit ( 1 );
+	}
+	elf->data = data;
+
+	/* Close file */
+	close ( fd );
+
+	/* Check header */
+	ehdr = elf->data;
+	if ( ( elf->len < sizeof ( *ehdr ) ) ||
+	     ( memcmp ( ident, ehdr->e_ident, sizeof ( ident ) ) != 0 ) ) {
+		eprintf ( "Invalid ELF header in %s\n", name );
+		exit ( 1 );
+	}
+	elf->ehdr = ehdr;
+
+	/* Check section headers */
+	for ( i = 0 ; i < ehdr->e_shnum ; i++ ) {
+		offset = ( ehdr->e_shoff + ( i * ehdr->e_shentsize ) );
+		if ( elf->len < ( offset + sizeof ( *shdr ) ) ) {
+			eprintf ( "ELF section header outside file in %s\n",
+				  name );
+			exit ( 1 );
+		}
+		shdr = ( data + offset );
+		if ( ( shdr->sh_type != SHT_NOBITS ) &&
+		     ( ( elf->len < shdr->sh_offset ) ||
+		       ( ( ( elf->len - shdr->sh_offset ) < shdr->sh_size ) ))){
+			eprintf ( "ELF section %d outside file in %s\n",
+				  i, name );
+			exit ( 1 );
+		}
+		if ( shdr->sh_link >= ehdr->e_shnum ) {
+			eprintf ( "ELF section %d link section %d out of "
+				  "range\n", i, shdr->sh_link );
+			exit ( 1 );
+		}
+	}
+}
+
+/**
+ * Get ELF string
+ *
+ * @v elf		ELF file
+ * @v section		String table section number
+ * @v offset		String table offset
+ * @ret string		ELF string
+ */
+static const char * elf_string ( struct elf_file *elf, unsigned int section,
+				 size_t offset ) {
+	const Elf_Ehdr *ehdr = elf->ehdr;
+	const Elf_Shdr *shdr;
+	char *string;
+	char *last;
+
+	/* Locate section header */
+	if ( section >= ehdr->e_shnum ) {
+		eprintf ( "Invalid ELF string section %d\n", section );
+		exit ( 1 );
+	}
+	shdr = ( elf->data + ehdr->e_shoff + ( section * ehdr->e_shentsize ) );
+
+	/* Sanity check section */
+	if ( shdr->sh_type != SHT_STRTAB ) {
+		eprintf ( "ELF section %d (type %d) is not a string table\n",
+			  section, shdr->sh_type );
+		exit ( 1 );
+	}
+	last = ( elf->data + shdr->sh_offset + shdr->sh_size - 1 );
+	if ( *last != '\0' ) {
+		eprintf ( "ELF section %d is not NUL-terminated\n", section );
+		exit ( 1 );
+	}
+
+	/* Locate string */
+	if ( offset >= shdr->sh_size ) {
+		eprintf ( "Invalid ELF string offset %zd in section %d\n",
+			  offset, section );
+		exit ( 1 );
+	}
+	string = ( elf->data + shdr->sh_offset + offset );
+
+	return string;
+}
+
+/**
+ * Set machine architecture
+ *
+ * @v elf		ELF file
+ * @v pe_header		PE file header
+ */
+static void set_machine ( struct elf_file *elf, struct pe_header *pe_header ) {
+	const Elf_Ehdr *ehdr = elf->ehdr;
+	uint16_t machine;
+
+	/* Identify machine architecture */
+	switch ( ehdr->e_machine ) {
+	case EM_386:
+		machine = EFI_IMAGE_MACHINE_IA32;
+		break;
+	case EM_X86_64:
+		machine = EFI_IMAGE_MACHINE_X64;
+		break;
+	case EM_ARM:
+		machine = EFI_IMAGE_MACHINE_ARMTHUMB_MIXED;
+		break;
+	case EM_AARCH64:
+		machine = EFI_IMAGE_MACHINE_AARCH64;
+		break;
+	default:
+		eprintf ( "Unknown ELF architecture %d\n", ehdr->e_machine );
+		exit ( 1 );
+	}
+
+	/* Set machine architecture */
+	pe_header->nt.FileHeader.Machine = machine;
+}
+
+/**
+ * Process section
+ *
+ * @v elf		ELF file
+ * @v shdr		ELF section header
+ * @v pe_header		PE file header
+ * @ret new		New PE section
+ */
+static struct pe_section * process_section ( struct elf_file *elf,
+					     const Elf_Shdr *shdr,
+					     struct pe_header *pe_header ) {
+	struct pe_section *new;
+	const char *name;
+	size_t section_memsz;
+	size_t section_filesz;
+	unsigned long code_start;
+	unsigned long code_end;
+	unsigned long data_start;
+	unsigned long data_mid;
+	unsigned long data_end;
+	unsigned long start;
+	unsigned long end;
+	unsigned long *applicable_start;
+	unsigned long *applicable_end;
+
+	/* Get section name */
+	name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name );
+
+	/* Extract current RVA limits from file header */
+	code_start = pe_header->nt.OptionalHeader.BaseOfCode;
+	code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
+#if defined(EFI_TARGET32)
+	data_start = pe_header->nt.OptionalHeader.BaseOfData;
+#elif defined(EFI_TARGET64)
+	data_start = code_end;
+#endif
+	data_mid = ( data_start +
+		     pe_header->nt.OptionalHeader.SizeOfInitializedData );
+	data_end = ( data_mid +
+		     pe_header->nt.OptionalHeader.SizeOfUninitializedData );
+
+	/* Allocate PE section */
+	section_memsz = shdr->sh_size;
+	section_filesz = ( ( shdr->sh_type == SHT_PROGBITS ) ?
+			   efi_file_align ( section_memsz ) : 0 );
+	new = xmalloc ( sizeof ( *new ) + section_filesz );
+	memset ( new, 0, sizeof ( *new ) + section_filesz );
+
+	/* Fill in section header details */
+	strncpy ( ( char * ) new->hdr.Name, name, sizeof ( new->hdr.Name ) );
+	new->hdr.Misc.VirtualSize = section_memsz;
+	new->hdr.VirtualAddress = shdr->sh_addr;
+	new->hdr.SizeOfRawData = section_filesz;
+
+	/* Fill in section characteristics and update RVA limits */
+	if ( ( shdr->sh_type == SHT_PROGBITS ) &&
+	     ( shdr->sh_flags & SHF_EXECINSTR ) ) {
+		/* .text-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_CODE |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_EXECUTE |
+			  EFI_IMAGE_SCN_MEM_READ );
+		applicable_start = &code_start;
+		applicable_end = &code_end;
+	} else if ( ( shdr->sh_type == SHT_PROGBITS ) &&
+		    ( shdr->sh_flags & SHF_WRITE ) ) {
+		/* .data-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_READ |
+			  EFI_IMAGE_SCN_MEM_WRITE );
+		applicable_start = &data_start;
+		applicable_end = &data_mid;
+	} else if ( shdr->sh_type == SHT_PROGBITS ) {
+		/* .rodata-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_READ );
+		applicable_start = &data_start;
+		applicable_end = &data_mid;
+	} else if ( shdr->sh_type == SHT_NOBITS ) {
+		/* .bss-type section */
+		new->hdr.Characteristics =
+			( EFI_IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+			  EFI_IMAGE_SCN_MEM_NOT_PAGED |
+			  EFI_IMAGE_SCN_MEM_READ |
+			  EFI_IMAGE_SCN_MEM_WRITE );
+		applicable_start = &data_mid;
+		applicable_end = &data_end;
+	} else {
+		eprintf ( "Unrecognised characteristics for section %s\n",
+			  name );
+		exit ( 1 );
+	}
+
+	/* Copy in section contents */
+	if ( shdr->sh_type == SHT_PROGBITS ) {
+		memcpy ( new->contents, ( elf->data + shdr->sh_offset ),
+			 shdr->sh_size );
+	}
+
+	/* Update RVA limits */
+	start = new->hdr.VirtualAddress;
+	end = ( start + new->hdr.Misc.VirtualSize );
+	if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
+		*applicable_start = start;
+	if ( *applicable_end < end )
+		*applicable_end = end;
+	if ( data_start < code_end )
+		data_start = code_end;
+	if ( data_mid < data_start )
+		data_mid = data_start;
+	if ( data_end < data_mid )
+		data_end = data_mid;
+
+	/* Write RVA limits back to file header */
+	pe_header->nt.OptionalHeader.BaseOfCode = code_start;
+	pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
+#if defined(EFI_TARGET32)
+	pe_header->nt.OptionalHeader.BaseOfData = data_start;
+#endif
+	pe_header->nt.OptionalHeader.SizeOfInitializedData =
+		( data_mid - data_start );
+	pe_header->nt.OptionalHeader.SizeOfUninitializedData =
+		( data_end - data_mid );
+
+	/* Update remaining file header fields */
+	pe_header->nt.FileHeader.NumberOfSections++;
+	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr );
+	pe_header->nt.OptionalHeader.SizeOfImage =
+		efi_file_align ( data_end );
+
+	return new;
+}
+
+/**
+ * Process relocation record
+ *
+ * @v elf		ELF file
+ * @v shdr		ELF section header
+ * @v syms		Symbol table
+ * @v nsyms		Number of symbol table entries
+ * @v rel		Relocation record
+ * @v pe_reltab		PE relocation table to fill in
+ */
+static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr,
+			    const Elf_Sym *syms, unsigned int nsyms,
+			    const Elf_Rel *rel, struct pe_relocs **pe_reltab ) {
+	unsigned int type = ELF_R_TYPE ( rel->r_info );
+	unsigned int sym = ELF_R_SYM ( rel->r_info );
+	unsigned int mrel = ELF_MREL ( elf->ehdr->e_machine, type );
+	size_t offset = ( shdr->sh_addr + rel->r_offset );
+
+	/* Look up symbol and process relocation */
+	if ( sym >= nsyms ) {
+		eprintf ( "Symbol out of range\n" );
+		exit ( 1 );
+	}
+	if ( syms[sym].st_shndx == SHN_ABS ) {
+		/* Skip absolute symbols; the symbol value won't
+		 * change when the object is loaded.
+		 */
+	} else {
+		switch ( mrel ) {
+		case ELF_MREL ( EM_386, R_386_NONE ) :
+		case ELF_MREL ( EM_ARM, R_ARM_NONE ) :
+		case ELF_MREL ( EM_X86_64, R_X86_64_NONE ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_NONE ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_NULL ) :
+			/* Ignore dummy relocations used by REQUIRE_SYMBOL() */
+			break;
+		case ELF_MREL ( EM_386, R_386_32 ) :
+		case ELF_MREL ( EM_ARM, R_ARM_ABS32 ) :
+			/* Generate a 4-byte PE relocation */
+			generate_pe_reloc ( pe_reltab, offset, 4 );
+			break;
+		case ELF_MREL ( EM_X86_64, R_X86_64_64 ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_ABS64 ) :
+			/* Generate an 8-byte PE relocation */
+			generate_pe_reloc ( pe_reltab, offset, 8 );
+			break;
+		case ELF_MREL ( EM_386, R_386_PC32 ) :
+		case ELF_MREL ( EM_ARM, R_ARM_CALL ) :
+		case ELF_MREL ( EM_ARM, R_ARM_REL32 ) :
+		case ELF_MREL ( EM_ARM, R_ARM_THM_PC22 ) :
+		case ELF_MREL ( EM_ARM, R_ARM_THM_JUMP24 ) :
+		case ELF_MREL ( EM_ARM, R_ARM_V4BX ):
+		case ELF_MREL ( EM_X86_64, R_X86_64_PC32 ) :
+		case ELF_MREL ( EM_X86_64, R_X86_64_PLT32 ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_CALL26 ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_JUMP26 ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_LO21 ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_PG_HI21 ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_ADD_ABS_LO12_NC ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST8_ABS_LO12_NC ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST16_ABS_LO12_NC ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST32_ABS_LO12_NC ) :
+		case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST64_ABS_LO12_NC ) :
+			/* Skip PC-relative relocations; all relative
+			 * offsets remain unaltered when the object is
+			 * loaded.
+			 */
+			break;
+		default:
+			eprintf ( "Unrecognised relocation type %d\n", type );
+			exit ( 1 );
+		}
+	}
+}
+
+/**
+ * Process relocation records
+ *
+ * @v elf		ELF file
+ * @v shdr		ELF section header
+ * @v stride		Relocation record size
+ * @v pe_reltab		PE relocation table to fill in
+ */
+static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr,
+			     size_t stride, struct pe_relocs **pe_reltab ) {
+	const Elf_Shdr *symtab;
+	const Elf_Sym *syms;
+	const Elf_Rel *rel;
+	unsigned int nsyms;
+	unsigned int nrels;
+	unsigned int i;
+
+	/* Identify symbol table */
+	symtab = ( elf->data + elf->ehdr->e_shoff +
+		   ( shdr->sh_link * elf->ehdr->e_shentsize ) );
+	syms = ( elf->data + symtab->sh_offset );
+	nsyms = ( symtab->sh_size / sizeof ( syms[0] ) );
+
+	/* Process each relocation */
+	rel = ( elf->data + shdr->sh_offset );
+	nrels = ( shdr->sh_size / stride );
+	for ( i = 0 ; i < nrels ; i++ ) {
+		process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab );
+		rel = ( ( ( const void * ) rel ) + stride );
+	}
+}
+
+/**
+ * Create relocations section
+ *
+ * @v pe_header		PE file header
+ * @v pe_reltab		PE relocation table
+ * @ret section		Relocation section
+ */
+static struct pe_section *
+create_reloc_section ( struct pe_header *pe_header,
+		       struct pe_relocs *pe_reltab ) {
+	struct pe_section *reloc;
+	size_t section_memsz;
+	size_t section_filesz;
+	EFI_IMAGE_DATA_DIRECTORY *relocdir;
+
+	/* Allocate PE section */
+	section_memsz = output_pe_reltab ( pe_reltab, NULL );
+	section_filesz = efi_file_align ( section_memsz );
+	reloc = xmalloc ( sizeof ( *reloc ) + section_filesz );
+	memset ( reloc, 0, sizeof ( *reloc ) + section_filesz );
+
+	/* Fill in section header details */
+	strncpy ( ( char * ) reloc->hdr.Name, ".reloc",
+		  sizeof ( reloc->hdr.Name ) );
+	reloc->hdr.Misc.VirtualSize = section_memsz;
+	reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+	reloc->hdr.SizeOfRawData = section_filesz;
+	reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+				       EFI_IMAGE_SCN_MEM_NOT_PAGED |
+				       EFI_IMAGE_SCN_MEM_READ );
+
+	/* Copy in section contents */
+	output_pe_reltab ( pe_reltab, reloc->contents );
+
+	/* Update file header details */
+	pe_header->nt.FileHeader.NumberOfSections++;
+	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
+	pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+	relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
+		     [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
+	relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
+	relocdir->Size = reloc->hdr.Misc.VirtualSize;
+
+	return reloc;
+}
+
+/**
+ * Fix up debug section
+ *
+ * @v debug		Debug section
+ */
+static void fixup_debug_section ( struct pe_section *debug ) {
+	EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *contents;
+
+	/* Fix up FileOffset */
+	contents = ( ( void * ) debug->contents );
+	contents->FileOffset += ( debug->hdr.PointerToRawData -
+				  debug->hdr.VirtualAddress );
+}
+
+/**
+ * Create debug section
+ *
+ * @v pe_header		PE file header
+ * @ret section		Debug section
+ */
+static struct pe_section *
+create_debug_section ( struct pe_header *pe_header, const char *filename ) {
+	struct pe_section *debug;
+	size_t section_memsz;
+	size_t section_filesz;
+	EFI_IMAGE_DATA_DIRECTORY *debugdir;
+	struct {
+		EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug;
+		EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds;
+		char name[ strlen ( filename ) + 1 ];
+	} *contents;
+
+	/* Allocate PE section */
+	section_memsz = sizeof ( *contents );
+	section_filesz = efi_file_align ( section_memsz );
+	debug = xmalloc ( sizeof ( *debug ) + section_filesz );
+	memset ( debug, 0, sizeof ( *debug ) + section_filesz );
+	contents = ( void * ) debug->contents;
+
+	/* Fill in section header details */
+	strncpy ( ( char * ) debug->hdr.Name, ".debug",
+		  sizeof ( debug->hdr.Name ) );
+	debug->hdr.Misc.VirtualSize = section_memsz;
+	debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage;
+	debug->hdr.SizeOfRawData = section_filesz;
+	debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
+				       EFI_IMAGE_SCN_MEM_NOT_PAGED |
+				       EFI_IMAGE_SCN_MEM_READ );
+	debug->fixup = fixup_debug_section;
+
+	/* Create section contents */
+	contents->debug.TimeDateStamp = 0x10d1a884;
+	contents->debug.Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
+	contents->debug.SizeOfData =
+		( sizeof ( *contents ) - sizeof ( contents->debug ) );
+	contents->debug.RVA = ( debug->hdr.VirtualAddress +
+				offsetof ( typeof ( *contents ), rsds ) );
+	contents->debug.FileOffset = contents->debug.RVA;
+	contents->rsds.Signature = CODEVIEW_SIGNATURE_RSDS;
+	snprintf ( contents->name, sizeof ( contents->name ), "%s",
+		   filename );
+
+	/* Update file header details */
+	pe_header->nt.FileHeader.NumberOfSections++;
+	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
+	pe_header->nt.OptionalHeader.SizeOfImage += section_filesz;
+	debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
+		     [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+	debugdir->VirtualAddress = debug->hdr.VirtualAddress;
+	debugdir->Size = sizeof ( contents->debug );
+
+	return debug;
+}
+
+/**
+ * Write out PE file
+ *
+ * @v pe_header		PE file header
+ * @v pe_sections	List of PE sections
+ * @v pe		Output file
+ */
+static void write_pe_file ( struct pe_header *pe_header,
+			    struct pe_section *pe_sections,
+			    FILE *pe ) {
+	struct pe_section *section;
+	unsigned long fpos = 0;
+
+	/* Align length of headers */
+	fpos = pe_header->nt.OptionalHeader.SizeOfHeaders =
+		efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
+
+	/* Assign raw data pointers */
+	for ( section = pe_sections ; section ; section = section->next ) {
+		if ( section->hdr.SizeOfRawData ) {
+			section->hdr.PointerToRawData = fpos;
+			fpos += section->hdr.SizeOfRawData;
+			fpos = efi_file_align ( fpos );
+		}
+		if ( section->fixup )
+			section->fixup ( section );
+	}
+
+	/* Write file header */
+	if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) {
+		perror ( "Could not write PE header" );
+		exit ( 1 );
+	}
+
+	/* Write section headers */
+	for ( section = pe_sections ; section ; section = section->next ) {
+		if ( fwrite ( &section->hdr, sizeof ( section->hdr ),
+			      1, pe ) != 1 ) {
+			perror ( "Could not write section header" );
+			exit ( 1 );
+		}
+	}
+
+	/* Write sections */
+	for ( section = pe_sections ; section ; section = section->next ) {
+		if ( fseek ( pe, section->hdr.PointerToRawData,
+			     SEEK_SET ) != 0 ) {
+			eprintf ( "Could not seek to %x: %s\n",
+				  section->hdr.PointerToRawData,
+				  strerror ( errno ) );
+			exit ( 1 );
+		}
+		if ( section->hdr.SizeOfRawData &&
+		     ( fwrite ( section->contents, section->hdr.SizeOfRawData,
+				1, pe ) != 1 ) ) {
+			eprintf ( "Could not write section %.8s: %s\n",
+				  section->hdr.Name, strerror ( errno ) );
+			exit ( 1 );
+		}
+	}
+}
+
+/**
+ * Convert ELF to PE
+ *
+ * @v elf_name		ELF file name
+ * @v pe_name		PE file name
+ */
+static void elf2pe ( const char *elf_name, const char *pe_name,
+		     struct options *opts ) {
+	char pe_name_tmp[ strlen ( pe_name ) + 1 ];
+	struct pe_relocs *pe_reltab = NULL;
+	struct pe_section *pe_sections = NULL;
+	struct pe_section **next_pe_section = &pe_sections;
+	struct pe_header pe_header;
+	struct elf_file elf;
+	const Elf_Shdr *shdr;
+	size_t offset;
+	unsigned int i;
+	FILE *pe;
+
+	/* Create a modifiable copy of the PE name */
+	memcpy ( pe_name_tmp, pe_name, sizeof ( pe_name_tmp ) );
+
+	/* Read ELF file */
+	read_elf_file ( elf_name, &elf );
+
+	/* Initialise the PE header */
+	memcpy ( &pe_header, &efi_pe_header, sizeof ( pe_header ) );
+	set_machine ( &elf, &pe_header );
+	pe_header.nt.OptionalHeader.AddressOfEntryPoint = elf.ehdr->e_entry;
+	pe_header.nt.OptionalHeader.Subsystem = opts->subsystem;
+
+	/* Process input sections */
+	for ( i = 0 ; i < elf.ehdr->e_shnum ; i++ ) {
+		offset = ( elf.ehdr->e_shoff + ( i * elf.ehdr->e_shentsize ) );
+		shdr = ( elf.data + offset );
+
+		/* Process section */
+		if ( shdr->sh_flags & SHF_ALLOC ) {
+
+			/* Create output section */
+			*(next_pe_section) = process_section ( &elf, shdr,
+							       &pe_header );
+			next_pe_section = &(*next_pe_section)->next;
+
+		} else if ( shdr->sh_type == SHT_REL ) {
+
+			/* Process .rel relocations */
+			process_relocs ( &elf, shdr, sizeof ( Elf_Rel ),
+					 &pe_reltab );
+
+		} else if ( shdr->sh_type == SHT_RELA ) {
+
+			/* Process .rela relocations */
+			process_relocs ( &elf, shdr, sizeof ( Elf_Rela ),
+					 &pe_reltab );
+		}
+	}
+
+	/* Create the .reloc section */
+	*(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab );
+	next_pe_section = &(*next_pe_section)->next;
+
+	/* Create the .debug section */
+	*(next_pe_section) = create_debug_section ( &pe_header,
+						    basename ( pe_name_tmp ) );
+	next_pe_section = &(*next_pe_section)->next;
+
+	/* Write out PE file */
+	pe = fopen ( pe_name, "w" );
+	if ( ! pe ) {
+		eprintf ( "Could not open %s for writing: %s\n",
+			  pe_name, strerror ( errno ) );
+		exit ( 1 );
+	}
+	write_pe_file ( &pe_header, pe_sections, pe );
+	fclose ( pe );
+
+	/* Unmap ELF file */
+	munmap ( elf.data, elf.len );
+}
+
+/**
+ * Print help
+ *
+ * @v program_name	Program name
+ */
+static void print_help ( const char *program_name ) {
+	eprintf ( "Syntax: %s [--subsystem=<number>] infile outfile\n",
+		  program_name );
+}
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v opts		Options structure to populate
+ */
+static int parse_options ( const int argc, char **argv,
+			   struct options *opts ) {
+	char *end;
+	int c;
+
+	while (1) {
+		int option_index = 0;
+		static struct option long_options[] = {
+			{ "subsystem", required_argument, NULL, 's' },
+			{ "help", 0, NULL, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		if ( ( c = getopt_long ( argc, argv, "s:h",
+					 long_options,
+					 &option_index ) ) == -1 ) {
+			break;
+		}
+
+		switch ( c ) {
+		case 's':
+			opts->subsystem = strtoul ( optarg, &end, 0 );
+			if ( *end ) {
+				eprintf ( "Invalid subsytem \"%s\"\n",
+					  optarg );
+				exit ( 2 );
+			}
+			break;
+		case 'h':
+			print_help ( argv[0] );
+			exit ( 0 );
+		case '?':
+		default:
+			exit ( 2 );
+		}
+	}
+	return optind;
+}
+
+int main ( int argc, char **argv ) {
+	struct options opts = {
+		.subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
+	};
+	int infile_index;
+	const char *infile;
+	const char *outfile;
+
+	/* Parse command-line arguments */
+	infile_index = parse_options ( argc, argv, &opts );
+	if ( argc != ( infile_index + 2 ) ) {
+		print_help ( argv[0] );
+		exit ( 2 );
+	}
+	infile = argv[infile_index];
+	outfile = argv[infile_index + 1];
+
+	/* Convert file */
+	elf2pe ( infile, outfile, &opts );
+
+	return 0;
+}
diff --git a/.pc/f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch/src/Makefile.housekeeping b/.pc/f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch/src/Makefile.housekeeping
new file mode 100644
index 00000000..f8334921
--- /dev/null
+++ b/.pc/f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch/src/Makefile.housekeeping
@@ -0,0 +1,1567 @@
+# -*- makefile -*- : Force emacs to use Makefile mode
+#
+# This file contains various boring housekeeping functions that would
+# otherwise seriously clutter up the main Makefile.
+
+###############################################################################
+#
+# Find a usable "echo -e" substitute.
+#
+TAB 			:= $(shell $(PRINTF) '\t')
+ECHO_E_ECHO		:= $(ECHO)
+ECHO_E_ECHO_E		:= $(ECHO) -e
+ECHO_E_BIN_ECHO 	:= /bin/echo
+ECHO_E_BIN_ECHO_E 	:= /bin/echo -e
+ECHO_E_ECHO_TAB		:= $(shell $(ECHO_E_ECHO) '\t' | cat)
+ECHO_E_ECHO_E_TAB	:= $(shell $(ECHO_E_ECHO_E) '\t' | cat)
+ECHO_E_BIN_ECHO_TAB 	:= $(shell $(ECHO_E_BIN_ECHO) '\t')
+ECHO_E_BIN_ECHO_E_TAB 	:= $(shell $(ECHO_E_BIN_ECHO_E) '\t')
+
+ifeq ($(ECHO_E_ECHO_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_ECHO)
+endif
+ifeq ($(ECHO_E_ECHO_E_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_ECHO_E)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_BIN_ECHO)
+endif
+ifeq ($(ECHO_E_BIN_ECHO_E_TAB),$(TAB))
+ECHO_E		:= $(ECHO_E_BIN_ECHO_E)
+endif
+
+.echocheck :
+ifdef ECHO_E
+	@$(TOUCH) $@
+else
+	@$(PRINTF) '%24s : x%sx\n' 'tab' '$(TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO) \t"' \
+				    '$(ECHO_E_ECHO_TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_ECHO_E) \t"' \
+				    '$(ECHO_E_ECHO_E_TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO) \t"' \
+				    '$(ECHO_E_BIN_ECHO_TAB)'
+	@$(PRINTF) '%24s : x%sx\n' '"$(ECHO_E_BIN_ECHO_E) \t"' \
+				    '$(ECHO_E_BIN_ECHO_E_TAB)'
+	@$(ECHO) "No usable \"echo -e\" substitute found"
+	@exit 1
+endif
+MAKEDEPS	+= .echocheck
+VERYCLEANUP	+= .echocheck
+
+echo :
+	@$(ECHO) "Using \"$(ECHO_E)\" for \"echo -e\""
+
+###############################################################################
+#
+# Generate a usable "seq" substitute
+#
+define seq
+	$(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }')
+endef
+
+###############################################################################
+#
+# Determine host OS
+#
+HOST_OS		:= $(shell uname -s)
+hostos :
+	@$(ECHO) $(HOST_OS)
+
+###############################################################################
+#
+# Determine compiler
+
+CCDEFS		:= $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2)
+ccdefs:
+	@$(ECHO) $(CCDEFS)
+
+ifeq ($(filter __ICC,$(CCDEFS)),__ICC)
+CCTYPE		:= icc
+else
+CCTYPE		:= gcc
+endif
+cctype:
+	@$(ECHO) $(CCTYPE)
+
+###############################################################################
+#
+# Check for tools that can cause failed builds
+#
+
+ifeq ($(CCTYPE),gcc)
+GCC_2_96_BANNER := $(shell $(CC) -v 2>&1 | grep -is 'gcc version 2\.96')
+ifneq ($(GCC_2_96_BANNER),)
+$(warning gcc 2.96 is unsuitable for compiling iPXE)
+$(warning Use gcc 2.95 or a newer version instead)
+$(error Unsuitable build environment found)
+endif
+endif
+
+PERL_UNICODE_CHECK := $(shell $(PERL) -e 'use bytes; print chr(255)' | wc -c)
+ifeq ($(PERL_UNICODE_CHECK),2)
+$(warning Your Perl version has a Unicode handling bug)
+$(warning Execute this command before building iPXE:)
+$(warning export LANG=$${LANG%.UTF-8})
+$(error Unsuitable build environment found)
+endif
+
+LD_GOLD_BANNER := $(shell $(LD) -v 2>&1 | grep 'GNU gold')
+ifneq ($(LD_GOLD_BANNER),)
+$(warning GNU gold is unsuitable for building iPXE)
+$(warning Use GNU ld instead)
+$(error Unsuitable build environment found)
+endif
+
+###############################################################################
+#
+# Check if $(eval ...) is available to use
+#
+
+HAVE_EVAL :=
+ifndef NO_EVAL
+$(eval HAVE_EVAL := yes)
+endif
+eval :
+	@$(ECHO) $(HAVE_EVAL)
+
+###############################################################################
+#
+# Check for various tool workarounds
+#
+
+WORKAROUND_CFLAGS :=
+WORKAROUND_ASFLAGS :=
+WORKAROUND_LDFLAGS :=
+
+# Make syntax does not allow use of comma or space in certain places.
+# This ugly workaround is suggested in the manual.
+#
+COMMA	:= ,
+EMPTY	:=
+SPACE	:= $(EMPTY) $(EMPTY)
+HASH	:= \#
+define NEWLINE
+
+
+endef
+
+# Some widespread patched versions of gcc include -fstack-protector by
+# default, even when -ffreestanding is specified.  We therefore need
+# to disable -fstack-protector if the compiler supports it.
+#
+ifeq ($(CCTYPE),gcc)
+SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \
+		-o /dev/null >/dev/null 2>&1
+SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector')
+WORKAROUND_CFLAGS += $(SP_FLAGS)
+endif
+
+# gcc 4.4 generates .eh_frame sections by default, which distort the
+# output of "size".  Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \
+		 -fno-asynchronous-unwind-tables -x c -c /dev/null \
+		 -o /dev/null >/dev/null 2>&1
+CFI_FLAGS := $(shell $(CFI_TEST) && \
+	       $(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \
+		       '-fno-unwind-tables -fno-asynchronous-unwind-tables')
+WORKAROUND_CFLAGS += $(CFI_FLAGS)
+endif
+
+# gcc 4.6 generates spurious warnings if -Waddress is in force.
+# Inhibit this.
+#
+ifeq ($(CCTYPE),gcc)
+WNA_TEST = $(CC) -Waddress -x c -c /dev/null -o /dev/null >/dev/null 2>&1
+WNA_FLAGS := $(shell $(WNA_TEST) && $(ECHO) '-Wno-address')
+WORKAROUND_CFLAGS += $(WNA_FLAGS)
+
+# gcc 8.0 generates warnings for certain suspect string operations. Our
+# sources have been vetted for correct usage.  Turn off these warnings.
+#
+WNST_TEST = $(CC) -Wstringop-truncation -x c -c /dev/null -o /dev/null \
+		  >/dev/null 2>&1
+WNST_FLAGS := $(shell $(WNST_TEST) && $(ECHO) '-Wno-stringop-truncation')
+WORKAROUND_CFLAGS += $(WNST_FLAGS)
+endif
+
+# Some versions of gas choke on division operators, treating them as
+# comment markers.  Specifying --divide will work around this problem,
+# but isn't available on older gas versions.
+#
+DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null
+DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide')
+WORKAROUND_ASFLAGS += $(DIVIDE_FLAGS)
+
+###############################################################################
+#
+# Build verbosity
+#
+ifeq ($(V),1)
+Q :=
+QM := @\#
+else
+Q := @
+QM := @
+endif
+
+###############################################################################
+#
+# Checker
+#
+ifeq ($(C),1)
+export REAL_CC := $(CC)
+CC := cgcc
+CFLAGS += -Wno-decl
+endif
+
+###############################################################################
+#
+# Set BIN according to whatever was specified on the command line as
+# the build target.
+#
+
+# Determine how many different BIN directories are mentioned in the
+# make goals.
+#
+BIN_GOALS	:= $(filter bin bin/% bin-%,$(MAKECMDGOALS))
+BIN_GOALS_BINS	:= $(sort $(foreach BG,$(BIN_GOALS),\
+				    $(firstword $(subst /, ,$(BG)))))
+NUM_BINS	:= $(words $(BIN_GOALS_BINS))
+
+ifeq ($(NUM_BINS),0)
+
+# No BIN directory was specified.  Set BIN to "bin" as a sensible
+# default.
+
+BIN		:= bin
+
+else # NUM_BINS == 0
+
+ifeq ($(NUM_BINS),1)
+
+# If exactly one BIN directory was specified, set BIN to match this
+# directory.
+#
+BIN		:= $(firstword $(BIN_GOALS_BINS))
+
+else # NUM_BINS == 1
+
+# More than one BIN directory was specified.  We cannot handle the
+# latter case within a single make invocation, so set up recursive
+# targets for each BIN directory.  Use exactly one target for each BIN
+# directory since running multiple make invocations within the same
+# BIN directory is likely to cause problems.
+#
+# Leave $(BIN) undefined.  This has implications for any target that
+# depends on $(BIN); such targets should be made conditional upon the
+# existence of $(BIN).
+#
+BIN_GOALS_FIRST	:= $(foreach BGB,$(BIN_GOALS_BINS),\
+			     $(firstword $(filter $(BGB)/%,$(BIN_GOALS))))
+BIN_GOALS_OTHER	:= $(filter-out $(BIN_GOALS_FIRST),$(BIN_GOALS))
+
+$(BIN_GOALS_FIRST) : % : BIN_RECURSE
+	$(Q)$(MAKE) --no-print-directory BIN=$(firstword $(subst /, ,$@)) \
+	    $(filter $(firstword $(subst /, ,$@))/%, $(BIN_GOALS))
+$(BIN_GOALS_OTHER) : % : BIN_RECURSE
+	$(Q)$(TRUE)
+.PHONY : BIN_RECURSE
+
+endif # NUM_BINS == 1
+endif # NUM_BINS == 0
+
+ifdef BIN
+
+# Create $(BIN) directory if it doesn't exist yet
+#
+ifeq ($(wildcard $(BIN)),)
+$(shell $(MKDIR) -p $(BIN))
+endif
+
+# Target to allow e.g. "make bin-efi arch"
+#
+$(BIN) :
+	@# Do nothing, silently
+.PHONY : $(BIN)
+
+# Remove everything in $(BIN) for a "make clean"
+#
+CLEANUP	+= $(BIN)/*.* # Avoid picking up directories
+
+endif # defined(BIN)
+
+# Determine whether or not we need to include the dependency files
+#
+NO_DEP_TARGETS	:= $(BIN) clean veryclean
+ifeq ($(MAKECMDGOALS),)
+NEED_DEPS	:= 1
+endif
+ifneq ($(strip $(filter-out $(NO_DEP_TARGETS),$(MAKECMDGOALS))),)
+NEED_DEPS	:= 1
+endif
+
+###############################################################################
+#
+# Select build architecture and platform based on $(BIN)
+#
+# BIN has the form bin[-[<arch>-]<platform>[-sb]]
+
+ARCHS		:= $(patsubst arch/%,%,$(wildcard arch/*))
+PLATFORMS	:= $(patsubst config/defaults/%.h,%,\
+		     $(wildcard config/defaults/*.h))
+archs :
+	@$(ECHO) $(ARCHS)
+
+platforms :
+	@$(ECHO) $(PLATFORMS)
+
+ifdef BIN
+
+# Split $(BIN) into architecture, platform, and security flag (where present)
+BIN_ELEMENTS	:= $(subst -,$(SPACE),$(BIN))
+BIN_APS		:= $(wordlist 2,4,$(BIN_ELEMENTS))
+ifeq ($(lastword $(BIN_APS)),sb)
+BIN_AP		:= $(wordlist 2,$(words $(BIN_APS)),discard $(BIN_APS))
+BIN_SECUREBOOT	:= 1
+else
+BIN_AP		:= $(BIN_APS)
+BIN_SECUREBOOT	:= 0
+endif
+BIN_PLATFORM	:= $(lastword $(BIN_AP))
+BIN_ARCH	:= $(wordlist 2,$(words $(BIN_AP)),discard $(BIN_AP))
+
+# Determine build architecture
+DEFAULT_ARCH	:= i386
+ARCH		:= $(firstword $(BIN_ARCH) $(DEFAULT_ARCH))
+CFLAGS		+= -DARCH=$(ARCH)
+arch :
+	@$(ECHO) $(ARCH)
+.PHONY : arch
+
+# Determine build platform
+DEFAULT_PLATFORM := pcbios
+PLATFORM	:= $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM))
+CFLAGS		+= -DPLATFORM=$(PLATFORM)
+platform :
+	@$(ECHO) $(PLATFORM)
+
+# Determine security flag
+DEFAULT_SECUREBOOT := 0
+SECUREBOOT	:= $(firstword $(BIN_SECUREBOOT) $(DEFAULT_SECUREBOOT))
+CFLAGS		+= -DSECUREBOOT=$(SECUREBOOT)
+secureboot :
+	@$(ECHO) $(SECUREBOOT)
+
+endif # defined(BIN)
+
+# Include architecture-specific Makefile
+ifdef ARCH
+MAKEDEPS	+= arch/$(ARCH)/Makefile
+include arch/$(ARCH)/Makefile
+endif
+
+# Include architecture-specific include path
+ifdef ARCH
+INCDIRS		+= arch/$(ARCH)/include
+INCDIRS		+= arch/$(ARCH)/include/$(PLATFORM)
+endif
+
+###############################################################################
+#
+# Source file handling
+
+# Exclude known-insecure files from Secure Boot builds
+ifeq ($(SECUREBOOT),0)
+SRCDIRS		+= $(SRCDIRS_INSEC)
+endif
+
+# SRCDIRS lists all directories containing source files.
+srcdirs :
+	@$(ECHO) $(SRCDIRS)
+
+# SRCS lists all .c or .S files found in any SRCDIR
+#
+SRCS	+= $(wildcard $(patsubst %,%/*.c,$(SRCDIRS)))
+SRCS	+= $(wildcard $(patsubst %,%/*.S,$(SRCDIRS)))
+srcs :
+	@$(ECHO) $(SRCS)
+
+# AUTO_SRCS lists all files in SRCS that are not mentioned in
+# NON_AUTO_SRCS.  Files should be added to NON_AUTO_SRCS if they
+# cannot be built using the standard build template.
+#
+AUTO_SRCS = $(filter-out $(NON_AUTO_SRCS),$(SRCS))
+autosrcs :
+	@$(ECHO) $(AUTO_SRCS)
+
+# Just about everything else in this section depends upon having
+# $(BIN) set
+
+ifdef BIN
+
+# INCDIRS lists the include path
+incdirs :
+	@$(ECHO) $(INCDIRS)
+
+# Common flags
+#
+CFLAGS		+= $(foreach INC,$(INCDIRS),-I$(INC))
+CFLAGS		+= -Os
+CFLAGS		+= -g
+ifeq ($(CCTYPE),gcc)
+CFLAGS		+= -ffreestanding
+CFLAGS		+= -Wall -W -Wformat-nonliteral
+HOST_CFLAGS	+= -Wall -W -Wformat-nonliteral
+endif
+ifeq ($(CCTYPE),icc)
+CFLAGS		+= -fno-builtin
+CFLAGS		+= -no-ip
+CFLAGS		+= -no-gcc
+CFLAGS		+= -diag-disable 111 # Unreachable code
+CFLAGS		+= -diag-disable 128 # Unreachable loop
+CFLAGS		+= -diag-disable 170 # Array boundary checks
+CFLAGS		+= -diag-disable 177 # Unused functions
+CFLAGS		+= -diag-disable 181 # printf() format checks
+CFLAGS		+= -diag-disable 188 # enum strictness
+CFLAGS		+= -diag-disable 193 # Undefined preprocessor identifiers
+CFLAGS		+= -diag-disable 280 # switch ( constant )
+CFLAGS		+= -diag-disable 310 # K&R parameter lists
+CFLAGS		+= -diag-disable 424 # Extra semicolon
+CFLAGS		+= -diag-disable 589 # Declarations mid-code
+CFLAGS		+= -diag-disable 593 # Unused variables
+CFLAGS		+= -diag-disable 810 # Casting ints to smaller ints
+CFLAGS		+= -diag-disable 981 # Sequence point violations
+CFLAGS		+= -diag-disable 1292 # Ignored attributes
+CFLAGS		+= -diag-disable 1338 # void pointer arithmetic
+CFLAGS		+= -diag-disable 1361 # Variable-length arrays
+CFLAGS		+= -diag-disable 1418 # Missing prototypes
+CFLAGS		+= -diag-disable 1419 # Missing prototypes
+CFLAGS		+= -diag-disable 1599 # Hidden variables
+CFLAGS		+= -Wall -Wmissing-declarations
+endif
+CFLAGS		+= $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
+ASFLAGS		+= $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
+LDFLAGS		+= $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
+HOST_CFLAGS	+= $(WORKAROUND_CFLAGS) -O2 -g
+
+# Inhibit -Werror if NO_WERROR is specified on make command line
+#
+ifneq ($(NO_WERROR),1)
+CFLAGS		+= -Werror
+ASFLAGS		+= --fatal-warnings
+HOST_CFLAGS	+= -Werror
+endif
+
+# Function trace recorder state in the last build.  This is needed
+# in order to correctly rebuild whenever the function recorder is
+# enabled/disabled.
+#
+FNREC_STATE	:= $(BIN)/.fnrec.state
+ifeq ($(wildcard $(FNREC_STATE)),)
+FNREC_OLD	:= <invalid>
+else
+FNREC_OLD	:= $(shell cat $(FNREC_STATE))
+endif
+ifeq ($(FNREC_OLD),$(FNREC))
+$(FNREC_STATE) :
+else
+$(FNREC_STATE) : clean
+$(shell $(ECHO) "$(FNREC)" > $(FNREC_STATE))
+endif
+
+VERYCLEANUP	+= $(FNREC_STATE)
+MAKEDEPS	+= $(FNREC_STATE)
+
+ifeq ($(FNREC),1)
+# Enabling -finstrument-functions affects gcc's analysis and leads to spurious
+# warnings about use of uninitialised variables.
+#
+CFLAGS		+= -Wno-uninitialized
+CFLAGS		+= -finstrument-functions
+CFLAGS		+= -finstrument-functions-exclude-file-list=core/fnrec.c
+endif
+
+# Enable per-item sections and section garbage collection.  Note that
+# some older versions of gcc support -fdata-sections but treat it as
+# implying -fno-common, which would break our build.  Some other older
+# versions issue a spurious and uninhibitable warning if
+# -ffunction-sections is used with -g, which would also break our
+# build since we use -Werror.
+#
+ifeq ($(CCTYPE),gcc)
+DS_TEST		= $(ECHO) 'char x;' | \
+		  $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \
+		  grep -E '\.comm' > /dev/null
+DS_FLAGS	:= $(shell $(DS_TEST) && $(ECHO) '-fdata-sections')
+FS_TEST		= $(CC) -ffunction-sections -g -c -x c /dev/null \
+		  -o /dev/null 2>/dev/null
+FS_FLAGS	:= $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections')
+CFLAGS		+= $(FS_FLAGS) $(DS_FLAGS)
+endif
+LDFLAGS		+= --gc-sections
+
+# Force creation of static binaries (required for OpenBSD, does no
+# harm on other platforms).
+#
+LDFLAGS		+= -static
+
+# compiler.h is needed for our linking and debugging system
+#
+CFLAGS		+= -include include/compiler.h
+
+# The section type character (e.g. "@" in "@progbits") varies by
+# architecture.
+#
+CFLAGS		+= -DASM_TCHAR='$(ASM_TCHAR)' -DASM_TCHAR_OPS='$(ASM_TCHAR_OPS)'
+
+# CFLAGS for specific object types
+#
+CFLAGS_c	+=
+CFLAGS_S 	+= -DASSEMBLY
+
+# Base object name of the current target
+#
+OBJECT		= $(firstword $(subst ., ,$(@F)))
+
+# CFLAGS for specific object files.  You can define
+# e.g. CFLAGS_rtl8139, and have those flags automatically used when
+# compiling bin/rtl8139.o.
+#
+OBJ_CFLAGS	= $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT))
+$(BIN)/%.flags :
+	@$(ECHO) $(OBJ_CFLAGS)
+
+# ICC requires postprocessing objects to fix up table alignments
+#
+ifeq ($(CCTYPE),icc)
+POST_O		= && $(ICCFIX) $@
+POST_O_DEPS	:= $(ICCFIX)
+else
+POST_O		:=
+POST_O_DEPS	:=
+endif
+
+# Debug level calculations
+#
+DBGLVL_MAX	= -DDBGLVL_MAX=$(firstword $(subst ., ,$(1)))
+DBGLVL_DFLT	= -DDBGLVL_DFLT=$(lastword $(subst ., ,$(1)))
+DBGLVL		= $(call DBGLVL_MAX,$(1)) $(call DBGLVL_DFLT,$(1))
+
+# Rules for specific object types.
+#
+COMPILE_c	= $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS)
+RULE_c		= $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O)
+RULE_c_to_ids.o = $(Q)$(ECHO_E) '$(OBJ_IDS_ASM_NL)' | $(ASSEMBLE_S) -o $@
+RULE_c_to_dbg%.o= $(Q)$(COMPILE_c) $(call DBGLVL,$*) -c $< -o $@ $(POST_O)
+RULE_c_to_c	= $(Q)$(COMPILE_c) -E -c $< > $@
+RULE_c_to_s	= $(Q)$(COMPILE_c) -S -g0 -c $< -o $@
+
+PREPROCESS_S	= $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS)
+ASSEMBLE_S	= $(AS) $(ASFLAGS)
+RULE_S		= $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_dbg%.o= $(Q)$(PREPROCESS_S) $(call DBGLVL,$*) $< | $(ASSEMBLE_S) -o $@
+RULE_S_to_s	= $(Q)$(PREPROCESS_S) $< > $@
+
+GENERIC_TARGETS	+= ids.o dbg%.o c s
+
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBED		:= $(EMBEDDED_IMAGE) # Maintain backwards compatibility
+EMBEDDED_LIST	:= $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBED_OLD := <invalid>
+else
+EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBED_OLD),$(EMBED))
+$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP	+= $(EMBEDDED_LIST)
+
+EMBEDDED_FILES	:= $(subst $(COMMA), ,$(EMBED))
+EMBED_ALL	:= $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
+		     EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+			     \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
+
+embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
+
+# List of trusted root certificates
+#
+TRUSTED_LIST	:= $(BIN)/.trusted.list
+ifeq ($(wildcard $(TRUSTED_LIST)),)
+TRUST_OLD := <invalid>
+else
+TRUST_OLD := $(shell cat $(TRUSTED_LIST))
+endif
+ifneq ($(TRUST_OLD),$(TRUST))
+$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST))
+endif
+
+$(TRUSTED_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP	+= $(TRUSTED_LIST)
+
+# Trusted root certificate fingerprints
+#
+TRUSTED_CERTS	:= $(subst $(COMMA), ,$(TRUST))
+TRUSTED_FPS	:= $(foreach CERT,$(TRUSTED_CERTS),\
+		     0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\
+			 $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \
+				 -fingerprint))))$(COMMA))
+
+rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
+
+CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
+
+# List of embedded certificates
+#
+CERT_LIST := $(BIN)/.certificate.list
+ifeq ($(wildcard $(CERT_LIST)),)
+CERT_OLD := <invalid>
+else
+CERT_OLD := $(shell cat $(CERT_LIST))
+endif
+ifneq ($(CERT_OLD),$(CERT))
+$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
+endif
+
+$(CERT_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(CERT_LIST)
+
+# Embedded certificates concatenated and then split into one file per
+# certificate (even if original files contained certificate chains)
+#
+CERT_FILES := $(subst $(COMMA), ,$(CERT))
+CERT_CONCAT := $(BIN)/.certificates.pem
+
+ifneq ($(CERT),)
+
+CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l)
+
+$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST)
+	$(Q)cat $(CERT_FILES) > $@
+
+# We must use an (otherwise unnecessary) pattern rule here to encode
+# the fact that one "csplit" command generates multiple targets
+CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
+	       $(BIN)/.certificate.pem.$(i))
+$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.%
+	$(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \
+		'/BEGIN CERTIFICATE/' '{*}'
+
+CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS))
+$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.%
+	$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
+
+CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\
+	      CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" ))
+
+endif
+
+certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS)
+
+CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)"
+
+CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.*
+
+# (Single-element) list of private keys
+#
+ifdef KEY
+PRIVKEY	:= $(KEY) # Maintain backwards compatibility
+endif
+PRIVKEY_LIST := $(BIN)/.private_key.list
+ifeq ($(wildcard $(PRIVKEY_LIST)),)
+PRIVKEY_OLD := <invalid>
+else
+PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST))
+endif
+ifneq ($(PRIVKEY_OLD),$(PRIVKEY))
+$(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST))
+endif
+
+$(PRIVKEY_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(PRIVKEY_LIST)
+
+# Embedded private key
+#
+PRIVKEY_INC := $(BIN)/.private_key.der
+
+ifdef PRIVKEY
+$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
+	$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
+
+privkey_DEPS += $(PRIVKEY_INC)
+endif
+
+CLEANUP += $(BIN)/.private_key.*
+
+privkey_DEPS += $(PRIVKEY_LIST)
+
+CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
+
+# (Single-element) list of named configurations
+#
+CONFIG_LIST := $(BIN)/.config.list
+ifeq ($(wildcard $(CONFIG_LIST)),)
+CONFIG_OLD := <invalid>
+else
+CONFIG_OLD := $(shell cat $(CONFIG_LIST))
+endif
+ifneq ($(CONFIG_OLD),$(CONFIG))
+$(shell $(ECHO) "$(CONFIG)" > $(CONFIG_LIST))
+endif
+
+$(CONFIG_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(CONFIG_LIST)
+
+# Named configurations
+#
+ifneq ($(CONFIG),)
+ifneq ($(wildcard config/$(CONFIG)),)
+CFLAGS	+= -DCONFIG=$(CONFIG)
+endif
+CFLAGS	+= -DLOCAL_CONFIG=$(CONFIG)
+endif
+
+config/named.h : $(CONFIG_LIST)
+	$(Q)$(TOUCH) $@
+
+.PRECIOUS : config/named.h
+
+# (Single-element) list of assertion configuration
+#
+ASSERT_LIST := $(BIN)/.assert.list
+ifeq ($(wildcard $(ASSERT_LIST)),)
+ASSERT_OLD := <invalid>
+else
+ASSERT_OLD := $(shell cat $(ASSERT_LIST))
+endif
+ifneq ($(ASSERT_OLD),$(ASSERT))
+$(shell $(ECHO) "$(ASSERT)" > $(ASSERT_LIST))
+endif
+
+$(ASSERT_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(ASSERT_LIST)
+
+# Assertion configuration
+#
+ifneq ($(ASSERT),)
+CFLAGS	+= -DASSERTING=$(ASSERT)
+endif
+
+include/assert.h : $(ASSERT_LIST)
+	$(Q)$(TOUCH) $@
+
+.PRECIOUS : include/assert.h
+
+# (Single-element) list of profiling configuration
+#
+PROFILE_LIST := $(BIN)/.profile.list
+ifeq ($(wildcard $(PROFILE_LIST)),)
+PROFILE_OLD := <invalid>
+else
+PROFILE_OLD := $(shell cat $(PROFILE_LIST))
+endif
+ifneq ($(PROFILE_OLD),$(PROFILE))
+$(shell $(ECHO) "$(PROFILE)" > $(PROFILE_LIST))
+endif
+
+$(PROFILE_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(PROFILE_LIST)
+
+# Profiling configuration
+#
+ifneq ($(PROFILE),)
+CFLAGS	+= -DPROFILING=$(PROFILE)
+endif
+
+include/ipxe/profile.h : $(PROFILE_LIST)
+	$(Q)$(TOUCH) $@
+
+.PRECIOUS : include/ipxe/profile.h
+
+# These files use .incbin inline assembly to include a binary file.
+# Unfortunately ccache does not detect this dependency and caches
+# builds even when the binary file has changed.
+#
+$(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC)
+$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC)
+$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC)
+
+# Debug message autocolourisation range
+#
+DBGCOL_LIST	:= $(BIN)/.dbgcol.list
+ifeq ($(wildcard $(DBGCOL_LIST)),)
+DBGCOL_OLD := <invalid>
+else
+DBGCOL_OLD := $(shell cat $(DBGCOL_LIST))
+endif
+ifneq ($(DBGCOL_OLD),$(DBGCOL))
+$(shell $(ECHO) "$(DBGCOL)" > $(DBGCOL_LIST))
+endif
+
+$(DBGCOL_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP += $(DBGCOL_LIST)
+
+DBGCOL_COLOURS := $(subst -, ,$(DBGCOL))
+DBGCOL_MIN := $(firstword $(DBGCOL_COLOURS))
+DBGCOL_MAX := $(lastword $(DBGCOL_COLOURS))
+
+debug_DEPS += $(DBGCOL_LIST)
+
+CFLAGS_debug += $(if $(DBGCOL_MIN),-DDBGCOL_MIN=$(DBGCOL_MIN))
+CFLAGS_debug += $(if $(DBGCOL_MAX),-DDBGCOL_MAX=$(DBGCOL_MAX))
+
+# We automatically generate rules for any file mentioned in AUTO_SRCS
+# using the following set of templates.  We use $(eval ...) if
+# available, otherwise we generate separate Makefile fragments and
+# include them.
+
+# deps_template : generate dependency list for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define deps_template_file
+$(call deps_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1))))
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define deps_template_parts
+	@$(ECHO) "  [DEPS] $(1)"
+	@$(MKDIR) -p $(BIN)/deps/$(dir $(1))
+	$(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
+		-Wno-error -M $(1) -MG -MP | \
+		sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
+endef
+
+# rules_template : generate rules for a given source file
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define rules_template
+$(call rules_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1))))
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+#
+define rules_template_parts
+$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
+	$$(QM)$(ECHO) "  [BUILD] $$@"
+	$$(RULE_$(2))
+BOBJS += $$(BIN)/$(3).o
+$(foreach TGT,$(GENERIC_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT))))
+$$(BIN)/deps/$(1).d : $$($(3)_DEPS)
+TAGS : $$($(3)_DEPS)
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+# $(2) is the source type (e.g. "c")
+# $(3) is the source base name (e.g. "rtl8139")
+# $(4) is the destination type (e.g. "dbg%.o")
+#
+define rules_template_target
+$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)
+	$$(QM)$(ECHO) "  [BUILD] $$@"
+	$$(RULE_$(2)_to_$(4))
+$(TGT)_OBJS += $$(BIN)/$(3).$(4)
+endef
+#
+# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c")
+#
+define rules_template_file
+	@$(ECHO) "  [RULES] $(1)"
+	@$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+	@$(ECHO_E) '$(subst $(NEWLINE),\n,$(call rules_template,$(1)))' \
+		 > $(BIN)/rules/$(1).r
+endef
+
+# Generate the dependency files
+#
+$(BIN)/deps/%.d : % $(MAKEDEPS)
+	$(call deps_template_file,$<)
+
+# Calculate list of dependency files
+#
+AUTO_DEPS	= $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
+autodeps :
+	@$(ECHO) $(AUTO_DEPS)
+VERYCLEANUP	+= $(BIN)/deps
+
+# Include dependency files
+#
+ifdef NEED_DEPS
+ifneq ($(AUTO_DEPS),)
+-include $(AUTO_DEPS)
+endif
+endif
+
+# Generate the rules files
+#
+$(BIN)/rules/%.r : % $(MAKEDEPS)
+	$(call rules_template_file,$<)
+
+# Calculate list of rules files
+#
+AUTO_RULES	= $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS))
+autorules :
+	@$(ECHO) $(AUTO_RULES)
+VERYCLEANUP	+= $(BIN)/rules
+
+# Evaluate rules (or include rules files)
+#
+ifdef NEED_DEPS
+ifneq ($(AUTO_RULES),)
+ifneq ($(HAVE_EVAL),)
+$(foreach SRC,$(AUTO_SRCS),$(eval $(call rules_template,$(SRC))))
+else
+-include $(AUTO_RULES)
+endif
+endif
+endif
+
+# Files to be parsed using parserom.pl
+#
+ROM_SRCS	= $(foreach SRC,$(AUTO_SRCS),\
+		    $(if $(findstring drivers/,$(SRC)),$(SRC)))
+romsrcs :
+	@$(ECHO) $(ROM_SRCS)
+
+# List of files to be parsed using parserom.pl
+#
+ROM_SRCS_LIST	:= $(BIN)/.rom.list
+ifeq ($(wildcard $(ROM_SRCS_LIST)),)
+ROM_SRCS_OLD := <invalid>
+else
+ROM_SRCS_OLD := $(shell cat $(ROM_SRCS_LIST))
+endif
+ifneq ($(ROM_SRCS_OLD),$(ROM_SRCS))
+$(shell $(ECHO) "$(ROM_SRCS)" > $(ROM_SRCS_LIST))
+endif
+
+$(ROM_SRCS_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP	+= $(ROM_SRCS_LIST)
+
+# ROM definition file
+#
+ROMDEFS		= $(BIN)/.rom.defs
+$(ROMDEFS) : $(ROM_SRCS) $(ROM_SRCS_LIST) $(PARSEROM) $(MAKEDEPS)
+	$(QM)$(ECHO) "  [PARSEROM]"
+	$(Q)$(PERL) $(PARSEROM) $(ROM_SRCS) > $@
+
+VERYCLEANUP	+= $(ROMDEFS)
+
+# Evaluate ROM definition file
+ifdef NEED_DEPS
+ifneq ($(ROM_SRCS),)
+-include $(ROMDEFS)
+endif
+endif
+
+# Device ID tables (using IDs from ROM definition file)
+#
+define obj_pci_id_asm
+	.section ".pci_devlist.$(1)", "a", $(ASM_TCHAR)progbits
+	.globl pci_devlist_$(1)
+pci_devlist_$(1):
+	.short ( 0x$(1) & 0xffff )
+
+endef
+define obj_isa_id_asm
+endef
+OBJ_IDS_ASM	= $(foreach ROM,$(ROMS_$(OBJECT)),$(call obj_$(ROM_TYPE_$(ROM))_id_asm,$(ROM)))
+OBJ_IDS_ASM_NL	= $(subst $(NEWLINE),\n,$(OBJ_IDS_ASM))
+$(BIN)/%.ids :
+	@$(ECHO_E) '$(OBJ_IDS_ASM_NL)'
+
+BOBJS	+= $(patsubst %,$(BIN)/%.ids.o,$(DRIVERS))
+
+# The following variables are created by the autogenerated rules
+#
+bobjs :
+	@$(ECHO) $(BOBJS)
+drivers_% :
+	@$(ECHO) $(DRIVERS_$*)
+drivers :
+	@$(ECHO) $(DRIVERS)
+.PHONY : drivers
+roms :
+	@$(ECHO) $(ROMS)
+
+# Generate error usage information
+#
+$(BIN)/%.einfo : $(BIN)/%.o
+	$(QM)$(ECHO) "  [EINFO] $@"
+	$(Q)$(OBJCOPY) -O binary -j .einfo --set-section-flags .einfo=alloc \
+		$< $@
+
+EINFOS		:= $(patsubst $(BIN)/%.o,$(BIN)/%.einfo,$(BOBJS))
+$(BIN)/errors : $(EINFOS) $(EINFO)
+	$(QM)$(ECHO) "  [EINFO] $@"
+	$(Q)$(EINFO) $(EINFOS) | sort > $@
+CLEANUP		+= $(BIN)/errors	# Doesn't match the $(BIN)/*.* pattern
+
+# Generate the NIC file from the parsed source files.  The NIC file is
+# only for rom-o-matic.
+#
+$(BIN)/NIC : $(AUTO_DEPS)
+	@$(ECHO) '# This is an automatically generated file, do not edit' > $@
+	@$(ECHO) '# It does not affect anything in the build, ' \
+	     'it is only for rom-o-matic' >> $@
+	@$(ECHO) >> $@
+	@perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@
+CLEANUP		+= $(BIN)/NIC	# Doesn't match the $(BIN)/*.* pattern
+
+# Select drivers to be included in the all-drivers build
+#
+DRIVERS_ipxe	= $(DRIVERS_net) $(DRIVERS_infiniband) \
+		  $(DRIVERS_xen) $(DRIVERS_hyperv)
+
+# Analyse a target name (e.g. "bin/dfe538--prism2_pci.rom.tmp") and
+# derive the variables:
+# 
+# TGT_ELEMENTS : the elements of the target (e.g. "dfe538 prism2_pci")
+# TGT_PREFIX   : the prefix type (e.g. "pcirom")
+# TGT_DRIVERS  : the driver for each element (e.g. "rtl8139 prism2_pci")
+# TGT_ROM_NAME : the ROM name (e.g. "dfe538")
+#
+TGT_ELEMENTS	= $(subst --, ,$(firstword $(subst ., ,$(notdir $@))))
+TGT_ROM_NAME	= $(firstword $(TGT_ELEMENTS))
+TGT_DRIVERS	= $(strip $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \
+				    $(if $(DRIVERS_$(TGT_ELEMENT)), \
+					 $(DRIVERS_$(TGT_ELEMENT)), \
+					 $(firstword $(DRIVER_$(TGT_ELEMENT)) \
+						     $(TGT_ELEMENT)))))
+TGT_PREFIX_NAME	= $(word 2,$(subst ., ,$(notdir $@)))
+TGT_PREFIX	= $(strip $(if $(filter rom,$(TGT_PREFIX_NAME)), \
+			       $(ROM_TYPE_$(TGT_ROM_NAME))rom, \
+			       $(TGT_PREFIX_NAME)))
+
+# Look up ROM IDs for the current target
+# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables:
+#
+# TGT_PCI_VENDOR : the PCI vendor ID (e.g. "0x1186")
+# TGT_PCI_DEVICE : the PCI device ID (e.g. "0x1300")
+#
+TGT_PCI_VENDOR	= $(PCI_VENDOR_$(TGT_ROM_NAME))
+TGT_PCI_DEVICE	= $(PCI_DEVICE_$(TGT_ROM_NAME))
+
+# Calculate link-time options for the current target
+# (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the variables:
+#
+# TGT_LD_DRIVERS : symbols to require in order to drag in the relevant drivers
+#		   (e.g. "obj_rtl8139 obj_prism2_pci")
+# TGT_LD_IDS :     symbols to define in order to fill in ID structures in the
+#		   ROM header (e.g."pci_vendor_id=0x1186 pci_device_id=0x1300")
+#
+TGT_LD_DRIVERS	= $(subst -,_,$(patsubst %,obj_%,$(TGT_DRIVERS)))
+TGT_LD_IDS	= pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \
+		  pci_device_id=$(firstword $(TGT_PCI_DEVICE) 0)
+TGT_LD_DEVLIST	= $(foreach ELEM,$(TGT_ELEMENTS),$(if $(PCI_VENDOR_$(ELEM)),\
+		    pci_devlist_$(patsubst 0x%,%,$(PCI_VENDOR_$(ELEM)))$(patsubst 0x%,%,$(PCI_DEVICE_$(ELEM)))))
+TGT_LD_ENTRY	= _$(TGT_PREFIX)_start
+
+# Calculate linker flags based on link-time options for the current
+# target type (e.g. "bin/dfe538--prism2_pci.rom.tmp") and derive the
+# variables:
+#
+# TGT_LD_FLAGS : target-specific flags to pass to linker (e.g.
+#		 "-u obj_zpciprefix -u obj_rtl8139 -u obj_prism2_pci
+#		  --defsym pci_vendor=0x1186 --defsym pci_device=0x1300")
+#
+TGT_LD_FLAGS	= $(foreach SYM,$(TGT_LD_ENTRY) $(TGT_LD_DRIVERS) \
+		    $(TGT_LD_DEVLIST) obj_config obj_config_$(PLATFORM),\
+		    -u $(SYM) --defsym check_$(SYM)=$(SYM) ) \
+		  $(patsubst %,--defsym %,$(TGT_LD_IDS)) \
+		  -e $(TGT_LD_ENTRY)
+
+# Calculate list of debugging versions of objects to be included in
+# the target.
+#
+DEBUG_LIST	= $(subst $(COMMA), ,$(DEBUG))
+DEBUG_MAX	= $(firstword $(word 2,$(subst :, ,$(1))) 1)
+DEBUG_DFLT	= $(if $(word 3,$(subst :, ,$(1))),.$(word 3,$(subst :, ,$(1))))
+DEBUG_LEVEL	= $(call DEBUG_MAX,$(1))$(call DEBUG_DFLT,$(1))
+DEBUG_BASE	= $(firstword $(subst :, ,$(1))).dbg$(call DEBUG_LEVEL,$(1))
+DEBUG_OBJ	= $(BIN)/$(call DEBUG_BASE,$(1)).o
+DEBUG_ORIG_OBJ	= $(BIN)/$(firstword $(subst :, ,$(1))).o
+DEBUG_OBJS	= $(foreach D,$(DEBUG_LIST),$(call DEBUG_OBJ,$(D)))
+DEBUG_ORIG_OBJS	= $(foreach D,$(DEBUG_LIST),$(call DEBUG_ORIG_OBJ,$(D)))
+BLIB_OBJS	= $(DEBUG_OBJS) $(filter-out $(DEBUG_ORIG_OBJS),$(BOBJS))
+
+# Print out all derived information for a given target.
+#
+$(BIN)/%.info :
+	@$(ECHO) 'Elements             : $(TGT_ELEMENTS)'
+	@$(ECHO) 'Prefix               : $(TGT_PREFIX)'
+	@$(ECHO) 'Drivers              : $(TGT_DRIVERS)'
+	@$(ECHO) 'ROM name             : $(TGT_ROM_NAME)'
+	@$(ECHO)
+	@$(ECHO) 'PCI vendor           : $(TGT_PCI_VENDOR)'
+	@$(ECHO) 'PCI device           : $(TGT_PCI_DEVICE)'
+	@$(ECHO)
+	@$(ECHO) 'LD driver symbols    : $(TGT_LD_DRIVERS)'
+	@$(ECHO) 'LD ID symbols        : $(TGT_LD_IDS)'
+	@$(ECHO) 'LD devlist symbols   : $(TGT_LD_DEVLIST)'
+	@$(ECHO) 'LD entry point       : $(TGT_LD_ENTRY)'
+	@$(ECHO)
+	@$(ECHO) 'LD target flags      : $(TGT_LD_FLAGS)'
+	@$(ECHO)
+	@$(ECHO) 'Debugging objects    : $(DEBUG_OBJS)'
+	@$(ECHO) 'Replaced objects     : $(DEBUG_ORIG_OBJS)'
+
+# List of objects included in the last build of blib.  This is needed
+# in order to correctly rebuild blib whenever the list of objects
+# changes.
+#
+BLIB_LIST	:= $(BIN)/.blib.list
+ifeq ($(wildcard $(BLIB_LIST)),)
+BLIB_OBJS_OLD	:= <invalid>
+else
+BLIB_OBJS_OLD	:= $(shell cat $(BLIB_LIST))
+endif
+ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS))
+$(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST))
+endif
+
+$(BLIB_LIST) : $(MAKEDEPS)
+
+VERYCLEANUP	+= $(BLIB_LIST)
+
+# Library of all objects
+#
+BLIB		= $(BIN)/blib.a
+$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
+	$(Q)$(RM) $(BLIB)
+	$(QM)$(ECHO) "  [AR] $@"
+	$(Q)$(AR) r $@ $(sort $(BLIB_OBJS))
+	$(Q)$(RANLIB) $@
+blib : $(BLIB)
+
+# Command to generate build ID.  Must be unique for each $(BIN)/%.tmp,
+# even within the same build run.
+#
+BUILD_ID_CMD	:= perl -e 'printf "0x%08x", int ( rand ( 0xffffffff ) );'
+
+# Build timestamp
+#
+BUILD_TIMESTAMP := $(shell date +%s)
+
+# Build version
+#
+GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
+$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
+	$(QM)$(ECHO) "  [VERSION] $@"
+	$(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
+		-DVERSION_MAJOR=$(VERSION_MAJOR) \
+		-DVERSION_MINOR=$(VERSION_MINOR) \
+		-DVERSION_PATCH=$(VERSION_PATCH) \
+		-DVERSION="\"$(VERSION)\"" \
+		-c $< -o $@
+
+# Build an intermediate object file from the objects required for the
+# specified target.
+#
+$(BIN)/%.tmp : $(BIN)/version.%.o $(BLIB) $(MAKEDEPS) $(LDSCRIPT)
+	$(QM)$(ECHO) "  [LD] $@"
+	$(Q)$(LD) $(LDFLAGS) -T $(LDSCRIPT) $(TGT_LD_FLAGS) $< $(BLIB) -o $@ \
+		--defsym _build_id=`$(BUILD_ID_CMD)` \
+		--defsym _build_timestamp=$(BUILD_TIMESTAMP) \
+		-Map $(BIN)/$*.tmp.map
+	$(Q)$(OBJDUMP) -ht $@ | $(PERL) $(SORTOBJDUMP) >> $(BIN)/$*.tmp.map
+
+# Keep intermediate object file (useful for debugging)
+.PRECIOUS : $(BIN)/%.tmp
+
+# Show a linker map for the specified target
+#
+$(BIN)/%.map : $(BIN)/%.tmp
+	@less $(BIN)/$*.tmp.map
+
+# Get objects list for the specified target
+#
+define objs_list
+	$(sort $(foreach OBJ_SYMBOL,\
+		 $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+		 $(patsubst obj_%,%,$(OBJ_SYMBOL))))
+endef
+$(BIN)/%.objs : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call objs_list,$<)
+$(BIN)/%.sizes : $(BIN)/%.tmp
+	$(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \
+		sort -g
+
+# Get dependency list for the specified target
+#
+define deps_list
+	$(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS)))
+endef
+$(BIN)/%.deps : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call deps_list,$<)
+
+# Get unneeded source files for the specified target
+#
+define nodeps_list
+	$(sort $(filter-out $(call deps_list,$(1)),\
+		 $(foreach BOBJ,$(BOBJS),\
+		   $($(basename $(notdir $(BOBJ)))_DEPS))))
+endef
+$(BIN)/%.nodeps : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call nodeps_list,$<)
+
+# Get licensing verdict for the specified target
+#
+define licensable_deps_list
+	$(filter-out config/local/%.h,\
+	  $(filter-out $(BIN)/.%.list,\
+	    $(call deps_list,$(1))))
+endef
+define unlicensed_deps_list
+	$(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1)))
+endef
+define licence_list
+	$(sort $(foreach LICENCE,\
+		 $(filter __licence__%,$(shell $(NM) $(1) | cut -d" " -f3)),\
+		 $(word 2,$(subst __, ,$(LICENCE)))))
+endef
+$(BIN)/%.licence_list : $(BIN)/%.tmp
+	$(Q)$(ECHO) $(call licence_list,$<)
+$(BIN)/%.licence : $(BIN)/%.tmp
+	$(QM)$(ECHO) "  [LICENCE] $@"
+	$(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\
+		echo -n "Unable to determine licence because the following " ;\
+		echo "files are missing a licence declaration:" ;\
+		echo $(call unlicensed_deps_list,$<);\
+		exit 1,\
+		$(PERL) $(LICENCE) $(call licence_list,$<))
+
+# Extract compression information from intermediate object file
+#
+$(BIN)/%.zinfo : $(BIN)/%.tmp
+	$(QM)$(ECHO) "  [ZINFO] $@"
+	$(Q)$(OBJCOPY) -O binary -j .zinfo $< $@
+
+# Build raw binary file from intermediate object file
+#
+$(BIN)/%.bin : $(BIN)/%.tmp
+	$(QM)$(ECHO) "  [BIN] $@"
+	$(Q)$(OBJCOPY) -O binary -R .zinfo $< $@
+
+# Compress raw binary file
+#
+$(BIN)/%.zbin : $(BIN)/%.bin $(BIN)/%.zinfo $(ZBIN)
+	$(QM)$(ECHO) "  [ZBIN] $@"
+	$(Q)$(ZBIN) $(BIN)/$*.bin $(BIN)/$*.zinfo > $@
+
+# Rules for each media format.  These are generated and placed in an
+# external Makefile fragment.  We could do this via $(eval ...), but
+# that would require make >= 3.80.
+# 
+# Note that there's an alternative way to generate most .rom images:
+# they can be copied from their 'master' ROM image using cp and
+# reprocessed with makerom to add the PCI IDs and ident string.  The
+# relevant rule would look something like:
+#
+#   $(BIN)/dfe538%rom : $(BIN)/rtl8139%rom
+#	cat $< $@
+#	$(FINALISE_rom)
+# 
+# You can derive the ROM/driver relationships using the variables
+# DRIVER_<rom> and/or ROMS_<driver>.
+# 
+# We don't currently do this, because (a) it would require generating
+# yet more Makefile fragments (since you need a rule for each ROM in
+# ROMS), and (b) the linker is so fast that it probably wouldn't make
+# much difference to the overall build time.
+
+# Add NON_AUTO_MEDIA to the media list, so that they show up in the
+# output of "make"
+#
+MEDIA		+= $(NON_AUTO_MEDIA)
+
+media :
+	@$(ECHO) $(MEDIA)
+
+AUTO_MEDIA	= $(filter-out $(NON_AUTO_MEDIA),$(MEDIA))
+automedia :
+	@$(ECHO) $(AUTO_MEDIA)
+
+# media_template : create media rules
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template
+$(if $(filter $(1),$(AUTO_MEDIA)),$(call auto_media_template,$(1)))
+LIST_$(1) := $$(if $$(LIST_NAME_$(1)),$$($$(LIST_NAME_$(1))),$$(DRIVERS))
+ALL_$(1) = $$(foreach ITEM,$$(LIST_$(1)),$$(BIN)/$$(ITEM).$(1))
+$$(BIN)/all$(1)s : $$(ALL_$(1))
+$$(BIN)/allall : $$(BIN)/all$(1)s
+all$(1)s : $$(BIN)/all$(1)s
+allall : $$(BIN)/allall
+endef
+#
+# $(1) is the media name (e.g. "rom")
+#
+define auto_media_template
+$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin
+	$$(QM)echo "  [FINISH] $$@"
+	$$(Q)$$(CP) $$< $$@
+	$$(Q)$$(if $$(PAD_$(1)),$$(PAD_$(1)) $$@)
+	$$(Q)$$(if $$(FINALISE_$(1)),$$(FINALISE_$(1)) $$@)
+endef
+#
+# $(1) is the media name (e.g. "rom")
+#
+define media_template_file
+	@$(ECHO) "  [MEDIARULES] $(1)"
+	@$(MKDIR) -p $(BIN)/rules/$(dir $(1))
+	@$(ECHO_E) '$(subst $(NEWLINE),\n,$(call media_template,$(1)))' \
+		> $(BIN)/rules/$(1).media.r
+endef
+
+# Generate media rules files
+#
+$(BIN)/rules/%.media.r : $(MAKEDEPS)
+	$(call media_template_file,$*)
+
+# Calculate list of media rules files
+#
+MEDIA_RULES		= $(patsubst %,$(BIN)/rules/%.media.r,$(MEDIA))
+mediarules :
+	@$(ECHO) $(MEDIA_RULES)
+
+# Evaluate media rules (or include media rules files)
+#
+ifdef NEED_DEPS
+ifneq ($(MEDIA_RULES),)
+ifneq ($(HAVE_EVAL),)
+$(foreach MEDIUM,$(MEDIA),$(eval $(call media_template,$(MEDIUM))))
+else
+-include $(MEDIA_RULES)
+endif
+endif
+endif
+
+# Alias for ipxe.%
+#
+$(BIN)/etherboot.% : $(BIN)/ipxe.%
+	ln -sf $(notdir $<) $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# The compression utilities
+#
+
+ZBIN_LDFLAGS := -llzma
+
+$(ZBIN) : util/zbin.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) $< $(ZBIN_LDFLAGS) -o $@
+CLEANUP += $(ZBIN)
+
+###############################################################################
+#
+# The EFI image converter
+#
+
+$(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -DEFI_TARGET32 $< -o $@
+CLEANUP += $(ELF2EFI32)
+
+$(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -DEFI_TARGET64 $< -o $@
+CLEANUP += $(ELF2EFI64)
+
+$(EFIROM) : util/efirom.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EFIROM)
+
+$(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EFIFATBIN)
+
+###############################################################################
+#
+# The ICC fixup utility
+#
+$(ICCFIX) : util/iccfix.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(ICCFIX)
+
+###############################################################################
+#
+# The error usage information utility
+#
+$(EINFO) : util/einfo.c $(MAKEDEPS)
+	$(QM)$(ECHO) "  [HOSTCC] $@"
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
+CLEANUP += $(EINFO)
+
+###############################################################################
+#
+# Local configs
+#
+CONFIG_HEADERS := $(patsubst config/%,%,$(wildcard config/*.h))
+CONFIG_LOCAL_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\
+				  config/local/$(HEADER))
+
+$(CONFIG_LOCAL_HEADERS) :
+	$(Q)$(TOUCH) $@
+
+.PRECIOUS : $(CONFIG_LOCAL_HEADERS)
+
+ifneq ($(CONFIG),)
+
+CONFIG_LOCAL_NAMED_HEADERS := $(foreach HEADER,$(CONFIG_HEADERS),\
+					config/local/$(CONFIG)/$(HEADER))
+
+$(CONFIG_LOCAL_NAMED_HEADERS) :
+	$(Q)$(MKDIR) -p $(dir $@)
+	$(Q)$(TOUCH) $@
+
+.PRECIOUS : $(CONFIG_LOCAL_NAMED_HEADERS)
+
+endif
+
+###############################################################################
+#
+# Build the TAGS file(s) for emacs
+#
+TAGS :
+	ctags -e -R -f $@ --exclude=bin
+
+CLEANUP	+= TAGS
+
+###############################################################################
+#
+# Force rebuild for any given target
+#
+%.rebuild :
+	rm -f $*
+	$(Q)$(MAKE) $*
+
+###############################################################################
+#
+# Symbol table checks
+#
+
+ifdef BIN
+
+SYMTAB	= $(BIN)/symtab
+$(SYMTAB) : $(BLIB)
+	$(OBJDUMP) -w -t $< > $@
+
+CLEANUP	+= $(BIN)/symtab
+
+symcheck : $(SYMTAB)
+	$(PERL) $(SYMCHECK) $<
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Build bochs symbol table
+#
+
+ifdef BIN
+
+$(BIN)/%.bxs : $(BIN)/%.tmp
+	$(NM) $< | cut -d" " -f1,3 > $@
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Documentation
+#
+
+ifdef BIN
+
+$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
+	$(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
+		-e  's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \
+		-e  's{\@BIN\@}{$(BIN)}; ' \
+		-e  's{\@ARCH\@}{$(ARCH)}; ' \
+		$< > $@
+
+$(BIN)/doc : $(BIN)/doxygen.cfg
+	$(Q)$(DOXYGEN) $<
+
+.PHONY : $(BIN)/doc
+
+doc : $(BIN)/doc
+
+doc-clean :
+	$(Q)$(RM) -r $(BIN)/doc
+
+VERYCLEANUP	+= $(BIN)/doc
+
+docview :
+	@[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc
+	@if [ -n "$$BROWSER" ] ; then \
+		( $$BROWSER $(BIN)/doc/html/index.html & ) ; \
+	else \
+		$(ECHO) "Documentation index in $(BIN)/doc/html/index.html" ; \
+	fi
+
+endif # defined(BIN)
+
+###############################################################################
+#
+# Keyboard maps
+#
+
+hci/keymap/keymap_%.c :
+	$(Q)$(PERL) $(GENKEYMAP) $* > $@
+
+###############################################################################
+#
+# Force deletion of incomplete targets
+#
+
+.DELETE_ON_ERROR :
+
+###############################################################################
+#
+# Clean-up
+#
+
+ifeq ($(NUM_BINS),0)
+ALLBINS		:= bin{,-*}
+CLEANUP		:= $(patsubst $(BIN)/%,$(ALLBINS)/%,$(CLEANUP))
+VERYCLEANUP	:= $(patsubst $(BIN)/%,$(ALLBINS)/%,$(VERYCLEANUP))
+endif
+
+clean :
+	$(RM) $(CLEANUP)
+
+veryclean : clean
+	$(RM) -r $(VERYCLEANUP)
diff --git a/debian/.gitignore b/debian/.gitignore
deleted file mode 100644
index f7a525b6..00000000
--- a/debian/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-/*
-!/README*
-!/config/
-!/source/
-!/tree/
diff --git a/debian/changelog b/debian/changelog
index 43e7fe98..131c3f65 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+ipxe (1.0.0+git-20190125.36a4c85-5.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Apply upstream patch to fix FTBFS with gcc 10. (Closes: #966942)
+
+ -- Chris Hofstaedtler <zeha@debian.org>  Sun, 07 Feb 2021 17:25:50 +0000
+
 ipxe (1.0.0+git-20190125.36a4c85-5) unstable; urgency=medium
 
   * Cleanup src/bin correctly. (closes: #952275)
diff --git a/debian/patches/debian-changes b/debian/patches/debian-changes
new file mode 100644
index 00000000..526e1054
--- /dev/null
+++ b/debian/patches/debian-changes
@@ -0,0 +1,33 @@
+diff --git a/src/arch/x86/prefix/romprefix.S b/src/arch/x86/prefix/romprefix.S
+index 3abef0ea..d0789bbf 100644
+--- a/src/arch/x86/prefix/romprefix.S
++++ b/src/arch/x86/prefix/romprefix.S
+@@ -28,7 +28,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
+ #define PCI_FUNC_MASK 0x07
+ 
+ /* ROM banner timeout, converted to a number of (18Hz) timer ticks. */
++#ifndef ROM_BANNER_TIMEOUT_TICKS
+ #define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 )
++#endif
+ 
+ /* Allow payload to be excluded from ROM size
+  */
+diff --git a/src/bin/.gitignore b/src/bin/.gitignore
+deleted file mode 100644
+index 72e8ffc0..00000000
+--- a/src/bin/.gitignore
++++ /dev/null
+@@ -1 +0,0 @@
+-*
+diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c
+index 2c5b9df8..4144265e 100644
+--- a/src/util/elf2efi.c
++++ b/src/util/elf2efi.c
+@@ -18,6 +18,7 @@
+  */
+ 
+ #define FILE_LICENCE(...) extern void __file_licence ( void )
++#define _GNU_SOURCE
+ #include <stdint.h>
+ #include <stddef.h>
+ #include <stdlib.h>
diff --git a/debian/patches/f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch b/debian/patches/f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch
new file mode 100644
index 00000000..9df561f6
--- /dev/null
+++ b/debian/patches/f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch
@@ -0,0 +1,27 @@
+From f982a712979619dbae2c6e0d741757e2ce94be11 Mon Sep 17 00:00:00 2001
+From: Bruce Rogers <brogers@suse.com>
+Date: Wed, 6 May 2020 15:03:02 -0600
+Subject: [PATCH] [build] Be explicit about -fcommon compiler directive
+
+gcc10 switched default behavior from -fcommon to -fno-common.  Since
+"__shared" relies on the legacy behavior, explicitly specify it.
+
+Signed-off-by: Bruce Rogers <brogers@suse.com>
+Modified-by: Michael Brown <mcb30@ipxe.org>
+Signed-off-by: Michael Brown <mcb30@ipxe.org>
+---
+ src/Makefile.housekeeping | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
+index 66d6dd449..b6c61c112 100644
+--- a/src/Makefile.housekeeping
++++ b/src/Makefile.housekeeping
+@@ -418,6 +418,7 @@ CFLAGS		+= -Os
+ CFLAGS		+= -g
+ ifeq ($(CCTYPE),gcc)
+ CFLAGS		+= -ffreestanding
++CFLAGS		+= -fcommon
+ CFLAGS		+= -Wall -W -Wformat-nonliteral
+ HOST_CFLAGS	+= -Wall -W -Wformat-nonliteral
+ endif
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 00000000..e95da723
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+debian-changes
+f982a712979619dbae2c6e0d741757e2ce94be11-fcommon.patch
diff --git a/debian/source/format b/debian/source/format
index 7cb86238..163aaf8d 100644
--- a/debian/source/format
+++ b/debian/source/format
@@ -1 +1 @@
-3.0 (gitarchive)
+3.0 (quilt)
diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping
index f8334921..ab2581ee 100644
--- a/src/Makefile.housekeeping
+++ b/src/Makefile.housekeeping
@@ -413,6 +413,7 @@ CFLAGS		+= -Os
 CFLAGS		+= -g
 ifeq ($(CCTYPE),gcc)
 CFLAGS		+= -ffreestanding
+CFLAGS		+= -fcommon
 CFLAGS		+= -Wall -W -Wformat-nonliteral
 HOST_CFLAGS	+= -Wall -W -Wformat-nonliteral
 endif

Run locally

More details

Full run details