mirror of
				https://gitlab.com/qemu-project/ipxe.git
				synced 2025-11-03 07:59:06 +08:00 
			
		
		
		
	Compare commits
	
		
			10 Commits
		
	
	
		
			shutdown_t
			...
			fix486
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bc35b24e3e | |||
| 6ba671acd9 | |||
| ec746c0001 | |||
| e814d33900 | |||
| f4f9adf618 | |||
| fbbdc39260 | |||
| 53a5de3641 | |||
| 91c77e2592 | |||
| f43c2fd697 | |||
| 9062544f6a | 
@ -190,7 +190,7 @@ vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
 | 
			
		||||
	@$(ECHO) '    bin/10222000.rom  -- vlance/pcnet32'
 | 
			
		||||
	@$(ECHO) '    bin/15ad07b0.rom  -- vmxnet3'
 | 
			
		||||
	@$(ECHO) 
 | 
			
		||||
	@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
 | 
			
		||||
	@$(ECHO) 'For more information, see https://ipxe.org/howto/vmware'
 | 
			
		||||
	@$(ECHO)
 | 
			
		||||
	@$(ECHO) '==========================================================='
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -918,7 +918,7 @@ $(BIN)/deps/%.d : % $(MAKEDEPS)
 | 
			
		||||
 | 
			
		||||
# Calculate list of dependency files
 | 
			
		||||
#
 | 
			
		||||
AUTO_DEPS	= $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
 | 
			
		||||
AUTO_DEPS	= $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS) core/version.c)
 | 
			
		||||
autodeps :
 | 
			
		||||
	@$(ECHO) $(AUTO_DEPS)
 | 
			
		||||
VERYCLEANUP	+= $(BIN)/deps
 | 
			
		||||
@ -1202,7 +1202,7 @@ endif
 | 
			
		||||
# Build version
 | 
			
		||||
#
 | 
			
		||||
GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
 | 
			
		||||
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
 | 
			
		||||
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(version_DEPS) $(GIT_INDEX)
 | 
			
		||||
	$(QM)$(ECHO) "  [VERSION] $@"
 | 
			
		||||
	$(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
 | 
			
		||||
		-DVERSION_MAJOR=$(VERSION_MAJOR) \
 | 
			
		||||
 | 
			
		||||
@ -136,6 +136,8 @@ SECTIONS {
 | 
			
		||||
	*(.note.*)
 | 
			
		||||
	*(.discard)
 | 
			
		||||
	*(.discard.*)
 | 
			
		||||
	*(.sbat)
 | 
			
		||||
	*(.sbat.*)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
 | 
			
		||||
@ -100,5 +100,7 @@ SECTIONS {
 | 
			
		||||
		*(.rel.*)
 | 
			
		||||
		*(.discard)
 | 
			
		||||
		*(.discard.*)
 | 
			
		||||
		*(.sbat)
 | 
			
		||||
		*(.sbat.*)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -47,7 +47,7 @@ static char __bss16_array ( syslinux_version, [32] );
 | 
			
		||||
#define syslinux_version __use_data16 ( syslinux_version )
 | 
			
		||||
 | 
			
		||||
/** The "SYSLINUX" copyright string */
 | 
			
		||||
static char __data16_array ( syslinux_copyright, [] ) = " http://ipxe.org";
 | 
			
		||||
static char __data16_array ( syslinux_copyright, [] ) = " https://ipxe.org";
 | 
			
		||||
#define syslinux_copyright __use_data16 ( syslinux_copyright )
 | 
			
		||||
 | 
			
		||||
static char __data16_array ( syslinux_configuration_file, [] ) = "";
 | 
			
		||||
 | 
			
		||||
@ -380,6 +380,11 @@ process_bytes:
 | 
			
		||||
	pushl	%eax
 | 
			
		||||
	pushl	%ebp
 | 
			
		||||
 | 
			
		||||
	/* Construct ljmp code on stack (since .prefix may not be writable) */
 | 
			
		||||
	.equ	LJMP_LEN, 0x06
 | 
			
		||||
	pushw	%cs		/* "nop ; ljmp %cs, $2f" */
 | 
			
		||||
	pushw	$2f
 | 
			
		||||
	pushw	$0xea90
 | 
			
		||||
	/* Construct GDT on stack (since .prefix may not be writable) */
 | 
			
		||||
	.equ	GDT_LEN, 0x20
 | 
			
		||||
	.equ	PM_DS, 0x18	/* Flat data segment */
 | 
			
		||||
@ -410,8 +415,9 @@ process_bytes:
 | 
			
		||||
	pushw	%es
 | 
			
		||||
	pushw	%ds
 | 
			
		||||
	pushw	%ss
 | 
			
		||||
	pushw	%cs
 | 
			
		||||
	pushw	$2f
 | 
			
		||||
	pushw	%ss		/* Far pointer to ljmp code on stack */
 | 
			
		||||
	leaw	(GDT_LEN + 1)(%bp), %ax
 | 
			
		||||
	pushw	%ax
 | 
			
		||||
	cli
 | 
			
		||||
	data32 lgdt (%bp)
 | 
			
		||||
	movl	%cr0, %eax
 | 
			
		||||
@ -438,7 +444,7 @@ process_bytes:
 | 
			
		||||
	popfw
 | 
			
		||||
	movl	%eax, %cr0
 | 
			
		||||
	lret
 | 
			
		||||
2:	/* lret will ljmp to here */
 | 
			
		||||
2:	/* lret will ljmp to here (via constructed ljmp on stack) */
 | 
			
		||||
	popw	%ss
 | 
			
		||||
	popw	%ds
 | 
			
		||||
	popw	%es
 | 
			
		||||
@ -461,7 +467,7 @@ process_bytes:
 | 
			
		||||
 | 
			
		||||
	/* Restore GDT */
 | 
			
		||||
	data32 lgdt -8(%bp)
 | 
			
		||||
	leaw	GDT_LEN(%bp), %sp
 | 
			
		||||
	leaw	(GDT_LEN + LJMP_LEN)(%bp), %sp
 | 
			
		||||
 | 
			
		||||
	/* Restore registers and return */
 | 
			
		||||
	popl	%ebp
 | 
			
		||||
 | 
			
		||||
@ -161,7 +161,7 @@ pnpheader:
 | 
			
		||||
 | 
			
		||||
/* Manufacturer string */
 | 
			
		||||
mfgstr:
 | 
			
		||||
	.asciz	"http://ipxe.org"
 | 
			
		||||
	.asciz	"https://ipxe.org"
 | 
			
		||||
	.size mfgstr, . - mfgstr
 | 
			
		||||
 | 
			
		||||
/* Product string
 | 
			
		||||
@ -607,7 +607,7 @@ get_pmm_decompress_to:
 | 
			
		||||
 * 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.
 | 
			
		||||
 * to iPXE or https://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,
 | 
			
		||||
 | 
			
		||||
@ -229,6 +229,8 @@ SECTIONS {
 | 
			
		||||
	*(.einfo.*)
 | 
			
		||||
	*(.discard)
 | 
			
		||||
	*(.discard.*)
 | 
			
		||||
	*(.sbat)
 | 
			
		||||
	*(.sbat.*)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,8 @@ SECTIONS {
 | 
			
		||||
	*(.einfo.*)
 | 
			
		||||
	*(.discard)
 | 
			
		||||
	*(.discard.*)
 | 
			
		||||
	*(.sbat)
 | 
			
		||||
	*(.sbat.*)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -100,5 +100,7 @@ SECTIONS {
 | 
			
		||||
		*(.rel.*)
 | 
			
		||||
		*(.discard)
 | 
			
		||||
		*(.discard.*)
 | 
			
		||||
		*(.sbat)
 | 
			
		||||
		*(.sbat.*)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 */
 | 
			
		||||
#define PRODUCT_NAME ""
 | 
			
		||||
#define PRODUCT_SHORT_NAME "iPXE"
 | 
			
		||||
#define PRODUCT_URI "http://ipxe.org"
 | 
			
		||||
#define PRODUCT_URI "https://ipxe.org"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Tag line
 | 
			
		||||
@ -44,15 +44,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 * (e.g. "Permission denied") and a 32-bit error number.  This number
 | 
			
		||||
 * is incorporated into an error URI such as
 | 
			
		||||
 *
 | 
			
		||||
 *   "No such file or directory (http://ipxe.org/2d0c613b)"
 | 
			
		||||
 *   "No such file or directory (https://ipxe.org/2d0c613b)"
 | 
			
		||||
 *
 | 
			
		||||
 * or
 | 
			
		||||
 *
 | 
			
		||||
 *   "Operation not supported (http://ipxe.org/3c092003)"
 | 
			
		||||
 *   "Operation not supported (https://ipxe.org/3c092003)"
 | 
			
		||||
 *
 | 
			
		||||
 * Users may browse to the URI within the error message, which is
 | 
			
		||||
 * provided by a database running on the iPXE web site
 | 
			
		||||
 * (http://ipxe.org).  This database provides details for all possible
 | 
			
		||||
 * (https://ipxe.org).  This database provides details for all possible
 | 
			
		||||
 * errors generated by iPXE, including:
 | 
			
		||||
 *
 | 
			
		||||
 * - the detailed error message (e.g. "Not an OCSP signing
 | 
			
		||||
@ -74,13 +74,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 * If you have a customer support team and would like your customers
 | 
			
		||||
 * to contact your support team for all problems, instead of using the
 | 
			
		||||
 * existing support infrastructure provided by http://ipxe.org, then
 | 
			
		||||
 * existing support infrastructure provided by https://ipxe.org, then
 | 
			
		||||
 * you may define a custom URI to be included within error messages.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that the custom URI is a printf() format string which must
 | 
			
		||||
 * include a format specifier for the 32-bit error number.
 | 
			
		||||
 */
 | 
			
		||||
#define PRODUCT_ERROR_URI "http://ipxe.org/%08x"
 | 
			
		||||
#define PRODUCT_ERROR_URI "https://ipxe.org/%08x"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Command help messages
 | 
			
		||||
@ -88,7 +88,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 * iPXE command help messages include a URI constructed from the
 | 
			
		||||
 * command name, such as
 | 
			
		||||
 *
 | 
			
		||||
 *   "See http://ipxe.org/cmd/vcreate for further information"
 | 
			
		||||
 *   "See https://ipxe.org/cmd/vcreate for further information"
 | 
			
		||||
 *
 | 
			
		||||
 * The iPXE web site includes documentation for the commands provided
 | 
			
		||||
 * by the iPXE shell, including:
 | 
			
		||||
@ -113,7 +113,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 * If you want to provide your own documentation for all of the
 | 
			
		||||
 * commands provided by the iPXE shell, rather than using the existing
 | 
			
		||||
 * support infrastructure provided by http://ipxe.org, then you may
 | 
			
		||||
 * support infrastructure provided by https://ipxe.org, then you may
 | 
			
		||||
 * define a custom URI to be included within command help messages.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that the custom URI is a printf() format string which must
 | 
			
		||||
@ -124,7 +124,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *   iPXE project and prohibit the alteration or removal of any
 | 
			
		||||
 *   references to "iPXE". ]
 | 
			
		||||
 */
 | 
			
		||||
#define PRODUCT_COMMAND_URI "http://ipxe.org/cmd/%s"
 | 
			
		||||
#define PRODUCT_COMMAND_URI "https://ipxe.org/cmd/%s"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Setting help messages
 | 
			
		||||
@ -132,7 +132,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 * iPXE setting help messages include a URI constructed from the
 | 
			
		||||
 * setting name, such as
 | 
			
		||||
 *
 | 
			
		||||
 *   "http://ipxe.org/cfg/initiator-iqn"
 | 
			
		||||
 *   "https://ipxe.org/cfg/initiator-iqn"
 | 
			
		||||
 *
 | 
			
		||||
 * The iPXE web site includes documentation for the settings used by
 | 
			
		||||
 * iPXE, including:
 | 
			
		||||
@ -156,7 +156,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *
 | 
			
		||||
 * If you want to provide your own documentation for all of the
 | 
			
		||||
 * settings used by iPXE, rather than using the existing support
 | 
			
		||||
 * infrastructure provided by http://ipxe.org, then you may define a
 | 
			
		||||
 * infrastructure provided by https://ipxe.org, then you may define a
 | 
			
		||||
 * custom URI to be included within setting help messages.
 | 
			
		||||
 *
 | 
			
		||||
 * Note that the custom URI is a printf() format string which must
 | 
			
		||||
@ -167,7 +167,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 *   iPXE project and prohibit the alteration or removal of any
 | 
			
		||||
 *   references to "iPXE". ]
 | 
			
		||||
 */
 | 
			
		||||
#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s"
 | 
			
		||||
#define PRODUCT_SETTING_URI "https://ipxe.org/cfg/%s"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Product security name suffix
 | 
			
		||||
 *
 | 
			
		||||
 * Vendors creating signed iPXE binaries must set this to a non-empty
 | 
			
		||||
 * value (e.g. "2pint").
 | 
			
		||||
 */
 | 
			
		||||
#define PRODUCT_SBAT_NAME ""
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Product security generation
 | 
			
		||||
 *
 | 
			
		||||
 * Vendors creating signed iPXE binaries must set this to a non-zero
 | 
			
		||||
 * value, and must increment the value whenever a Secure Boot exploit
 | 
			
		||||
 * is fixed (unless the upstream IPXE_SBAT_GENERATION has already been
 | 
			
		||||
 * incremented as part of that fix).
 | 
			
		||||
 */
 | 
			
		||||
#define PRODUCT_SBAT_GENERATION 0
 | 
			
		||||
 | 
			
		||||
#include <config/local/branding.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2199,7 +2199,7 @@ const struct setting_type setting_type_base64 __setting_type = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Format UUID setting value
 | 
			
		||||
 * Format UUID/GUID setting value
 | 
			
		||||
 *
 | 
			
		||||
 * @v type		Setting type
 | 
			
		||||
 * @v raw		Raw setting value
 | 
			
		||||
@ -2208,17 +2208,24 @@ const struct setting_type setting_type_base64 __setting_type = {
 | 
			
		||||
 * @v len		Length of buffer
 | 
			
		||||
 * @ret len		Length of formatted value, or negative error
 | 
			
		||||
 */
 | 
			
		||||
static int format_uuid_setting ( const struct setting_type *type __unused,
 | 
			
		||||
static int format_uuid_setting ( const struct setting_type *type,
 | 
			
		||||
				 const void *raw, size_t raw_len, char *buf,
 | 
			
		||||
				 size_t len ) {
 | 
			
		||||
	const union uuid *uuid = raw;
 | 
			
		||||
	union uuid uuid;
 | 
			
		||||
 | 
			
		||||
	/* Range check */
 | 
			
		||||
	if ( raw_len != sizeof ( *uuid ) )
 | 
			
		||||
	if ( raw_len != sizeof ( uuid ) )
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
 | 
			
		||||
	/* Copy value */
 | 
			
		||||
	memcpy ( &uuid, raw, sizeof ( uuid ) );
 | 
			
		||||
 | 
			
		||||
	/* Mangle GUID byte ordering */
 | 
			
		||||
	if ( type == &setting_type_guid )
 | 
			
		||||
		uuid_mangle ( &uuid );
 | 
			
		||||
 | 
			
		||||
	/* Format value */
 | 
			
		||||
	return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
 | 
			
		||||
	return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** UUID setting type */
 | 
			
		||||
@ -2227,6 +2234,12 @@ const struct setting_type setting_type_uuid __setting_type = {
 | 
			
		||||
	.format = format_uuid_setting,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** GUID setting type */
 | 
			
		||||
const struct setting_type setting_type_guid __setting_type = {
 | 
			
		||||
	.name = "guid",
 | 
			
		||||
	.format = format_uuid_setting,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Format PCI bus:dev.fn setting value
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
@ -334,8 +334,15 @@ struct uri * parse_uri ( const char *uri_string ) {
 | 
			
		||||
		uri->efragment = tmp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Identify absolute/relative URI */
 | 
			
		||||
	if ( ( tmp = strchr ( raw, ':' ) ) ) {
 | 
			
		||||
	/* Identify absolute URIs */
 | 
			
		||||
	epath = raw;
 | 
			
		||||
	for ( tmp = raw ; ; tmp++ ) {
 | 
			
		||||
		/* Possible scheme character (for our URI schemes) */
 | 
			
		||||
		if ( isalpha ( *tmp ) || ( *tmp == '-' ) || ( *tmp == '_' ) )
 | 
			
		||||
			continue;
 | 
			
		||||
		/* Invalid scheme character or NUL: is a relative URI */
 | 
			
		||||
		if ( *tmp != ':' )
 | 
			
		||||
			break;
 | 
			
		||||
		/* Absolute URI: identify hierarchical/opaque */
 | 
			
		||||
		uri->scheme = raw;
 | 
			
		||||
		*(tmp++) = '\0';
 | 
			
		||||
@ -347,9 +354,7 @@ struct uri * parse_uri ( const char *uri_string ) {
 | 
			
		||||
			uri->opaque = tmp;
 | 
			
		||||
			epath = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Relative URI */
 | 
			
		||||
		epath = raw;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If we don't have a path (i.e. we have an absolute URI with
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <wchar.h>
 | 
			
		||||
#include <ipxe/features.h>
 | 
			
		||||
#include <ipxe/version.h>
 | 
			
		||||
#include <ipxe/sbat.h>
 | 
			
		||||
#include <config/general.h>
 | 
			
		||||
#include <config/branding.h>
 | 
			
		||||
 | 
			
		||||
@ -92,3 +93,32 @@ const wchar_t build_wname[] = WSTRING ( BUILD_NAME );
 | 
			
		||||
/** Copy of build name string within ".prefix" */
 | 
			
		||||
const char build_name_prefix[] __attribute__ (( section ( ".prefix.name" ) ))
 | 
			
		||||
	= BUILD_NAME;
 | 
			
		||||
 | 
			
		||||
/** SBAT upstream iPXE line
 | 
			
		||||
 *
 | 
			
		||||
 * This line represents the security generation of the upstream
 | 
			
		||||
 * codebase from which this build is derived.
 | 
			
		||||
 */
 | 
			
		||||
#define SBAT_IPXE							\
 | 
			
		||||
	SBAT_LINE ( "ipxe", IPXE_SBAT_GENERATION,			\
 | 
			
		||||
		    "iPXE", BUILD_NAME, VERSION, "https://ipxe.org" )
 | 
			
		||||
 | 
			
		||||
/** SBAT local build line
 | 
			
		||||
 *
 | 
			
		||||
 * This line states the security generation of the local build, which
 | 
			
		||||
 * may include non-default features or non-upstreamed modifications.
 | 
			
		||||
 */
 | 
			
		||||
#if PRODUCT_SBAT_GENERATION
 | 
			
		||||
#define SBAT_PRODUCT							\
 | 
			
		||||
	SBAT_LINE ( "ipxe." PRODUCT_SBAT_NAME, PRODUCT_SBAT_GENERATION,	\
 | 
			
		||||
		    PRODUCT_SHORT_NAME, BUILD_NAME, VERSION,		\
 | 
			
		||||
		    PRODUCT_URI )
 | 
			
		||||
#else
 | 
			
		||||
#define SBAT_PRODUCT ""
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** SBAT data */
 | 
			
		||||
#define SBAT_DATA SBAT_HEADER "" SBAT_IPXE "" SBAT_PRODUCT
 | 
			
		||||
 | 
			
		||||
/** SBAT data (without any NUL terminator) */
 | 
			
		||||
const char sbat[ sizeof ( SBAT_DATA ) - 1 ] __sbat = SBAT_DATA;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								src/include/ipxe/sbat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/include/ipxe/sbat.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
#ifndef _IPXE_SBAT_H
 | 
			
		||||
#define _IPXE_SBAT_H
 | 
			
		||||
 | 
			
		||||
/** @file
 | 
			
		||||
 *
 | 
			
		||||
 * Secure Boot Advanced Targeting (SBAT)
 | 
			
		||||
 *
 | 
			
		||||
 * SBAT defines an encoding for security generation numbers stored as
 | 
			
		||||
 * a CSV file within a special ".sbat" section in the signed binary.
 | 
			
		||||
 * If a Secure Boot exploit is discovered then the generation number
 | 
			
		||||
 * will be incremented alongside the corresponding fix.
 | 
			
		||||
 *
 | 
			
		||||
 * Platforms may then record the minimum generation number required
 | 
			
		||||
 * for any given product.  This allows for an efficient revocation
 | 
			
		||||
 * mechanism that consumes minimal flash storage space (in contrast to
 | 
			
		||||
 * the DBX mechanism, which allows for only a single-digit number of
 | 
			
		||||
 * revocation events to ever take place across all possible signed
 | 
			
		||||
 * binaries).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A single line within an SBAT CSV file
 | 
			
		||||
 *
 | 
			
		||||
 * @v name		Machine-readable component name
 | 
			
		||||
 * @v generation	Security generation number
 | 
			
		||||
 * @v vendor		Human-readable vendor name
 | 
			
		||||
 * @v package		Human-readable package name
 | 
			
		||||
 * @v version		Human-readable package version
 | 
			
		||||
 * @v uri		Contact URI
 | 
			
		||||
 * @ret line		CSV line
 | 
			
		||||
 */
 | 
			
		||||
#define SBAT_LINE( name, generation, vendor, package, version, uri )	\
 | 
			
		||||
	name "," _S2 ( generation ) "," vendor "," package ","		\
 | 
			
		||||
	version "," uri "\n"
 | 
			
		||||
 | 
			
		||||
/** SBAT format generation */
 | 
			
		||||
#define SBAT_GENERATION 1
 | 
			
		||||
 | 
			
		||||
/** Upstream security generation
 | 
			
		||||
 *
 | 
			
		||||
 * This represents the security generation of the upstream codebase.
 | 
			
		||||
 * It will be incremented whenever a Secure Boot exploit is fixed in
 | 
			
		||||
 * the upstream codebase.
 | 
			
		||||
 *
 | 
			
		||||
 * If you do not have commit access to the upstream iPXE repository,
 | 
			
		||||
 * then you may not modify this value under any circumstances.
 | 
			
		||||
 */
 | 
			
		||||
#define IPXE_SBAT_GENERATION 1
 | 
			
		||||
 | 
			
		||||
/* Seriously, do not modify this value */
 | 
			
		||||
#if IPXE_SBAT_GENERATION != 1
 | 
			
		||||
#error "You may not modify IPXE_SBAT_GENERATION"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** SBAT header line */
 | 
			
		||||
#define SBAT_HEADER							\
 | 
			
		||||
	SBAT_LINE ( "sbat", SBAT_GENERATION, "SBAT Version", "sbat",	\
 | 
			
		||||
		    _S2 ( SBAT_GENERATION ),				\
 | 
			
		||||
		    "https://github.com/rhboot/shim/blob/main/SBAT.md" )
 | 
			
		||||
 | 
			
		||||
/** Mark variable as being in the ".sbat" section */
 | 
			
		||||
#define __sbat __attribute__ (( section ( ".sbat" ), aligned ( 512 ) ))
 | 
			
		||||
 | 
			
		||||
extern const char sbat[] __sbat;
 | 
			
		||||
 | 
			
		||||
#endif /* _IPXE_SBAT_H */
 | 
			
		||||
@ -426,6 +426,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type;
 | 
			
		||||
extern const struct setting_type setting_type_hexraw __setting_type;
 | 
			
		||||
extern const struct setting_type setting_type_base64 __setting_type;
 | 
			
		||||
extern const struct setting_type setting_type_uuid __setting_type;
 | 
			
		||||
extern const struct setting_type setting_type_guid __setting_type;
 | 
			
		||||
extern const struct setting_type setting_type_busdevfn __setting_type;
 | 
			
		||||
extern const struct setting_type setting_type_dnssl __setting_type;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -774,7 +774,7 @@ struct srp_aer_rsp {
 | 
			
		||||
 * The working draft specification for the SRP boot firmware table can
 | 
			
		||||
 * be found at
 | 
			
		||||
 *
 | 
			
		||||
 *   http://ipxe.org/wiki/srp/sbft
 | 
			
		||||
 *   https://ipxe.org/wiki/srp/sbft
 | 
			
		||||
 *
 | 
			
		||||
 *****************************************************************************
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -24,11 +24,14 @@
 | 
			
		||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <ipxe/image.h>
 | 
			
		||||
#include <ipxe/init.h>
 | 
			
		||||
#include <ipxe/in.h>
 | 
			
		||||
#include <ipxe/efi/efi.h>
 | 
			
		||||
#include <ipxe/efi/efi_autoexec.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/PxeBaseCode.h>
 | 
			
		||||
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
 | 
			
		||||
#include <ipxe/efi/Guid/FileInfo.h>
 | 
			
		||||
 | 
			
		||||
@ -39,10 +42,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/** Autoexec script filename */
 | 
			
		||||
#define AUTOEXEC_FILENAME L"autoexec.ipxe"
 | 
			
		||||
static wchar_t efi_autoexec_wname[] = L"autoexec.ipxe";
 | 
			
		||||
 | 
			
		||||
/** Autoexec script image name */
 | 
			
		||||
#define AUTOEXEC_NAME "autoexec.ipxe"
 | 
			
		||||
static char efi_autoexec_name[] = "autoexec.ipxe";
 | 
			
		||||
 | 
			
		||||
/** Autoexec script (if any) */
 | 
			
		||||
static void *efi_autoexec;
 | 
			
		||||
@ -51,21 +54,21 @@ static void *efi_autoexec;
 | 
			
		||||
static size_t efi_autoexec_len;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load autoexec script
 | 
			
		||||
 * Load autoexec script from filesystem
 | 
			
		||||
 *
 | 
			
		||||
 * @v device		Device handle
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
static int efi_autoexec_filesystem ( EFI_HANDLE device ) {
 | 
			
		||||
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
			
		||||
	static wchar_t name[] = AUTOEXEC_FILENAME;
 | 
			
		||||
	union {
 | 
			
		||||
		void *interface;
 | 
			
		||||
		EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
 | 
			
		||||
	} u;
 | 
			
		||||
	struct {
 | 
			
		||||
		EFI_FILE_INFO info;
 | 
			
		||||
		CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ];
 | 
			
		||||
		CHAR16 name[ sizeof ( efi_autoexec_wname ) /
 | 
			
		||||
			     sizeof ( efi_autoexec_wname[0] ) ];
 | 
			
		||||
	} info;
 | 
			
		||||
	EFI_FILE_PROTOCOL *root;
 | 
			
		||||
	EFI_FILE_PROTOCOL *file;
 | 
			
		||||
@ -74,10 +77,6 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	assert ( efi_autoexec == NULL );
 | 
			
		||||
	assert ( efi_autoexec_len == 0 );
 | 
			
		||||
 | 
			
		||||
	/* Open simple file system protocol */
 | 
			
		||||
	if ( ( efirc = bs->OpenProtocol ( device,
 | 
			
		||||
					  &efi_simple_file_system_protocol_guid,
 | 
			
		||||
@ -99,11 +98,12 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Open autoexec script */
 | 
			
		||||
	if ( ( efirc = root->Open ( root, &file, name,
 | 
			
		||||
	if ( ( efirc = root->Open ( root, &file, efi_autoexec_wname,
 | 
			
		||||
				    EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s has no %ls: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), name, strerror ( rc ) );
 | 
			
		||||
		       efi_handle_name ( device ), efi_autoexec_wname,
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		goto err_open;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -113,7 +113,8 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
				       &info ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s could not get %ls info: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), name, strerror ( rc ) );
 | 
			
		||||
		       efi_handle_name ( device ), efi_autoexec_wname,
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		goto err_getinfo;
 | 
			
		||||
	}
 | 
			
		||||
	size = info.info.FileSize;
 | 
			
		||||
@ -122,7 +123,7 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	if ( ! size ) {
 | 
			
		||||
		rc = -EINVAL;
 | 
			
		||||
		DBGC ( device, "EFI %s has zero-length %ls\n",
 | 
			
		||||
		       efi_handle_name ( device ), name );
 | 
			
		||||
		       efi_handle_name ( device ), efi_autoexec_wname );
 | 
			
		||||
		goto err_empty;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -131,7 +132,8 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
					  &data ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s could not allocate %ls: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), name, strerror ( rc ) );
 | 
			
		||||
		       efi_handle_name ( device ), efi_autoexec_wname,
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -139,7 +141,8 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s could not read %ls: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), name, strerror ( rc ) );
 | 
			
		||||
		       efi_handle_name ( device ), efi_autoexec_wname,
 | 
			
		||||
		       strerror ( rc ) );
 | 
			
		||||
		goto err_read;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -148,7 +151,7 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	efi_autoexec_len = size;
 | 
			
		||||
	data = NULL;
 | 
			
		||||
	DBGC ( device, "EFI %s found %ls\n",
 | 
			
		||||
	       efi_handle_name ( device ), name );
 | 
			
		||||
	       efi_handle_name ( device ), efi_autoexec_wname );
 | 
			
		||||
 | 
			
		||||
	/* Success */
 | 
			
		||||
	rc = 0;
 | 
			
		||||
@ -169,6 +172,199 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load autoexec script from TFTP server
 | 
			
		||||
 *
 | 
			
		||||
 * @v device		Device handle
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
static int efi_autoexec_tftp ( EFI_HANDLE device ) {
 | 
			
		||||
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
			
		||||
	union {
 | 
			
		||||
		void *interface;
 | 
			
		||||
		EFI_PXE_BASE_CODE_PROTOCOL *pxe;
 | 
			
		||||
	} u;
 | 
			
		||||
	EFI_PXE_BASE_CODE_MODE *mode;
 | 
			
		||||
	EFI_PXE_BASE_CODE_PACKET *packet;
 | 
			
		||||
	union {
 | 
			
		||||
		struct in_addr in;
 | 
			
		||||
		EFI_IP_ADDRESS ip;
 | 
			
		||||
	} server;
 | 
			
		||||
	size_t filename_max;
 | 
			
		||||
	char *filename;
 | 
			
		||||
	char *sep;
 | 
			
		||||
	UINT64 size;
 | 
			
		||||
	VOID *data;
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Open PXE base code protocol */
 | 
			
		||||
	if ( ( efirc = bs->OpenProtocol ( device,
 | 
			
		||||
					  &efi_pxe_base_code_protocol_guid,
 | 
			
		||||
					  &u.interface, efi_image_handle,
 | 
			
		||||
					  device,
 | 
			
		||||
					  EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s has no PXE base code instance: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), strerror ( rc ) );
 | 
			
		||||
		goto err_pxe;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Do not attempt to parse DHCPv6 packets */
 | 
			
		||||
	mode = u.pxe->Mode;
 | 
			
		||||
	if ( mode->UsingIpv6 ) {
 | 
			
		||||
		rc = -ENOTSUP;
 | 
			
		||||
		DBGC ( device, "EFI %s has IPv6 PXE base code\n",
 | 
			
		||||
		       efi_handle_name ( device ) );
 | 
			
		||||
		goto err_ipv6;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Identify relevant reply packet */
 | 
			
		||||
	if ( mode->PxeReplyReceived &&
 | 
			
		||||
	     mode->PxeReply.Dhcpv4.BootpBootFile[0] ) {
 | 
			
		||||
		/* Use boot filename if present in PXE reply */
 | 
			
		||||
		DBGC ( device, "EFI %s using PXE reply filename\n",
 | 
			
		||||
		       efi_handle_name ( device ) );
 | 
			
		||||
		packet = &mode->PxeReply;
 | 
			
		||||
	} else if ( mode->DhcpAckReceived &&
 | 
			
		||||
		    mode->DhcpAck.Dhcpv4.BootpBootFile[0] ) {
 | 
			
		||||
		/* Otherwise, use boot filename if present in DHCPACK */
 | 
			
		||||
		DBGC ( device, "EFI %s using DHCPACK filename\n",
 | 
			
		||||
		       efi_handle_name ( device ) );
 | 
			
		||||
		packet = &mode->DhcpAck;
 | 
			
		||||
	} else if ( mode->ProxyOfferReceived &&
 | 
			
		||||
		    mode->ProxyOffer.Dhcpv4.BootpBootFile[0] ) {
 | 
			
		||||
		/* Otherwise, use boot filename if present in ProxyDHCPOFFER */
 | 
			
		||||
		DBGC ( device, "EFI %s using ProxyDHCPOFFER filename\n",
 | 
			
		||||
		       efi_handle_name ( device ) );
 | 
			
		||||
		packet = &mode->ProxyOffer;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* No boot filename available */
 | 
			
		||||
		rc = -ENOENT;
 | 
			
		||||
		DBGC ( device, "EFI %s has no PXE boot filename\n",
 | 
			
		||||
		       efi_handle_name ( device ) );
 | 
			
		||||
		goto err_packet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate filename */
 | 
			
		||||
	filename_max = ( sizeof ( packet->Dhcpv4.BootpBootFile )
 | 
			
		||||
			 + ( sizeof ( efi_autoexec_name ) - 1 /* NUL */ )
 | 
			
		||||
			 + 1 /* NUL */ );
 | 
			
		||||
	filename = zalloc ( filename_max );
 | 
			
		||||
	if ( ! filename ) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto err_filename;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Extract next-server address and boot filename */
 | 
			
		||||
	memset ( &server, 0, sizeof ( server ) );
 | 
			
		||||
	memcpy ( &server.in, packet->Dhcpv4.BootpSiAddr,
 | 
			
		||||
		 sizeof ( server.in ) );
 | 
			
		||||
	memcpy ( filename, packet->Dhcpv4.BootpBootFile,
 | 
			
		||||
		 sizeof ( packet->Dhcpv4.BootpBootFile ) );
 | 
			
		||||
 | 
			
		||||
	/* Update filename to autoexec script name */
 | 
			
		||||
	sep = strrchr ( filename, '/' );
 | 
			
		||||
	if ( ! sep )
 | 
			
		||||
		sep = strrchr ( filename, '\\' );
 | 
			
		||||
	if ( ! sep )
 | 
			
		||||
		sep = ( filename - 1 );
 | 
			
		||||
	strcpy ( ( sep + 1 ), efi_autoexec_name );
 | 
			
		||||
 | 
			
		||||
	/* Get file size */
 | 
			
		||||
	if ( ( efirc = u.pxe->Mtftp ( u.pxe,
 | 
			
		||||
				      EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
 | 
			
		||||
				      NULL, FALSE, &size, NULL, &server.ip,
 | 
			
		||||
				      ( ( UINT8 * ) filename ), NULL,
 | 
			
		||||
				      FALSE ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s could not get size of %s:%s: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), inet_ntoa ( server.in ),
 | 
			
		||||
		       filename, strerror ( rc ) );
 | 
			
		||||
		goto err_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ignore zero-length files */
 | 
			
		||||
	if ( ! size ) {
 | 
			
		||||
		rc = -EINVAL;
 | 
			
		||||
		DBGC ( device, "EFI %s has zero-length %s:%s\n",
 | 
			
		||||
		       efi_handle_name ( device ), inet_ntoa ( server.in ),
 | 
			
		||||
		       filename );
 | 
			
		||||
		goto err_empty;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate temporary copy */
 | 
			
		||||
	if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size,
 | 
			
		||||
					  &data ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s could not allocate %s:%s: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), inet_ntoa ( server.in ),
 | 
			
		||||
		       filename, strerror ( rc ) );
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Download file */
 | 
			
		||||
	if ( ( efirc = u.pxe->Mtftp ( u.pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE,
 | 
			
		||||
				      data, FALSE, &size, NULL, &server.ip,
 | 
			
		||||
				      ( ( UINT8 * ) filename ), NULL,
 | 
			
		||||
				      FALSE ) ) != 0 ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( device, "EFI %s could not download %s:%s: %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), inet_ntoa ( server.in ),
 | 
			
		||||
		       filename, strerror ( rc ) );
 | 
			
		||||
		goto err_download;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Record autoexec script */
 | 
			
		||||
	efi_autoexec = data;
 | 
			
		||||
	efi_autoexec_len = size;
 | 
			
		||||
	data = NULL;
 | 
			
		||||
	DBGC ( device, "EFI %s found %s:%s\n", efi_handle_name ( device ),
 | 
			
		||||
	       inet_ntoa ( server.in ), filename );
 | 
			
		||||
 | 
			
		||||
	/* Success */
 | 
			
		||||
	rc = 0;
 | 
			
		||||
 | 
			
		||||
 err_download:
 | 
			
		||||
	if ( data )
 | 
			
		||||
		bs->FreePool ( data );
 | 
			
		||||
 err_alloc:
 | 
			
		||||
 err_empty:
 | 
			
		||||
 err_size:
 | 
			
		||||
	free ( filename );
 | 
			
		||||
 err_filename:
 | 
			
		||||
 err_packet:
 | 
			
		||||
 err_ipv6:
 | 
			
		||||
	bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid,
 | 
			
		||||
			    efi_image_handle, device );
 | 
			
		||||
 err_pxe:
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load autoexec script
 | 
			
		||||
 *
 | 
			
		||||
 * @v device		Device handle
 | 
			
		||||
 * @ret rc		Return status code
 | 
			
		||||
 */
 | 
			
		||||
int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* Sanity check */
 | 
			
		||||
	assert ( efi_autoexec == NULL );
 | 
			
		||||
	assert ( efi_autoexec_len == 0 );
 | 
			
		||||
 | 
			
		||||
	/* Try loading from file system, if supported */
 | 
			
		||||
	if ( ( rc = efi_autoexec_filesystem ( device ) ) == 0 )
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Try loading via TFTP, if supported */
 | 
			
		||||
	if ( ( rc = efi_autoexec_tftp ( device ) ) == 0 )
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return -ENOENT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Register autoexec script
 | 
			
		||||
 *
 | 
			
		||||
@ -176,7 +372,6 @@ int efi_autoexec_load ( EFI_HANDLE device ) {
 | 
			
		||||
static void efi_autoexec_startup ( void ) {
 | 
			
		||||
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
			
		||||
	EFI_HANDLE device = efi_loaded_image->DeviceHandle;
 | 
			
		||||
	const char *name = AUTOEXEC_NAME;
 | 
			
		||||
	struct image *image;
 | 
			
		||||
 | 
			
		||||
	/* Do nothing if we have no autoexec script */
 | 
			
		||||
@ -184,15 +379,16 @@ static void efi_autoexec_startup ( void ) {
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Create autoexec image */
 | 
			
		||||
	image = image_memory ( name, virt_to_user ( efi_autoexec ),
 | 
			
		||||
	image = image_memory ( efi_autoexec_name,
 | 
			
		||||
			       virt_to_user ( efi_autoexec ),
 | 
			
		||||
			       efi_autoexec_len );
 | 
			
		||||
	if ( ! image ) {
 | 
			
		||||
		DBGC ( device, "EFI %s could not create %s\n",
 | 
			
		||||
		       efi_handle_name ( device ), name );
 | 
			
		||||
		       efi_handle_name ( device ), efi_autoexec_name );
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	DBGC ( device, "EFI %s registered %s\n",
 | 
			
		||||
	       efi_handle_name ( device ), name );
 | 
			
		||||
	       efi_handle_name ( device ), efi_autoexec_name );
 | 
			
		||||
 | 
			
		||||
	/* Free temporary copy */
 | 
			
		||||
	bs->FreePool ( efi_autoexec );
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <ipxe/retry.h>
 | 
			
		||||
#include <ipxe/timer.h>
 | 
			
		||||
#include <ipxe/init.h>
 | 
			
		||||
#include <ipxe/efi/efi.h>
 | 
			
		||||
#include <ipxe/efi/efi_watchdog.h>
 | 
			
		||||
 | 
			
		||||
@ -80,3 +81,36 @@ static void efi_watchdog_expired ( struct retry_timer *timer,
 | 
			
		||||
 | 
			
		||||
/** Watchdog holdoff timer */
 | 
			
		||||
struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Disable watching when shutting down to boot an operating system
 | 
			
		||||
 *
 | 
			
		||||
 * @v booting		System is shutting down for OS boot
 | 
			
		||||
 */
 | 
			
		||||
static void efi_watchdog_shutdown ( int booting ) {
 | 
			
		||||
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
			
		||||
	EFI_STATUS efirc;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	/* If we are shutting down to boot an operating system, then
 | 
			
		||||
	 * disable the boot services watchdog timer.  The UEFI
 | 
			
		||||
	 * specification mandates that the platform firmware does this
 | 
			
		||||
	 * as part of the ExitBootServices() call, but some platforms
 | 
			
		||||
	 * (e.g. Hyper-V) are observed to occasionally forget to do
 | 
			
		||||
	 * so, resulting in a reboot approximately five minutes after
 | 
			
		||||
	 * starting the operating system.
 | 
			
		||||
	 */
 | 
			
		||||
	if ( booting &&
 | 
			
		||||
	     ( ( efirc = bs->SetWatchdogTimer ( 0, 0, 0, NULL ) ) != 0 ) ) {
 | 
			
		||||
		rc = -EEFI ( efirc );
 | 
			
		||||
		DBGC ( &efi_watchdog, "EFI could not disable watchdog timer: "
 | 
			
		||||
		       "%s\n", strerror ( rc ) );
 | 
			
		||||
		/* Nothing we can do */
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Watchdog startup/shutdown function */
 | 
			
		||||
struct startup_fn efi_watchdog_startup_fn __startup_fn ( STARTUP_EARLY ) = {
 | 
			
		||||
	.name = "efi_watchdog",
 | 
			
		||||
	.shutdown = efi_watchdog_shutdown,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -140,7 +140,8 @@ static int smbios_fetch ( struct settings *settings __unused,
 | 
			
		||||
		 * is 2.6 or higher; we match this behaviour.
 | 
			
		||||
		 */
 | 
			
		||||
		raw = &buf[tag_offset];
 | 
			
		||||
		if ( ( setting->type == &setting_type_uuid ) &&
 | 
			
		||||
		if ( ( ( setting->type == &setting_type_uuid ) ||
 | 
			
		||||
		       ( setting->type == &setting_type_guid ) ) &&
 | 
			
		||||
		     ( tag_len == sizeof ( uuid ) ) &&
 | 
			
		||||
		     ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) {
 | 
			
		||||
			DBG ( "SMBIOS detected mangled UUID\n" );
 | 
			
		||||
 | 
			
		||||
@ -74,6 +74,19 @@ SECTIONS {
 | 
			
		||||
	_ebss = .;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * The SBAT section
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    . = ALIGN ( _page_align );
 | 
			
		||||
    .sbat : {
 | 
			
		||||
	_sbat = .;
 | 
			
		||||
	KEEP(*(.sbat))
 | 
			
		||||
	KEEP(*(.sbat.*))
 | 
			
		||||
	_esbat = .;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Weak symbols that need zero values if not otherwise defined
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -250,6 +250,12 @@ static struct setting test_uuid_setting = {
 | 
			
		||||
	.type = &setting_type_uuid,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Test GUID setting type */
 | 
			
		||||
static struct setting test_guid_setting = {
 | 
			
		||||
	.name = "test_guid",
 | 
			
		||||
	.type = &setting_type_guid,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Test PCI bus:dev.fn setting type */
 | 
			
		||||
static struct setting test_busdevfn_setting = {
 | 
			
		||||
	.name = "test_busdevfn",
 | 
			
		||||
@ -419,6 +425,10 @@ static void settings_test_exec ( void ) {
 | 
			
		||||
		    RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8,
 | 
			
		||||
			  0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ),
 | 
			
		||||
		    "1a6a749d-0eda-461a-a87a-7cfe4fca4a57" );
 | 
			
		||||
	fetchf_ok ( &test_settings, &test_guid_setting,
 | 
			
		||||
		    RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8,
 | 
			
		||||
			  0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ),
 | 
			
		||||
		    "9d746a1a-da0e-1a46-a87a-7cfe4fca4a57" );
 | 
			
		||||
 | 
			
		||||
	/* "busdevfn" setting type (no store capability) */
 | 
			
		||||
	fetchf_ok ( &test_settings, &test_busdevfn_setting,
 | 
			
		||||
 | 
			
		||||
@ -657,6 +657,15 @@ static struct uri_test uri_file_volume = {
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Relative URI with colons in path */
 | 
			
		||||
static struct uri_test uri_colons = {
 | 
			
		||||
	"/boot/52:54:00:12:34:56/boot.ipxe",
 | 
			
		||||
	{
 | 
			
		||||
		.path = "/boot/52:54:00:12:34:56/boot.ipxe",
 | 
			
		||||
		.epath = "/boot/52:54:00:12:34:56/boot.ipxe",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** URI with port number */
 | 
			
		||||
static struct uri_port_test uri_explicit_port = {
 | 
			
		||||
	"http://192.168.0.1:8080/boot.php",
 | 
			
		||||
@ -957,6 +966,7 @@ static void uri_test_exec ( void ) {
 | 
			
		||||
	uri_parse_format_dup_ok ( &uri_file_relative );
 | 
			
		||||
	uri_parse_format_dup_ok ( &uri_file_absolute );
 | 
			
		||||
	uri_parse_format_dup_ok ( &uri_file_volume );
 | 
			
		||||
	uri_parse_format_dup_ok ( &uri_colons );
 | 
			
		||||
 | 
			
		||||
	/** URI port number tests */
 | 
			
		||||
	uri_port_ok ( &uri_explicit_port );
 | 
			
		||||
 | 
			
		||||
@ -579,8 +579,8 @@ int ipxe ( struct net_device *netdev ) {
 | 
			
		||||
	 * defining the string PRODUCT_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.
 | 
			
		||||
	 * references to iPXE or https://ipxe.org, we prefer you not
 | 
			
		||||
	 * to do so.
 | 
			
		||||
	 *
 | 
			
		||||
	 */
 | 
			
		||||
	printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD PRODUCT_SHORT_NAME " %s"
 | 
			
		||||
 | 
			
		||||
@ -753,15 +753,13 @@ static struct pe_section *
 | 
			
		||||
create_reloc_section ( struct pe_header *pe_header,
 | 
			
		||||
		       struct pe_relocs *pe_reltab ) {
 | 
			
		||||
	struct pe_section *reloc;
 | 
			
		||||
	size_t section_rawsz;
 | 
			
		||||
	size_t section_memsz;
 | 
			
		||||
	size_t section_filesz;
 | 
			
		||||
	EFI_IMAGE_DATA_DIRECTORY *relocdir;
 | 
			
		||||
 | 
			
		||||
	/* Allocate PE section */
 | 
			
		||||
	section_rawsz = output_pe_reltab ( pe_reltab, NULL );
 | 
			
		||||
	section_filesz = efi_file_align ( section_rawsz );
 | 
			
		||||
	section_memsz = efi_image_align ( section_rawsz );
 | 
			
		||||
	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 );
 | 
			
		||||
 | 
			
		||||
@ -782,11 +780,12 @@ create_reloc_section ( struct pe_header *pe_header,
 | 
			
		||||
	/* Update file header details */
 | 
			
		||||
	pe_header->nt.FileHeader.NumberOfSections++;
 | 
			
		||||
	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr );
 | 
			
		||||
	pe_header->nt.OptionalHeader.SizeOfImage += section_memsz;
 | 
			
		||||
	pe_header->nt.OptionalHeader.SizeOfImage +=
 | 
			
		||||
		efi_image_align ( section_memsz );
 | 
			
		||||
	relocdir = &(pe_header->nt.OptionalHeader.DataDirectory
 | 
			
		||||
		     [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]);
 | 
			
		||||
	relocdir->VirtualAddress = reloc->hdr.VirtualAddress;
 | 
			
		||||
	relocdir->Size = section_rawsz;
 | 
			
		||||
	relocdir->Size = section_memsz;
 | 
			
		||||
 | 
			
		||||
	return reloc;
 | 
			
		||||
}
 | 
			
		||||
@ -824,8 +823,8 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) {
 | 
			
		||||
	} *contents;
 | 
			
		||||
 | 
			
		||||
	/* Allocate PE section */
 | 
			
		||||
	section_memsz = efi_image_align ( sizeof ( *contents ) );
 | 
			
		||||
	section_filesz = efi_file_align ( sizeof ( *contents ) );
 | 
			
		||||
	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;
 | 
			
		||||
@ -857,7 +856,8 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) {
 | 
			
		||||
	/* Update file header details */
 | 
			
		||||
	pe_header->nt.FileHeader.NumberOfSections++;
 | 
			
		||||
	pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr );
 | 
			
		||||
	pe_header->nt.OptionalHeader.SizeOfImage += section_memsz;
 | 
			
		||||
	pe_header->nt.OptionalHeader.SizeOfImage +=
 | 
			
		||||
		efi_image_align ( section_memsz );
 | 
			
		||||
	debugdir = &(pe_header->nt.OptionalHeader.DataDirectory
 | 
			
		||||
		     [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
 | 
			
		||||
	debugdir->VirtualAddress = debug->hdr.VirtualAddress;
 | 
			
		||||
 | 
			
		||||
@ -565,7 +565,7 @@ EOM
 | 
			
		||||
    return join("\n", @output);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Output NIC list in DokuWiki format (for http://ipxe.org)
 | 
			
		||||
# Output NIC list in DokuWiki format (for https://ipxe.org)
 | 
			
		||||
sub format_nic_list_dokuwiki {
 | 
			
		||||
    my ($nic_list, $column_names) = @_;
 | 
			
		||||
    my @output;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user