diff options
author | Yonghee Han <onstudy@samsung.com> | 2016-07-27 16:39:12 +0900 |
---|---|---|
committer | Yonghee Han <onstudy@samsung.com> | 2016-07-27 16:47:03 +0900 |
commit | a3b133b0ea0696e42fd876b9a803e28bc6ef5299 (patch) | |
tree | 68d7537fb9ede28b2e4d2b9f44eb70988279b8ba /roms/ipxe | |
parent | 0d6a2f7e595218b5632ba7005128470e65138951 (diff) | |
download | qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.tar.gz qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.tar.bz2 qemu-a3b133b0ea0696e42fd876b9a803e28bc6ef5299.zip |
Imported Upstream version 2.3.1upstream/2.3.1
Change-Id: I2161522ea1d7ff10cd1d697609d473243c05e1df
Diffstat (limited to 'roms/ipxe')
224 files changed, 26319 insertions, 2145 deletions
diff --git a/roms/ipxe/src/Makefile b/roms/ipxe/src/Makefile index ea987b84c..b742d1283 100644 --- a/roms/ipxe/src/Makefile +++ b/roms/ipxe/src/Makefile @@ -46,6 +46,7 @@ ZBIN := ./util/zbin ELF2EFI32 := ./util/elf2efi32 ELF2EFI64 := ./util/elf2efi64 EFIROM := ./util/efirom +EFIFATBIN := ./util/efifatbin ICCFIX := ./util/iccfix EINFO := ./util/einfo GENKEYMAP := ./util/genkeymap.pl @@ -84,6 +85,7 @@ SRCDIRS += drivers/bitbash SRCDIRS += drivers/infiniband SRCDIRS += interface/pxe interface/efi interface/smbios SRCDIRS += interface/bofm +SRCDIRS += interface/xen SRCDIRS += tests SRCDIRS += crypto crypto/axtls crypto/matrixssl SRCDIRS += hci hci/commands hci/tui @@ -96,6 +98,7 @@ SRCDIRS += config # automatic build system. # NON_AUTO_SRCS := +NON_AUTO_SRCS += core/version.c NON_AUTO_SRCS += drivers/net/prism2.c # INCDIRS lists the include path @@ -145,6 +148,7 @@ all : $(ALL) # everything : $(Q)$(MAKE) --no-print-directory $(ALL) \ + bin/3c509.rom bin/intel.rom bin/intel.mrom \ bin-i386-efi/ipxe.efi bin-i386-efi/ipxe.efidrv \ bin-i386-efi/ipxe.efirom \ bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \ @@ -189,8 +193,8 @@ VERSION_PATCH = 0 EXTRAVERSION = + MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION) +ifneq ($(wildcard ../.git),) GITVERSION := $(shell git describe --always --abbrev=1 --match "" 2>/dev/null) -ifneq ($(GITVERSION),) VERSION += ($(GITVERSION)) endif version : diff --git a/roms/ipxe/src/Makefile.housekeeping b/roms/ipxe/src/Makefile.housekeeping index e240a7386..1a75d3939 100644 --- a/roms/ipxe/src/Makefile.housekeeping +++ b/roms/ipxe/src/Makefile.housekeeping @@ -229,7 +229,7 @@ endif # Determine how many different BIN directories are mentioned in the # make goals. # -BIN_GOALS := $(filter bin/% bin-%,$(MAKECMDGOALS)) +BIN_GOALS := $(filter bin bin/% bin-%,$(MAKECMDGOALS)) BIN_GOALS_BINS := $(sort $(foreach BG,$(BIN_GOALS),\ $(firstword $(subst /, ,$(BG))))) NUM_BINS := $(words $(BIN_GOALS_BINS)) @@ -689,6 +689,36 @@ 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 + # 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. @@ -697,17 +727,31 @@ $(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) -# Version number +# Debug message autocolourisation range # -CFLAGS_version += -DVERSION_MAJOR=$(VERSION_MAJOR) \ - -DVERSION_MINOR=$(VERSION_MINOR) \ - -DVERSION_PATCH=$(VERSION_PATCH) \ - -DVERSION="\"$(VERSION)\"" -# Make sure the version number gets updated on every git checkout -ifneq ($(GITVERSION),) -$(BIN)/version.% : ../.git/index +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 := $(word 1,$(DBGCOL_COLOURS)) +DBGCOL_MAX := $(word 2,$(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 @@ -856,28 +900,29 @@ $(BIN)/NIC : $(AUTO_DEPS) @perl -ne 'chomp; print "$$1\n" if /\# NIC\t(.*)$$/' $^ >> $@ CLEANUP += $(BIN)/NIC # Doesn't match the $(BIN)/*.* pattern -# Analyse a target name (e.g. "bin/dfe538--prism2_pci.zrom.tmp") and +# 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. "zrom") +# 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_MEDIA : the media type (e.g. "rom") # DRIVERS_ipxe = $(DRIVERS) CARD_DRIVER = $(firstword $(DRIVER_$(1)) $(1)) TGT_ELEMENTS = $(subst --, ,$(firstword $(subst ., ,$(notdir $@)))) -TGT_PREFIX = $(word 2,$(subst ., ,$(notdir $@))) TGT_ROM_NAME = $(firstword $(TGT_ELEMENTS)) TGT_DRIVERS = $(strip $(if $(DRIVERS_$(TGT_ROM_NAME)), \ $(DRIVERS_$(TGT_ROM_NAME)), \ $(foreach TGT_ELEMENT,$(TGT_ELEMENTS), \ $(call CARD_DRIVER,$(TGT_ELEMENT))) )) -TGT_MEDIA = $(subst z,,$(TGT_PREFIX)) +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.zrom.tmp") and derive the variables: +# (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") @@ -886,7 +931,7 @@ 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.zrom.tmp") and derive the variables: +# (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") @@ -899,7 +944,7 @@ TGT_LD_IDS = pci_vendor_id=$(firstword $(TGT_PCI_VENDOR) 0) \ 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.zrom.tmp") and derive the +# 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. @@ -930,7 +975,6 @@ $(BIN)/%.info : @$(ECHO) 'Prefix : $(TGT_PREFIX)' @$(ECHO) 'Drivers : $(TGT_DRIVERS)' @$(ECHO) 'ROM name : $(TGT_ROM_NAME)' - @$(ECHO) 'Media : $(TGT_MEDIA)' @$(ECHO) @$(ECHO) 'PCI vendor : $(TGT_PCI_VENDOR)' @$(ECHO) 'PCI device : $(TGT_PCI_DEVICE)' @@ -977,13 +1021,31 @@ blib : $(BLIB) # 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 : $(BLIB) $(MAKEDEPS) $(LDSCRIPT) +$(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)` -Map $(BIN)/$*.tmp.map + $(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) @@ -1206,6 +1268,11 @@ $(EFIROM) : util/efirom.c $(MAKEDEPS) $(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 @@ -1228,8 +1295,27 @@ CLEANUP += $(EINFO) # # Local configs # -config/local/%.h : - $(Q)touch $@ +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 ############################################################################### # @@ -1358,6 +1444,13 @@ hci/keymap/keymap_%.c : # # Clean-up # + +ifeq ($(NUM_BINS),0) +ALLBINS := bin{,-*} +CLEANUP := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(CLEANUP)) +VERYCLEANUP := $(patsubst $(BIN)/%,$(ALLBINS)/%,$(VERYCLEANUP)) +endif + clean : $(RM) $(CLEANUP) diff --git a/roms/ipxe/src/arch/i386/Makefile b/roms/ipxe/src/arch/i386/Makefile index d1b885c87..4925cc4e6 100644 --- a/roms/ipxe/src/arch/i386/Makefile +++ b/roms/ipxe/src/arch/i386/Makefile @@ -82,7 +82,8 @@ ISOLINUX_BIN_LIST := \ /usr/share/syslinux/isolinux.bin \ /usr/share/syslinux/bios/isolinux.bin \ /usr/local/share/syslinux/isolinux.bin \ - /usr/local/share/syslinux/bios/isolinux.bin + /usr/local/share/syslinux/bios/isolinux.bin \ + /usr/lib/ISOLINUX/isolinux.bin ISOLINUX_BIN = $(firstword $(wildcard $(ISOLINUX_BIN_LIST))) # i386-specific directories containing source files diff --git a/roms/ipxe/src/arch/i386/Makefile.efi b/roms/ipxe/src/arch/i386/Makefile.efi index 8d651b04d..aa809eb5d 100644 --- a/roms/ipxe/src/arch/i386/Makefile.efi +++ b/roms/ipxe/src/arch/i386/Makefile.efi @@ -4,6 +4,10 @@ # ELF2EFI = $(ELF2EFI32) +# Use EFI ABI +# +CFLAGS += -malign-double + # Include generic EFI Makefile # MAKEDEPS += arch/x86/Makefile.efi diff --git a/roms/ipxe/src/arch/i386/Makefile.pcbios b/roms/ipxe/src/arch/i386/Makefile.pcbios index d3fe8b9e6..ff823737d 100644 --- a/roms/ipxe/src/arch/i386/Makefile.pcbios +++ b/roms/ipxe/src/arch/i386/Makefile.pcbios @@ -16,6 +16,8 @@ SRCDIRS += arch/i386/drivers/net # MEDIA += rom MEDIA += mrom +MEDIA += pcirom +MEDIA += isarom MEDIA += pxe MEDIA += kpxe MEDIA += kkpxe @@ -31,6 +33,8 @@ MEDIA += exe # PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff PAD_mrom = $(PAD_rom) +PAD_pcirom = $(PAD_rom) +PAD_isarom = $(PAD_rom) PAD_dsk = $(PERL) $(PADIMG) --blksize=512 PAD_hd = $(PERL) $(PADIMG) --blksize=32768 PAD_exe = $(PERL) $(PADIMG) --blksize=512 @@ -39,23 +43,27 @@ PAD_exe = $(PERL) $(PADIMG) --blksize=512 # FINALISE_rom = $(PERL) $(FIXROM) FINALISE_mrom = $(FINALISE_rom) +FINALISE_pcirom = $(FINALISE_rom) +FINALISE_isarom = $(FINALISE_rom) -# Use $(ROMS) rather than $(DRIVERS) for "allroms" and "allmroms" +# Use $(ROMS) rather than $(DRIVERS) for "allroms", "allmroms", etc. # LIST_NAME_rom := ROMS LIST_NAME_mrom := ROMS +LIST_NAME_pcirom := ROMS +LIST_NAME_isarom := ROMS # rule to make a non-emulation ISO boot image NON_AUTO_MEDIA += iso %iso: %lkrn util/geniso $(QM)$(ECHO) " [GENISO] $@" - $(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) bash util/geniso $@ $< + $(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) VERSION="$(VERSION)" bash util/geniso -o $@ $< # rule to make a floppy emulation ISO boot image NON_AUTO_MEDIA += liso -%liso: %lkrn util/genliso - $(QM)$(ECHO) " [GENLISO] $@" - $(Q)bash util/genliso $@ $< +%liso: %lkrn util/geniso + $(QM)$(ECHO) " [GENISO] $@" + $(Q)VERSION="$(VERSION)" bash util/geniso -l -o $@ $< # rule to make a syslinux floppy image (mountable, bootable) NON_AUTO_MEDIA += sdsk diff --git a/roms/ipxe/src/arch/i386/core/pci_autoboot.c b/roms/ipxe/src/arch/i386/core/pci_autoboot.c index 5e6197e2e..a3eb1f97d 100644 --- a/roms/ipxe/src/arch/i386/core/pci_autoboot.c +++ b/roms/ipxe/src/arch/i386/core/pci_autoboot.c @@ -34,10 +34,8 @@ uint16_t __bss16 ( autoboot_busdevfn ); */ static void pci_autoboot_init ( void ) { - if ( autoboot_busdevfn ) { - autoboot_device.bus_type = BUS_TYPE_PCI; - autoboot_device.location = autoboot_busdevfn; - } + if ( autoboot_busdevfn ) + set_autoboot_busloc ( BUS_TYPE_PCI, autoboot_busdevfn ); } /** PCI autoboot device initialisation function */ diff --git a/roms/ipxe/src/arch/i386/drivers/net/undinet.c b/roms/ipxe/src/arch/i386/drivers/net/undinet.c index 82dd8d2f9..6450665ff 100644 --- a/roms/ipxe/src/arch/i386/drivers/net/undinet.c +++ b/roms/ipxe/src/arch/i386/drivers/net/undinet.c @@ -72,8 +72,8 @@ struct undi_nic { /** Delay between retries of PXENV_UNDI_INITIALIZE */ #define UNDI_INITIALIZE_RETRY_DELAY_MS 200 -/** Maximum number of calls to PXENV_UNDI_ISR per poll */ -#define UNDI_POLL_QUOTA 4 +/** Maximum number of received packets per poll */ +#define UNDI_RX_QUOTA 4 /** Alignment of received frame payload */ #define UNDI_RX_ALIGN 16 @@ -331,7 +331,7 @@ static void undinet_poll ( struct net_device *netdev ) { struct undi_nic *undinic = netdev->priv; struct s_PXENV_UNDI_ISR undi_isr; struct io_buffer *iobuf = NULL; - unsigned int quota = UNDI_POLL_QUOTA; + unsigned int quota = UNDI_RX_QUOTA; size_t len; size_t reserve_len; size_t frag_len; @@ -370,7 +370,7 @@ static void undinet_poll ( struct net_device *netdev ) { } /* Run through the ISR loop */ - while ( quota-- ) { + while ( quota ) { profile_start ( &undinet_isr_call_profiler ); if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR, &undi_isr, @@ -424,6 +424,7 @@ static void undinet_poll ( struct net_device *netdev ) { if ( iob_len ( iobuf ) == len ) { /* Whole packet received; deliver it */ netdev_rx ( netdev, iob_disown ( iobuf ) ); + quota--; /* Etherboot 5.4 fails to return all packets * under mild load; pretend it retriggered. */ diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c index b2b7bf2d8..bd73838b5 100644 --- a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c +++ b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <assert.h> #include <realmode.h> +#include <bios.h> #include <ipxe/console.h> #include <ipxe/ansiesc.h> #include <ipxe/keymap.h> @@ -148,11 +149,53 @@ static void bios_handle_sgr ( struct ansiesc_context *ctx __unused, } } +/** + * Handle ANSI DECTCEM set (show cursor) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void bios_handle_dectcem_set ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, + int params[] __unused ) { + uint8_t height; + + /* Get character height */ + get_real ( height, BDA_SEG, BDA_CHAR_HEIGHT ); + + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "int $0x10\n\t" + "cli\n\t" ) + : : "a" ( 0x0100 ), + "c" ( ( ( height - 2 ) << 8 ) | + ( height - 1 ) ) ); +} + +/** + * Handle ANSI DECTCEM reset (hide cursor) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void bios_handle_dectcem_reset ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, + int params[] __unused ) { + + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "int $0x10\n\t" + "cli\n\t" ) + : : "a" ( 0x0100 ), "c" ( 0x2000 ) ); +} + /** BIOS console ANSI escape sequence handlers */ static struct ansiesc_handler bios_ansiesc_handlers[] = { { ANSIESC_CUP, bios_handle_cup }, { ANSIESC_ED, bios_handle_ed }, { ANSIESC_SGR, bios_handle_sgr }, + { ANSIESC_DECTCEM_SET, bios_handle_dectcem_set }, + { ANSIESC_DECTCEM_RESET, bios_handle_dectcem_reset }, { 0, NULL } }; diff --git a/roms/ipxe/src/arch/i386/include/bios.h b/roms/ipxe/src/arch/i386/include/bios.h index 3e6a845e3..0754b1168 100644 --- a/roms/ipxe/src/arch/i386/include/bios.h +++ b/roms/ipxe/src/arch/i386/include/bios.h @@ -9,5 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define BDA_REBOOT 0x0072 #define BDA_REBOOT_WARM 0x1234 #define BDA_NUM_DRIVES 0x0075 +#define BDA_CHAR_HEIGHT 0x0085 #endif /* BIOS_H */ diff --git a/roms/ipxe/src/arch/i386/include/ipxe/msr.h b/roms/ipxe/src/arch/i386/include/ipxe/msr.h new file mode 100644 index 000000000..c88e26a39 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/ipxe/msr.h @@ -0,0 +1,38 @@ +#ifndef _IPXE_MSR_H +#define _IPXE_MSR_H + +/** @file + * + * Model-specific registers + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Read model-specific register + * + * @v msr Model-specific register + * @ret value Value + */ +static inline __attribute__ (( always_inline )) uint64_t +rdmsr ( unsigned int msr ) { + uint64_t value; + + __asm__ __volatile__ ( "rdmsr" : "=A" ( value ) : "c" ( msr ) ); + return value; +} + +/** + * Write model-specific register + * + * @v msr Model-specific register + * @v value Value + */ +static inline __attribute__ (( always_inline )) void +wrmsr ( unsigned int msr, uint64_t value ) { + + __asm__ __volatile__ ( "wrmsr" : : "c" ( msr ), "A" ( value ) ); +} + +#endif /* _IPXE_MSR_H */ diff --git a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c index 744c7b6dd..0b6be9a03 100644 --- a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c +++ b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c @@ -240,12 +240,12 @@ int pxeparent_call ( SEGOFF16_t entry, unsigned int function, "D" ( __from_data16 ( &pxeparent_params ) ) : "ecx", "esi" ); profile_stop ( &profiler->total ); - profile_start_at ( &profiler->p2r, profiler->total.started ); + profile_start_at ( &profiler->p2r, profile_started ( &profiler->total)); profile_stop_at ( &profiler->p2r, started ); profile_start_at ( &profiler->ext, started ); profile_stop_at ( &profiler->ext, stopped ); profile_start_at ( &profiler->r2p, stopped ); - profile_stop_at ( &profiler->r2p, profiler->total.stopped ); + profile_stop_at ( &profiler->r2p, profile_stopped ( &profiler->total )); /* Determine return status code based on PXENV_EXIT and * PXENV_STATUS diff --git a/roms/ipxe/src/arch/i386/prefix/isaromprefix.S b/roms/ipxe/src/arch/i386/prefix/isaromprefix.S new file mode 100644 index 000000000..e28208089 --- /dev/null +++ b/roms/ipxe/src/arch/i386/prefix/isaromprefix.S @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 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. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define BUSTYPE "ISAR" +#define _rom_start _isarom_start +#include "romprefix.S" diff --git a/roms/ipxe/src/arch/i386/prefix/libprefix.S b/roms/ipxe/src/arch/i386/prefix/libprefix.S index 3aee415f5..7c1ece791 100644 --- a/roms/ipxe/src/arch/i386/prefix/libprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/libprefix.S @@ -95,6 +95,29 @@ print_character: .size print_character, . - print_character /***************************************************************************** + * Utility function: print space + * + * Parameters: + * %ds:di : output buffer (or %di=0 to print to console) + * Returns: + * %ds:di : next character in output buffer (if applicable) + ***************************************************************************** + */ + .section ".prefix.lib", "awx", @progbits + .code16 + .globl print_space +print_space: + /* Preserve registers */ + pushw %ax + /* Print space */ + movb $( ' ' ), %al + call print_character + /* Restore registers and return */ + popw %ax + ret + .size print_space, . - print_space + +/***************************************************************************** * Utility function: print a NUL-terminated string * * Parameters: @@ -231,12 +254,10 @@ print_kill_line: movb $( '\r' ), %al call print_character /* Print 79 spaces */ - movb $( ' ' ), %al movw $79, %cx -1: call print_character +1: call print_space loop 1b /* Print CR */ - movb $( '\r' ), %al call print_character /* Restore registers and return */ popw %cx @@ -725,9 +746,15 @@ a20_death_message: xorw %di, %di movl %esi, %eax call print_hex_dword + call print_space + movl %ecx, %eax + call print_hex_dword movw $payload_death_message, %si call print_message -2: jmp 2b +2: /* Halt system */ + cli + hlt + jmp 2b .section ".prefix.data", "aw", @progbits payload_death_message: .asciz "\nPayload inaccessible - cannot continue\n" diff --git a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S index 624f9b0ad..259bc6ba5 100644 --- a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S @@ -1,123 +1,58 @@ -/* - Copyright (C) 2000, Entity Cyber, Inc. - - Authors: Gary Byers (gb@thinguin.org) - Marty Connor (mdc@thinguin.org) - - This software may be used and distributed according to the terms - of the GNU Public License (GPL), incorporated herein by reference. - - Description: - - This is just a little bit of code and data that can get prepended - to a ROM image in order to allow bootloaders to load the result - as if it were a Linux kernel image. - - A real Linux kernel image consists of a one-sector boot loader - (to load the image from a floppy disk), followed a few sectors - of setup code, followed by the kernel code itself. There's - a table in the first sector (starting at offset 497) that indicates - how many sectors of setup code follow the first sector and which - contains some other parameters that aren't interesting in this - case. - - When a bootloader loads the sectors that comprise a kernel image, - it doesn't execute the code in the first sector (since that code - would try to load the image from a floppy disk.) The code in the - first sector below doesn't expect to get executed (and prints an - error message if it ever -is- executed.) - - We don't require much in the way of setup code. Historically, the - Linux kernel required at least 4 sectors of setup code. - Therefore, at least 4 sectors must be present even though we don't - use them. - -*/ - FILE_LICENCE ( GPL_ANY ) -#define SETUPSECS 4 /* Minimal nr of setup-sectors */ -#define PREFIXSIZE ((SETUPSECS+1)*512) -#define PREFIXPGH (PREFIXSIZE / 16 ) -#define BOOTSEG 0x07C0 /* original address of boot-sector */ -#define INITSEG 0x9000 /* we move boot here - out of the way */ -#define SETUPSEG 0x9020 /* setup starts here */ -#define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */ +#define BZI_LOAD_HIGH_ADDR 0x100000 .text - .code16 .arch i386 - .org 0 + .code16 .section ".prefix", "ax", @progbits .globl _lkrn_start _lkrn_start: -/* - This is a minimal boot sector. If anyone tries to execute it (e.g., if - a .lilo file is dd'ed to a floppy), print an error message. -*/ - -bootsector: - jmp $BOOTSEG, $1f /* reload cs:ip to match relocation addr */ -1: - movw $0x2000, %di /* 0x2000 is arbitrary value >= length - of bootsect + room for stack */ - - movw $BOOTSEG, %ax - movw %ax,%ds - movw %ax,%es - - cli - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */ - movw %di,%sp - sti - - movw $why_end-why, %cx - movw $why, %si - - movw $0x0007, %bx /* page 0, attribute 7 (normal) */ - movb $0x0e, %ah /* write char, tty mode */ -prloop: - lodsb - int $0x10 - loop prloop -freeze: jmp freeze - -why: .ascii "This image cannot be loaded from a floppy disk.\r\n" -why_end: +/***************************************************************************** + * + * Kernel header + * + * We place our prefix (i.e. our .prefix and .text16.early sections) + * within the bzImage real-mode portion which gets loaded at + * 1000:0000, and our payload (i.e. everything else) within the + * bzImage protected-mode portion which gets loaded at 0x100000 + * upwards. + * + */ -/* - The following header is documented in the Linux source code at - Documentation/x86/boot.txt -*/ - .org 497 -setup_sects: - .byte SETUPSECS -root_flags: + .org 0x1f1 +setup_sects: + .byte -1 /* Allow for initial "boot sector" */ + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ + .ascii "ADHL" + .long setup_sects + .long 512 + .long 0 + .previous +root_flags: .word 0 -syssize: - .long -PREFIXPGH - +syssize: + .long 0 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "ADDL" + .ascii "ADPL" .long syssize .long 16 .long 0 .previous - -ram_size: +ram_size: .word 0 -vid_mode: +vid_mode: .word 0 -root_dev: +root_dev: .word 0 -boot_flag: - .word 0xAA55 +boot_flag: + .word 0xaa55 jump: /* Manually specify a two-byte jmp instruction here rather - * than leaving it up to the assembler. */ - .byte 0xeb - .byte setup_code - header + * than leaving it up to the assembler. + */ + .byte 0xeb, ( setup - header ) header: .byte 'H', 'd', 'r', 'S' version: @@ -131,7 +66,7 @@ kernel_version: type_of_loader: .byte 0 loadflags: - .byte 0 + .byte 0x01 /* LOADED_HIGH */ setup_move_size: .word 0 code32_start: @@ -144,21 +79,22 @@ bootsect_kludge: .long 0 heap_end_ptr: .word 0 -pad1: - .word 0 +ext_loader_ver: + .byte 0 +ext_loader_type: + .byte 0 cmd_line_ptr: .long 0 initrd_addr_max: - /* We don't use an initrd but some bootloaders (e.g. SYSLINUX) have - * been known to require this field. Set the value to 2 GB. This - * value is also used by the Linux kernel. */ - .long 0x7fffffff + .long 0xffffffff kernel_alignment: .long 0 relocatable_kernel: .byte 0 -pad2: - .byte 0, 0, 0 +min_alignment: + .byte 0 +xloadflags: + .word 0 cmdline_size: .long 0x7ff hardware_subarch: @@ -169,28 +105,18 @@ hardware_subarch_data: version_string: .asciz VERSION -/* - We don't need to do too much setup. - - This code gets loaded at SETUPSEG:0. It wants to start - executing the image that's loaded at SYSSEG:0 and - whose entry point is SYSSEG:0. -*/ -setup_code: - /* We expect to be contiguous in memory once loaded. The Linux image - * boot process requires that setup code is loaded separately from - * "non-real code". Since we don't need any information that's left - * in the prefix, it doesn't matter: we just have to ensure that - * %cs:0000 is where the start of the image *would* be. - */ - ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_ipxe - - - .org PREFIXSIZE -/* - We're now at the beginning of the kernel proper. +/***************************************************************************** + * + * Setup code + * */ -run_ipxe: + +setup: + /* Fix up code segment */ + pushw %ds + pushw $1f + lret +1: /* Set up stack just below 0x7c00 and clear direction flag */ xorw %ax, %ax movw %ax, %ss @@ -198,7 +124,7 @@ run_ipxe: cld /* Retrieve command-line pointer */ - movl %ds:cmd_line_ptr, %edx + movl cmd_line_ptr, %edx testl %edx, %edx jz no_cmd_line @@ -240,7 +166,6 @@ no_cmd_line: jnz 1f orl $0xffffffff, %ebp /* Allow arbitrary relocation if no initrd */ 1: - /* Install iPXE */ call alloc_basemem xorl %esi, %esi @@ -282,3 +207,30 @@ no_cmd_line: /* Boot next device */ int $0x18 + +/***************************************************************************** + * + * Open payload (called by libprefix) + * + * Parameters: + * %ds:0000 : Prefix + * %esi : Buffer for copy of image source (or zero if no buffer available) + * %ecx : Expected offset within buffer of first payload block + * Returns: + * %esi : Valid image source address (buffered or unbuffered) + * %ecx : Actual offset within buffer of first payload block + * CF set on error + */ + + .section ".text16.early", "awx", @progbits + .globl open_payload +open_payload: + + /* Our payload will always end up at BZI_LOAD_HIGH_ADDR */ + movl $BZI_LOAD_HIGH_ADDR, %esi + xorl %ecx, %ecx + lret + + /* Payload must be aligned to a whole number of setup sectors */ + .globl _payload_align + .equ _payload_align, 512 diff --git a/roms/ipxe/src/arch/i386/prefix/mromprefix.S b/roms/ipxe/src/arch/i386/prefix/mromprefix.S index 0f0847e5f..4c94457c2 100644 --- a/roms/ipxe/src/arch/i386/prefix/mromprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/mromprefix.S @@ -30,10 +30,12 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PCI_BAR_5 0x24 #define PCI_BAR_EXPROM 0x30 +#define PCIR_SIGNATURE ( 'P' + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) ) + #define ROMPREFIX_EXCLUDE_PAYLOAD 1 #define ROMPREFIX_MORE_IMAGES 1 -#define _rom_start _mrom_start -#include "romprefix.S" +#define _pcirom_start _mrom_start +#include "pciromprefix.S" .text .arch i386 @@ -99,6 +101,7 @@ find_mem_bar: jle 1f stc movl $0xbabababa, %esi /* Report "No suitable BAR" */ + movl rom_bar_size, %ecx jmp 99f 1: movw $4, %bp @@ -157,17 +160,26 @@ find_mem_bar: call pci_write_config_dword /* Locate our ROM image */ -1: addr32 es cmpw $0xaa55, (%eax) - je 2f - stc - movl %eax, %esi /* Report failure address */ - jmp 99f -2: addr32 es cmpl $_build_id, build_id(%eax) +1: movl $0xaa55, %ecx /* 55aa signature */ + addr32 es cmpw %cx, (%eax) + jne 2f + movl $PCIR_SIGNATURE, %ecx /* PCIR signature */ + addr32 es movzwl 0x18(%eax), %edx + addr32 es cmpl %ecx, (%eax,%edx) + jne 2f + addr32 es cmpl $_build_id, build_id(%eax) /* iPXE build ID */ je 3f - addr32 es movzbl 2(%eax), %ecx + movl $0x80, %ecx /* Last image */ + addr32 es testb %cl, 0x15(%eax,%edx) + jnz 2f + addr32 es movzwl 0x10(%eax,%edx), %ecx /* PCIR image length */ shll $9, %ecx addl %ecx, %eax jmp 1b +2: /* Failure */ + stc + movl %eax, %esi /* Report failure address */ + jmp 99f 3: /* Copy payload to buffer, or set buffer address to BAR address */ @@ -184,7 +196,7 @@ find_mem_bar: movl %eax, %esi addr32 es movzbl 2(%esi), %ecx shll $7, %ecx - addr32 es movzbl 2(%esi,%ecx,4), %edx + addr32 es movzwl mpciheader_image_length(%esi,%ecx,4), %edx shll $7, %edx addl %edx, %ecx addr32 es rep movsl @@ -451,20 +463,12 @@ pci_set_mem_access: .org 0x00 mromheader: .word 0xaa55 /* BIOS extension signature */ -mromheader_size: .byte 0 /* Size in 512-byte blocks */ .org 0x18 .word mpciheader .org 0x1a .word 0 .size mromheader, . - mromheader - .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "APPB" - .long mromheader_size - .long 512 - .long 0 - .previous - mpciheader: .ascii "PCIR" /* Signature */ .word pci_vendor_id /* Vendor identification */ diff --git a/roms/ipxe/src/arch/i386/prefix/pciromprefix.S b/roms/ipxe/src/arch/i386/prefix/pciromprefix.S new file mode 100644 index 000000000..45ba31f50 --- /dev/null +++ b/roms/ipxe/src/arch/i386/prefix/pciromprefix.S @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 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. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define BUSTYPE "PCIR" +#define _rom_start _pcirom_start +#include "romprefix.S" diff --git a/roms/ipxe/src/arch/i386/prefix/romprefix.S b/roms/ipxe/src/arch/i386/prefix/romprefix.S index ae18f05d0..7bc4fe8cd 100644 --- a/roms/ipxe/src/arch/i386/prefix/romprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/romprefix.S @@ -46,6 +46,12 @@ FILE_LICENCE ( GPL2_OR_LATER ) #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 @@ -64,8 +70,10 @@ checksum: .word ipxeheader .org 0x16 .word undiheader +.ifeqs BUSTYPE, "PCIR" .org 0x18 .word pciheader +.endif .org 0x1a .word pnpheader .size romheader, . - romheader @@ -77,6 +85,7 @@ checksum: .long 0 .previous +.ifeqs BUSTYPE, "PCIR" pciheader: .ascii "PCIR" /* Signature */ .word pci_vendor_id /* Vendor identification */ @@ -107,6 +116,7 @@ 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 @@ -148,11 +158,14 @@ mfgstr: */ prodstr: .ascii PRODUCT_SHORT_NAME +.ifeqs BUSTYPE, "PCIR" prodstr_separator: .byte 0 .ascii "(PCI " prodstr_pci_id: - .asciz "xx:xx.x)" /* Filled in by init code */ + .ascii "xx:xx.x)" /* Filled in by init code */ +.endif /* PCIR */ + .byte 0 .size prodstr, . - prodstr .globl undiheader @@ -167,7 +180,7 @@ undiheader: .word _data16_memsz /* Stack segment size */ .word _data16_memsz /* Data segment size */ .word _text16_memsz /* Code segment size */ - .ascii "PCIR" /* Bus type */ + .ascii BUSTYPE /* Bus type */ .equ undiheader_len, . - undiheader .size undiheader, . - undiheader @@ -208,38 +221,39 @@ init: pushw %cs popw %ds - /* Shuffle some registers around. We need %di available for - * the print_xxx functions, and in a register that's - * addressable from %es, so shuffle as follows: - * - * %di (pointer to PnP structure) => %bx - * %bx (runtime segment address, for PCI 3.0) => %gs - */ - movw %bx, %gs - movw %di, %bx - - /* Store PCI bus:dev.fn address */ - movw %ax, init_pci_busdevfn - /* Print message as early as possible */ movw $init_message, %si xorw %di, %di call print_message - call print_pci_busdevfn - /* Fill in product name string, if possible */ + /* 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 */ - movb $( ' ' ), %al xorw %di, %di - call print_character + call print_space movw %cs, %ax call print_hex_word - /* Check for PCI BIOS version */ + /* Check for PCI BIOS version, if applicable */ +.ifeqs BUSTYPE, "PCIR" pushl %ebx pushl %edx pushl %edi @@ -290,6 +304,7 @@ no_pci3: 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. @@ -403,13 +418,13 @@ no_pmm: loop 1b subb %bl, checksum - /* Copy self to option ROM space. Required for PCI3.0, which - * loads us to a temporary location in low memory. Will be a - * no-op for lower PCI versions. + /* 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. */ - movb $( ' ' ), %al +.ifeqs BUSTYPE, "PCIR" xorw %di, %di - call print_character + call print_space movw %gs, %ax call print_hex_word movzbw romheader_size, %cx @@ -418,10 +433,13 @@ no_pmm: xorw %si, %si xorw %di, %di cs rep movsb +.endif - /* Skip prompt if this is not the first PCI function */ + /* 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 @@ -571,11 +589,13 @@ init_message: .ascii "\n" .ascii PRODUCT_NAME .ascii "\n" - .asciz "iPXE (http://ipxe.org) " + .asciz "iPXE (http://ipxe.org)" .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 @@ -598,9 +618,11 @@ 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 * @@ -739,14 +761,18 @@ exec: /* Set %ds = %cs */ lret .section ".text16", "awx", @progbits 1: - /* Retrieve PCI bus:dev.fn */ + /* 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 */ + /* Store PCI bus:dev.fn, if applicable */ +.ifeqs BUSTYPE, "PCIR" movw %ax, autoboot_busdevfn +.endif /* Call main() */ pushl $main diff --git a/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c b/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c index f90d49b02..cc4765de2 100644 --- a/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c +++ b/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c @@ -8,6 +8,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> +#include <ipxe/profile.h> #include <realmode.h> #include <pic8259.h> @@ -20,7 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); extern char interrupt_wrapper[]; /** The interrupt vectors */ -static struct interrupt_vector intr_vec[ IRQ_MAX + 1 ]; +static struct interrupt_vector intr_vec[NUM_INT]; /** The interrupt descriptor table */ struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) )); @@ -30,6 +31,12 @@ struct idtr idtr = { .limit = ( sizeof ( idt ) - 1 ), }; +/** Timer interrupt profiler */ +static struct profiler timer_irq_profiler __profiler = { .name = "irq.timer" }; + +/** Other interrupt profiler */ +static struct profiler other_irq_profiler __profiler = { .name = "irq.other" }; + /** * Allocate space on the real-mode stack and copy data there from a * user buffer @@ -83,13 +90,11 @@ void set_interrupt_vector ( unsigned int intr, void *vector ) { */ void init_idt ( void ) { struct interrupt_vector *vec; - unsigned int irq; unsigned int intr; /* Initialise the interrupt descriptor table and interrupt vectors */ - for ( irq = 0 ; irq <= IRQ_MAX ; irq++ ) { - intr = IRQ_INT ( irq ); - vec = &intr_vec[irq]; + for ( intr = 0 ; intr < NUM_INT ; intr++ ) { + vec = &intr_vec[intr]; vec->pushal = PUSHAL_INSN; vec->movb = MOVB_INSN; vec->intr = intr; @@ -98,24 +103,47 @@ void init_idt ( void ) { ( uint32_t ) vec->next ); set_interrupt_vector ( intr, vec ); } + DBGC ( &intr_vec[0], "INTn vector at %p+%xn (phys %#lx+%xn)\n", + intr_vec, sizeof ( intr_vec[0] ), + virt_to_phys ( intr_vec ), sizeof ( intr_vec[0] ) ); /* Initialise the interrupt descriptor table register */ idtr.base = virt_to_phys ( idt ); } /** + * Determine interrupt profiler (for debugging) + * + * @v intr Interrupt number + * @ret profiler Profiler + */ +static struct profiler * interrupt_profiler ( int intr ) { + + switch ( intr ) { + case IRQ_INT ( 0 ) : + return &timer_irq_profiler; + default: + return &other_irq_profiler; + } +} + +/** * Interrupt handler * - * @v irq Interrupt number + * @v intr Interrupt number */ -void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int irq ) { +void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int intr ) { + struct profiler *profiler = interrupt_profiler ( intr ); uint32_t discard_eax; /* Reissue interrupt in real mode */ + profile_start ( profiler ); __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t" "\n1:\n\t" "int $0x00\n\t" ) - : "=a" ( discard_eax ) : "0" ( irq ) ); + : "=a" ( discard_eax ) : "0" ( intr ) ); + profile_stop ( profiler ); + profile_exclude ( profiler ); } PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); diff --git a/roms/ipxe/src/arch/x86/Makefile b/roms/ipxe/src/arch/x86/Makefile index cdd397d40..e555587df 100644 --- a/roms/ipxe/src/arch/x86/Makefile +++ b/roms/ipxe/src/arch/x86/Makefile @@ -8,6 +8,7 @@ SRCDIRS += arch/x86/core SRCDIRS += arch/x86/interface/efi SRCDIRS += arch/x86/prefix SRCDIRS += arch/x86/hci/commands +SRCDIRS += arch/x86/drivers/xen # breaks building some of the linux-related objects CFLAGS += -Ulinux diff --git a/roms/ipxe/src/arch/x86/Makefile.efi b/roms/ipxe/src/arch/x86/Makefile.efi index 3e3fbe3ca..13a69d9f7 100644 --- a/roms/ipxe/src/arch/x86/Makefile.efi +++ b/roms/ipxe/src/arch/x86/Makefile.efi @@ -15,6 +15,10 @@ NON_AUTO_MEDIA += efidrv NON_AUTO_MEDIA += drv.efi NON_AUTO_MEDIA += efirom +# Include SNP driver in the all-drivers build +# +DRIVERS += snp + # Rules for building EFI files # $(BIN)/%.efi : $(BIN)/%.efi.tmp $(ELF2EFI) diff --git a/roms/ipxe/src/arch/x86/Makefile.linux b/roms/ipxe/src/arch/x86/Makefile.linux index e35b04f0e..1faf84753 100644 --- a/roms/ipxe/src/arch/x86/Makefile.linux +++ b/roms/ipxe/src/arch/x86/Makefile.linux @@ -10,4 +10,4 @@ SRCDIRS += arch/x86/core/linux $(BIN)/%.linux : $(BIN)/%.linux.tmp $(QM)$(ECHO) " [FINISH] $@" - $(Q)cp -p $< $@ + $(Q)$(CP) $< $@ diff --git a/roms/ipxe/src/arch/x86/drivers/xen/hvm.c b/roms/ipxe/src/arch/x86/drivers/xen/hvm.c new file mode 100644 index 000000000..7406ca68d --- /dev/null +++ b/roms/ipxe/src/arch/x86/drivers/xen/hvm.c @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2014 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 (at your option) 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdio.h> +#include <errno.h> +#include <ipxe/malloc.h> +#include <ipxe/pci.h> +#include <ipxe/cpuid.h> +#include <ipxe/msr.h> +#include <ipxe/xen.h> +#include <ipxe/xenver.h> +#include <ipxe/xenmem.h> +#include <ipxe/xenstore.h> +#include <ipxe/xenbus.h> +#include <ipxe/xengrant.h> +#include "hvm.h" + +/** @file + * + * Xen HVM driver + * + */ + +/** + * Get CPUID base + * + * @v hvm HVM device + * @ret rc Return status code + */ +static int hvm_cpuid_base ( struct hvm_device *hvm ) { + struct { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + } __attribute__ (( packed )) signature; + uint32_t base; + uint32_t version; + uint32_t discard_eax; + uint32_t discard_ebx; + uint32_t discard_ecx; + uint32_t discard_edx; + + /* Scan for magic signature */ + for ( base = HVM_CPUID_MIN ; base <= HVM_CPUID_MAX ; + base += HVM_CPUID_STEP ) { + cpuid ( base, &discard_eax, &signature.ebx, &signature.ecx, + &signature.edx ); + if ( memcmp ( &signature, HVM_CPUID_MAGIC, + sizeof ( signature ) ) == 0 ) { + hvm->cpuid_base = base; + cpuid ( ( base + HVM_CPUID_VERSION ), &version, + &discard_ebx, &discard_ecx, &discard_edx ); + DBGC2 ( hvm, "HVM using CPUID base %#08x (v%d.%d)\n", + base, ( version >> 16 ), ( version & 0xffff ) ); + return 0; + } + } + + DBGC ( hvm, "HVM could not find hypervisor\n" ); + return -ENODEV; +} + +/** + * Map hypercall page(s) + * + * @v hvm HVM device + * @ret rc Return status code + */ +static int hvm_map_hypercall ( struct hvm_device *hvm ) { + uint32_t pages; + uint32_t msr; + uint32_t discard_ecx; + uint32_t discard_edx; + physaddr_t hypercall_phys; + uint32_t version; + static xen_extraversion_t extraversion; + int xenrc; + int rc; + + /* Get number of hypercall pages and MSR to use */ + cpuid ( ( hvm->cpuid_base + HVM_CPUID_PAGES ), &pages, &msr, + &discard_ecx, &discard_edx ); + + /* Allocate pages */ + hvm->hypercall_len = ( pages * PAGE_SIZE ); + hvm->xen.hypercall = malloc_dma ( hvm->hypercall_len, PAGE_SIZE ); + if ( ! hvm->xen.hypercall ) { + DBGC ( hvm, "HVM could not allocate %d hypercall page(s)\n", + pages ); + return -ENOMEM; + } + hypercall_phys = virt_to_phys ( hvm->xen.hypercall ); + DBGC2 ( hvm, "HVM hypercall page(s) at [%#08lx,%#08lx) via MSR %#08x\n", + hypercall_phys, ( hypercall_phys + hvm->hypercall_len ), msr ); + + /* Write to MSR */ + wrmsr ( msr, hypercall_phys ); + + /* Check that hypercall mechanism is working */ + version = xenver_version ( &hvm->xen ); + if ( ( xenrc = xenver_extraversion ( &hvm->xen, &extraversion ) ) != 0){ + rc = -EXEN ( xenrc ); + DBGC ( hvm, "HVM could not get extraversion: %s\n", + strerror ( rc ) ); + return rc; + } + DBGC2 ( hvm, "HVM found Xen version %d.%d%s\n", + ( version >> 16 ), ( version & 0xffff ) , extraversion ); + + return 0; +} + +/** + * Unmap hypercall page(s) + * + * @v hvm HVM device + */ +static void hvm_unmap_hypercall ( struct hvm_device *hvm ) { + + /* Free pages */ + free_dma ( hvm->xen.hypercall, hvm->hypercall_len ); +} + +/** + * Allocate and map MMIO space + * + * @v hvm HVM device + * @v space Source mapping space + * @v len Length (must be a multiple of PAGE_SIZE) + * @ret mmio MMIO space address, or NULL on error + */ +static void * hvm_ioremap ( struct hvm_device *hvm, unsigned int space, + size_t len ) { + struct xen_add_to_physmap add; + struct xen_remove_from_physmap remove; + unsigned int pages = ( len / PAGE_SIZE ); + physaddr_t mmio_phys; + unsigned int i; + void *mmio; + int xenrc; + int rc; + + /* Sanity check */ + assert ( ( len % PAGE_SIZE ) == 0 ); + + /* Check for available space */ + if ( ( hvm->mmio_offset + len ) > hvm->mmio_len ) { + DBGC ( hvm, "HVM could not allocate %zd bytes of MMIO space " + "(%zd of %zd remaining)\n", len, + ( hvm->mmio_len - hvm->mmio_offset ), hvm->mmio_len ); + goto err_no_space; + } + + /* Map this space */ + mmio = ioremap ( ( hvm->mmio + hvm->mmio_offset ), len ); + if ( ! mmio ) { + DBGC ( hvm, "HVM could not map MMIO space [%08lx,%08lx)\n", + ( hvm->mmio + hvm->mmio_offset ), + ( hvm->mmio + hvm->mmio_offset + len ) ); + goto err_ioremap; + } + mmio_phys = virt_to_phys ( mmio ); + + /* Add to physical address space */ + for ( i = 0 ; i < pages ; i++ ) { + add.domid = DOMID_SELF; + add.idx = i; + add.space = space; + add.gpfn = ( ( mmio_phys / PAGE_SIZE ) + i ); + if ( ( xenrc = xenmem_add_to_physmap ( &hvm->xen, &add ) ) !=0){ + rc = -EXEN ( xenrc ); + DBGC ( hvm, "HVM could not add space %d idx %d at " + "[%08lx,%08lx): %s\n", space, i, + ( mmio_phys + ( i * PAGE_SIZE ) ), + ( mmio_phys + ( ( i + 1 ) * PAGE_SIZE ) ), + strerror ( rc ) ); + goto err_add_to_physmap; + } + } + + /* Update offset */ + hvm->mmio_offset += len; + + return mmio; + + i = pages; + err_add_to_physmap: + for ( i-- ; ( signed int ) i >= 0 ; i-- ) { + remove.domid = DOMID_SELF; + add.gpfn = ( ( mmio_phys / PAGE_SIZE ) + i ); + xenmem_remove_from_physmap ( &hvm->xen, &remove ); + } + iounmap ( mmio ); + err_ioremap: + err_no_space: + return NULL; +} + +/** + * Unmap MMIO space + * + * @v hvm HVM device + * @v mmio MMIO space address + * @v len Length (must be a multiple of PAGE_SIZE) + */ +static void hvm_iounmap ( struct hvm_device *hvm, void *mmio, size_t len ) { + struct xen_remove_from_physmap remove; + physaddr_t mmio_phys = virt_to_phys ( mmio ); + unsigned int pages = ( len / PAGE_SIZE ); + unsigned int i; + int xenrc; + int rc; + + /* Unmap this space */ + iounmap ( mmio ); + + /* Remove from physical address space */ + for ( i = 0 ; i < pages ; i++ ) { + remove.domid = DOMID_SELF; + remove.gpfn = ( ( mmio_phys / PAGE_SIZE ) + i ); + if ( ( xenrc = xenmem_remove_from_physmap ( &hvm->xen, + &remove ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( hvm, "HVM could not remove space [%08lx,%08lx): " + "%s\n", ( mmio_phys + ( i * PAGE_SIZE ) ), + ( mmio_phys + ( ( i + 1 ) * PAGE_SIZE ) ), + strerror ( rc ) ); + /* Nothing we can do about this */ + } + } +} + +/** + * Map shared info page + * + * @v hvm HVM device + * @ret rc Return status code + */ +static int hvm_map_shared_info ( struct hvm_device *hvm ) { + physaddr_t shared_info_phys; + int rc; + + /* Map shared info page */ + hvm->xen.shared = hvm_ioremap ( hvm, XENMAPSPACE_shared_info, + PAGE_SIZE ); + if ( ! hvm->xen.shared ) { + rc = -ENOMEM; + goto err_alloc; + } + shared_info_phys = virt_to_phys ( hvm->xen.shared ); + DBGC2 ( hvm, "HVM shared info page at [%#08lx,%#08lx)\n", + shared_info_phys, ( shared_info_phys + PAGE_SIZE ) ); + + /* Sanity check */ + DBGC2 ( hvm, "HVM wallclock time is %d\n", + readl ( &hvm->xen.shared->wc_sec ) ); + + return 0; + + hvm_iounmap ( hvm, hvm->xen.shared, PAGE_SIZE ); + err_alloc: + return rc; +} + +/** + * Unmap shared info page + * + * @v hvm HVM device + */ +static void hvm_unmap_shared_info ( struct hvm_device *hvm ) { + + /* Unmap shared info page */ + hvm_iounmap ( hvm, hvm->xen.shared, PAGE_SIZE ); +} + +/** + * Map grant table + * + * @v hvm HVM device + * @ret rc Return status code + */ +static int hvm_map_grant ( struct hvm_device *hvm ) { + physaddr_t grant_phys; + int rc; + + /* Initialise grant table */ + if ( ( rc = xengrant_init ( &hvm->xen ) ) != 0 ) { + DBGC ( hvm, "HVM could not initialise grant table: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Map grant table */ + hvm->xen.grant.table = hvm_ioremap ( hvm, XENMAPSPACE_grant_table, + hvm->xen.grant.len ); + if ( ! hvm->xen.grant.table ) + return -ENODEV; + + grant_phys = virt_to_phys ( hvm->xen.grant.table ); + DBGC2 ( hvm, "HVM mapped grant table at [%08lx,%08lx)\n", + grant_phys, ( grant_phys + hvm->xen.grant.len ) ); + return 0; +} + +/** + * Unmap grant table + * + * @v hvm HVM device + */ +static void hvm_unmap_grant ( struct hvm_device *hvm ) { + + /* Unmap grant table */ + hvm_iounmap ( hvm, hvm->xen.grant.table, hvm->xen.grant.len ); +} + +/** + * Map XenStore + * + * @v hvm HVM device + * @ret rc Return status code + */ +static int hvm_map_xenstore ( struct hvm_device *hvm ) { + uint64_t xenstore_evtchn; + uint64_t xenstore_pfn; + physaddr_t xenstore_phys; + char *name; + int xenrc; + int rc; + + /* Get XenStore event channel */ + if ( ( xenrc = xen_hvm_get_param ( &hvm->xen, HVM_PARAM_STORE_EVTCHN, + &xenstore_evtchn ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( hvm, "HVM could not get XenStore event channel: %s\n", + strerror ( rc ) ); + return rc; + } + hvm->xen.store.port = xenstore_evtchn; + + /* Get XenStore PFN */ + if ( ( xenrc = xen_hvm_get_param ( &hvm->xen, HVM_PARAM_STORE_PFN, + &xenstore_pfn ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( hvm, "HVM could not get XenStore PFN: %s\n", + strerror ( rc ) ); + return rc; + } + xenstore_phys = ( xenstore_pfn * PAGE_SIZE ); + + /* Map XenStore */ + hvm->xen.store.intf = ioremap ( xenstore_phys, PAGE_SIZE ); + if ( ! hvm->xen.store.intf ) { + DBGC ( hvm, "HVM could not map XenStore at [%08lx,%08lx)\n", + xenstore_phys, ( xenstore_phys + PAGE_SIZE ) ); + return -ENODEV; + } + DBGC2 ( hvm, "HVM mapped XenStore at [%08lx,%08lx) with event port " + "%d\n", xenstore_phys, ( xenstore_phys + PAGE_SIZE ), + hvm->xen.store.port ); + + /* Check that XenStore is working */ + if ( ( rc = xenstore_read ( &hvm->xen, &name, "name", NULL ) ) != 0 ) { + DBGC ( hvm, "HVM could not read domain name: %s\n", + strerror ( rc ) ); + return rc; + } + DBGC2 ( hvm, "HVM running in domain \"%s\"\n", name ); + free ( name ); + + return 0; +} + +/** + * Unmap XenStore + * + * @v hvm HVM device + */ +static void hvm_unmap_xenstore ( struct hvm_device *hvm ) { + + /* Unmap XenStore */ + iounmap ( hvm->xen.store.intf ); +} + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int hvm_probe ( struct pci_device *pci ) { + struct hvm_device *hvm; + int rc; + + /* Allocate and initialise structure */ + hvm = zalloc ( sizeof ( *hvm ) ); + if ( ! hvm ) { + rc = -ENOMEM; + goto err_alloc; + } + hvm->mmio = pci_bar_start ( pci, HVM_MMIO_BAR ); + hvm->mmio_len = pci_bar_size ( pci, HVM_MMIO_BAR ); + DBGC2 ( hvm, "HVM has MMIO space [%08lx,%08lx)\n", + hvm->mmio, ( hvm->mmio + hvm->mmio_len ) ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Attach to hypervisor */ + if ( ( rc = hvm_cpuid_base ( hvm ) ) != 0 ) + goto err_cpuid_base; + if ( ( rc = hvm_map_hypercall ( hvm ) ) != 0 ) + goto err_map_hypercall; + if ( ( rc = hvm_map_shared_info ( hvm ) ) != 0 ) + goto err_map_shared_info; + if ( ( rc = hvm_map_grant ( hvm ) ) != 0 ) + goto err_map_grant; + if ( ( rc = hvm_map_xenstore ( hvm ) ) != 0 ) + goto err_map_xenstore; + + /* Probe Xen devices */ + if ( ( rc = xenbus_probe ( &hvm->xen, &pci->dev ) ) != 0 ) { + DBGC ( hvm, "HVM could not probe Xen bus: %s\n", + strerror ( rc ) ); + goto err_xenbus_probe; + } + + pci_set_drvdata ( pci, hvm ); + return 0; + + xenbus_remove ( &hvm->xen, &pci->dev ); + err_xenbus_probe: + hvm_unmap_xenstore ( hvm ); + err_map_xenstore: + hvm_unmap_grant ( hvm ); + err_map_grant: + hvm_unmap_shared_info ( hvm ); + err_map_shared_info: + hvm_unmap_hypercall ( hvm ); + err_map_hypercall: + err_cpuid_base: + free ( hvm ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void hvm_remove ( struct pci_device *pci ) { + struct hvm_device *hvm = pci_get_drvdata ( pci ); + + xenbus_remove ( &hvm->xen, &pci->dev ); + hvm_unmap_xenstore ( hvm ); + hvm_unmap_grant ( hvm ); + hvm_unmap_shared_info ( hvm ); + hvm_unmap_hypercall ( hvm ); + free ( hvm ); +} + +/** PCI device IDs */ +static struct pci_device_id hvm_ids[] = { + PCI_ROM ( 0x5853, 0x0001, "hvm", "hvm", 0 ), + PCI_ROM ( 0x5853, 0x0002, "hvm2", "hvm2", 0 ), +}; + +/** PCI driver */ +struct pci_driver hvm_driver __pci_driver = { + .ids = hvm_ids, + .id_count = ( sizeof ( hvm_ids ) / sizeof ( hvm_ids[0] ) ), + .probe = hvm_probe, + .remove = hvm_remove, +}; + +/* Drag in netfront driver */ +REQUIRE_OBJECT ( netfront ); diff --git a/roms/ipxe/src/arch/x86/drivers/xen/hvm.h b/roms/ipxe/src/arch/x86/drivers/xen/hvm.h new file mode 100644 index 000000000..325d20d66 --- /dev/null +++ b/roms/ipxe/src/arch/x86/drivers/xen/hvm.h @@ -0,0 +1,75 @@ +#ifndef _HVM_H +#define _HVM_H + +/** @file + * + * Xen HVM driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/xen.h> +#include <xen/hvm/hvm_op.h> +#include <xen/hvm/params.h> + +/** Minimum CPUID base */ +#define HVM_CPUID_MIN 0x40000000UL + +/** Maximum CPUID base */ +#define HVM_CPUID_MAX 0x4000ff00UL + +/** Increment between CPUID bases */ +#define HVM_CPUID_STEP 0x00000100UL + +/** Magic signature */ +#define HVM_CPUID_MAGIC "XenVMMXenVMM" + +/** Get Xen version */ +#define HVM_CPUID_VERSION 1 + +/** Get number of hypercall pages */ +#define HVM_CPUID_PAGES 2 + +/** PCI MMIO BAR */ +#define HVM_MMIO_BAR PCI_BASE_ADDRESS_1 + +/** A Xen HVM device */ +struct hvm_device { + /** Xen hypervisor */ + struct xen_hypervisor xen; + /** CPUID base */ + uint32_t cpuid_base; + /** Length of hypercall table */ + size_t hypercall_len; + /** MMIO base address */ + unsigned long mmio; + /** Current offset within MMIO address space */ + size_t mmio_offset; + /** Length of MMIO address space */ + size_t mmio_len; +}; + +/** + * Get HVM parameter value + * + * @v xen Xen hypervisor + * @v index Parameter index + * @v value Value to fill in + * @ret xenrc Xen status code + */ +static inline int xen_hvm_get_param ( struct xen_hypervisor *xen, + unsigned int index, uint64_t *value ) { + struct xen_hvm_param param; + int xenrc; + + param.domid = DOMID_SELF; + param.index = index; + xenrc = xen_hypercall_2 ( xen, __HYPERVISOR_hvm_op, HVMOP_get_param, + virt_to_phys ( ¶m ) ); + *value = param.value; + return xenrc; +} + +#endif /* _HVM_H */ diff --git a/roms/ipxe/src/arch/x86/include/bits/errfile.h b/roms/ipxe/src/arch/x86/include/bits/errfile.h index acf8c3e39..624575621 100644 --- a/roms/ipxe/src/arch/x86/include/bits/errfile.h +++ b/roms/ipxe/src/arch/x86/include/bits/errfile.h @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_timer_rdtsc ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 ) +#define ERRFILE_hvm ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00020000 ) #define ERRFILE_cpuid_cmd ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00000000 ) #define ERRFILE_cpuid_settings ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00010000 ) diff --git a/roms/ipxe/src/arch/x86/include/bits/xen.h b/roms/ipxe/src/arch/x86/include/bits/xen.h new file mode 100644 index 000000000..dbccf1b77 --- /dev/null +++ b/roms/ipxe/src/arch/x86/include/bits/xen.h @@ -0,0 +1,164 @@ +#ifndef _BITS_XEN_H +#define _BITS_XEN_H + +/** @file + * + * Xen interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* Hypercall registers */ +#ifdef __x86_64__ +#define XEN_REG1 "rdi" +#define XEN_REG2 "rsi" +#define XEN_REG3 "rdx" +#define XEN_REG4 "r10" +#define XEN_REG5 "r8" +#else +#define XEN_REG1 "ebx" +#define XEN_REG2 "ecx" +#define XEN_REG3 "edx" +#define XEN_REG4 "esi" +#define XEN_REG5 "edi" +#endif + +/** A hypercall entry point */ +struct xen_hypercall { + /** Code generated by hypervisor */ + uint8_t code[32]; +} __attribute__ (( packed )); + +/** + * Issue hypercall with one argument + * + * @v xen Xen hypervisor + * @v hypercall Hypercall number + * @v arg1 First argument + * @ret retval Return value + */ +static inline __attribute__ (( always_inline )) unsigned long +xen_hypercall_1 ( struct xen_hypervisor *xen, unsigned int hypercall, + unsigned long arg1 ) { + register unsigned long reg1 asm ( XEN_REG1 ) = arg1; + unsigned long retval; + + __asm__ __volatile__ ( "call *%2" + : "=a" ( retval ), "+r" ( reg1 ) + : "r" ( &xen->hypercall[hypercall] ) + : XEN_REG2, XEN_REG3, XEN_REG4, XEN_REG5, + "memory" ); + return retval; +} + +/** + * Issue hypercall with two arguments + * + * @v xen Xen hypervisor + * @v hypercall Hypercall number + * @v arg1 First argument + * @v arg2 Second argument + * @ret retval Return value + */ +static inline __attribute__ (( always_inline )) unsigned long +xen_hypercall_2 ( struct xen_hypervisor *xen, unsigned int hypercall, + unsigned long arg1, unsigned long arg2 ) { + register unsigned long reg1 asm ( XEN_REG1 ) = arg1; + register unsigned long reg2 asm ( XEN_REG2 ) = arg2; + unsigned long retval; + + __asm__ __volatile__ ( "call *%3" + : "=a" ( retval ), "+r" ( reg1 ), "+r" ( reg2 ) + : "r" ( &xen->hypercall[hypercall] ) + : XEN_REG3, XEN_REG4, XEN_REG5, "memory" ); + return retval; +} + +/** + * Issue hypercall with three arguments + * + * @v xen Xen hypervisor + * @v hypercall Hypercall number + * @v arg1 First argument + * @v arg2 Second argument + * @v arg3 Third argument + * @ret retval Return value + */ +static inline __attribute__ (( always_inline )) unsigned long +xen_hypercall_3 ( struct xen_hypervisor *xen, unsigned int hypercall, + unsigned long arg1, unsigned long arg2, unsigned long arg3 ) { + register unsigned long reg1 asm ( XEN_REG1 ) = arg1; + register unsigned long reg2 asm ( XEN_REG2 ) = arg2; + register unsigned long reg3 asm ( XEN_REG3 ) = arg3; + unsigned long retval; + + __asm__ __volatile__ ( "call *%4" + : "=a" ( retval ), "+r" ( reg1 ), "+r" ( reg2 ), + "+r" ( reg3 ) + : "r" ( &xen->hypercall[hypercall] ) + : XEN_REG4, XEN_REG5, "memory" ); + return retval; +} + +/** + * Issue hypercall with four arguments + * + * @v xen Xen hypervisor + * @v hypercall Hypercall number + * @v arg1 First argument + * @v arg2 Second argument + * @v arg3 Third argument + * @v arg4 Fourth argument + * @ret retval Return value + */ +static inline __attribute__ (( always_inline )) unsigned long +xen_hypercall_4 ( struct xen_hypervisor *xen, unsigned int hypercall, + unsigned long arg1, unsigned long arg2, unsigned long arg3, + unsigned long arg4 ) { + register unsigned long reg1 asm ( XEN_REG1 ) = arg1; + register unsigned long reg2 asm ( XEN_REG2 ) = arg2; + register unsigned long reg3 asm ( XEN_REG3 ) = arg3; + register unsigned long reg4 asm ( XEN_REG4 ) = arg4; + unsigned long retval; + + __asm__ __volatile__ ( "call *%5" + : "=a" ( retval ), "+r" ( reg1 ), "+r" ( reg2 ), + "+r" ( reg3 ), "+r" ( reg4 ) + : "r" ( &xen->hypercall[hypercall] ) + : XEN_REG5, "memory" ); + return retval; +} + +/** + * Issue hypercall with five arguments + * + * @v xen Xen hypervisor + * @v hypercall Hypercall number + * @v arg1 First argument + * @v arg2 Second argument + * @v arg3 Third argument + * @v arg4 Fourth argument + * @v arg5 Fifth argument + * @ret retval Return value + */ +static inline __attribute__ (( always_inline )) unsigned long +xen_hypercall_5 ( struct xen_hypervisor *xen, unsigned int hypercall, + unsigned long arg1, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5 ) { + register unsigned long reg1 asm ( XEN_REG1 ) = arg1; + register unsigned long reg2 asm ( XEN_REG2 ) = arg2; + register unsigned long reg3 asm ( XEN_REG3 ) = arg3; + register unsigned long reg4 asm ( XEN_REG4 ) = arg4; + register unsigned long reg5 asm ( XEN_REG5 ) = arg5; + unsigned long retval; + + __asm__ __volatile__ ( "call *%6" + : "=a" ( retval ), "+r" ( reg1 ), "+r" ( reg2 ), + "+r" ( reg3 ), "+r" ( reg4 ), "+r" ( reg5 ) + : "r" ( &xen->hypercall[hypercall] ) + : "memory" ); + return retval; +} + +#endif /* _BITS_XEN_H */ diff --git a/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h b/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h index adb00a686..9e68f4e78 100644 --- a/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h +++ b/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h @@ -28,6 +28,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Page shift */ +#define PAGE_SHIFT 12 + /* * Physical<->Bus and Bus<->I/O address mappings * @@ -45,7 +48,7 @@ IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) { static inline __always_inline void * IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) { - return phys_to_virt ( bus_addr ); + return ( bus_addr ? phys_to_virt ( bus_addr ) : NULL ); } static inline __always_inline void diff --git a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c index 280e33535..3daefd00a 100644 --- a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c +++ b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c @@ -22,7 +22,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <ipxe/init.h> #include <ipxe/efi/efi.h> -#include <ipxe/efi/efi_snp.h> /** * EFI entry point @@ -43,8 +42,5 @@ EFI_STATUS EFIAPI _efidrv_start ( EFI_HANDLE image_handle, initialise(); startup(); - /* Release network devices for use via SNP */ - efi_snp_release(); - return 0; } diff --git a/roms/ipxe/src/arch/x86/prefix/efiprefix.c b/roms/ipxe/src/arch/x86/prefix/efiprefix.c index eb8aa738a..b0bf99c65 100644 --- a/roms/ipxe/src/arch/x86/prefix/efiprefix.c +++ b/roms/ipxe/src/arch/x86/prefix/efiprefix.c @@ -21,7 +21,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <errno.h> +#include <ipxe/device.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_snp.h> +#include <ipxe/efi/efi_autoboot.h> /** * EFI entry point @@ -39,6 +43,12 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) goto err_init; + /* Record autoboot device (if any) */ + efi_set_autoboot(); + + /* Claim SNP devices for use by iPXE */ + efi_snp_claim(); + /* Call to main() */ if ( ( rc = main() ) != 0 ) { efirc = EFIRC ( rc ); @@ -46,7 +56,41 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, } err_main: + efi_snp_release(); efi_loaded_image->Unload ( image_handle ); + efi_driver_reconnect_all(); err_init: return efirc; } + +/** + * Probe EFI root bus + * + * @v rootdev EFI root device + */ +static int efi_probe ( struct root_device *rootdev __unused ) { + + return efi_driver_connect_all(); +} + +/** + * Remove EFI root bus + * + * @v rootdev EFI root device + */ +static void efi_remove ( struct root_device *rootdev __unused ) { + + efi_driver_disconnect_all(); +} + +/** EFI root device driver */ +static struct root_driver efi_root_driver = { + .probe = efi_probe, + .remove = efi_remove, +}; + +/** EFI root device */ +struct root_device efi_root_device __root_device = { + .dev = { .name = "EFI" }, + .driver = &efi_root_driver, +}; diff --git a/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h b/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h new file mode 100644 index 000000000..a5816ac35 --- /dev/null +++ b/roms/ipxe/src/arch/x86_64/include/ipxe/msr.h @@ -0,0 +1,43 @@ +#ifndef _IPXE_MSR_H +#define _IPXE_MSR_H + +/** @file + * + * Model-specific registers + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Read model-specific register + * + * @v msr Model-specific register + * @ret value Value + */ +static inline __attribute__ (( always_inline )) uint64_t +rdmsr ( unsigned int msr ) { + uint32_t high; + uint32_t low; + + __asm__ __volatile__ ( "rdmsr" : + "=d" ( high ), "=a" ( low ) : "c" ( msr ) ); + return ( ( ( ( uint64_t ) high ) << 32 ) | low ); +} + +/** + * Write model-specific register + * + * @v msr Model-specific register + * @v value Value + */ +static inline __attribute__ (( always_inline )) void +wrmsr ( unsigned int msr, uint64_t value ) { + uint32_t high = ( value >> 32 ); + uint32_t low = ( value >> 0 ); + + __asm__ __volatile__ ( "wrmsr" : : + "c" ( msr ), "d" ( high ), "a" ( low ) ); +} + +#endif /* _IPXE_MSR_H */ diff --git a/roms/ipxe/src/config/colour.h b/roms/ipxe/src/config/colour.h index c75f65e6d..57d20c1db 100644 --- a/roms/ipxe/src/config/colour.h +++ b/roms/ipxe/src/config/colour.h @@ -30,6 +30,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define COLOR_PXE_FG COLOR_BLACK #define COLOR_PXE_BG COLOR_WHITE +#include <config/named.h> +#include NAMED_CONFIG(colour.h) #include <config/local/colour.h> +#include LOCAL_NAMED_CONFIG(colour.h) #endif /* CONFIG_COLOUR_H */ diff --git a/roms/ipxe/src/config/console.h b/roms/ipxe/src/config/console.h index 5d2cc1dce..908ec5a0b 100644 --- a/roms/ipxe/src/config/console.h +++ b/roms/ipxe/src/config/console.h @@ -28,6 +28,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define LOG_LEVEL LOG_NONE +#include <config/named.h> +#include NAMED_CONFIG(console.h) #include <config/local/console.h> +#include LOCAL_NAMED_CONFIG(console.h) #endif /* CONFIG_CONSOLE_H */ diff --git a/roms/ipxe/src/config/crypto.h b/roms/ipxe/src/config/crypto.h index 95c73d477..1e021b0fb 100644 --- a/roms/ipxe/src/config/crypto.h +++ b/roms/ipxe/src/config/crypto.h @@ -17,6 +17,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #define TIMESTAMP_ERROR_MARGIN ( ( 12 * 60 + 30 ) * 60 ) +#include <config/named.h> +#include NAMED_CONFIG(crypto.h) #include <config/local/crypto.h> +#include LOCAL_NAMED_CONFIG(crypto.h) #endif /* CONFIG_CRYPTO_H */ diff --git a/roms/ipxe/src/config/general.h b/roms/ipxe/src/config/general.h index 72cfc3b86..539203457 100644 --- a/roms/ipxe/src/config/general.h +++ b/roms/ipxe/src/config/general.h @@ -182,6 +182,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #undef GDBUDP /* Remote GDB debugging over UDP * (both may be set) */ +#include <config/named.h> +#include NAMED_CONFIG(general.h) #include <config/local/general.h> +#include LOCAL_NAMED_CONFIG(general.h) #endif /* CONFIG_GENERAL_H */ diff --git a/roms/ipxe/src/config/named.h b/roms/ipxe/src/config/named.h new file mode 100644 index 000000000..36efdabdd --- /dev/null +++ b/roms/ipxe/src/config/named.h @@ -0,0 +1,26 @@ +#ifndef CONFIG_NAMED_H +#define CONFIG_NAMED_H + +/** @file + * + * Named configurations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* config/<name>/<header>.h */ +#ifdef CONFIG +#define NAMED_CONFIG(_header) <config/CONFIG/_header> +#else +#define NAMED_CONFIG(_header) <config/_header> +#endif + +/* config/local/<name>/<header>.h */ +#ifdef LOCAL_CONFIG +#define LOCAL_NAMED_CONFIG(_header) <config/local/LOCAL_CONFIG/_header> +#else +#define LOCAL_NAMED_CONFIG(_header) <config/_header> +#endif + +#endif /* CONFIG_NAMED_H */ diff --git a/roms/ipxe/src/config/serial.h b/roms/ipxe/src/config/serial.h index 8bb9311f1..08368efdb 100644 --- a/roms/ipxe/src/config/serial.h +++ b/roms/ipxe/src/config/serial.h @@ -32,6 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define COMSTOP 1 /* Stop bits */ #endif +#include <config/named.h> +#include NAMED_CONFIG(serial.h) #include <config/local/serial.h> +#include LOCAL_NAMED_CONFIG(serial.h) #endif /* CONFIG_SERIAL_H */ diff --git a/roms/ipxe/src/config/settings.h b/roms/ipxe/src/config/settings.h index b06f2901b..42fe9cc81 100644 --- a/roms/ipxe/src/config/settings.h +++ b/roms/ipxe/src/config/settings.h @@ -14,6 +14,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define MEMMAP_SETTINGS /* Memory map settings */ //#define VMWARE_SETTINGS /* VMware GuestInfo settings */ +#include <config/named.h> +#include NAMED_CONFIG(settings.h) #include <config/local/settings.h> +#include LOCAL_NAMED_CONFIG(settings.h) #endif /* CONFIG_SETTINGS_H */ diff --git a/roms/ipxe/src/config/sideband.h b/roms/ipxe/src/config/sideband.h index 2e2a8d419..039bb5d09 100644 --- a/roms/ipxe/src/config/sideband.h +++ b/roms/ipxe/src/config/sideband.h @@ -11,6 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */ +#include <config/named.h> +#include NAMED_CONFIG(sideband.h) #include <config/local/sideband.h> +#include LOCAL_NAMED_CONFIG(sideband.h) #endif /* CONFIG_SIDEBAND_H */ diff --git a/roms/ipxe/src/config/vbox/README b/roms/ipxe/src/config/vbox/README new file mode 100644 index 000000000..b6f2da950 --- /dev/null +++ b/roms/ipxe/src/config/vbox/README @@ -0,0 +1,18 @@ +Build using this command line: + +make CONFIG=vbox bin/intel--virtio-net--pcnet32.isarom + +Max size of a VirtualBox ROM is 56KB, 57344 bytes. There should be no need +to pad the image as long as the binary is smaller or equal to this size. + +To use the ROM in VirtualBox you need to enable it using this command: + +vboxmanage setextradata global \ + VBoxInternal/Devices/pcbios/0/Config/LanBootRom \ + /absolute/path/to/intel--virtio-net--pcnet32.isarom + +NB: If you build the ROM using the .rom prefix then it'll be built as a PCI +ROM, which won't work properly in VirtualBox. The error message you'll see +is "No more network devices", which is somewhat confusing. If you enter the +shell and use the "autoboot" command things will work as intended. Remember +to always build as a .isarom to avoid this issue. diff --git a/roms/ipxe/src/config/vbox/colour.h b/roms/ipxe/src/config/vbox/colour.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/ipxe/src/config/vbox/colour.h diff --git a/roms/ipxe/src/config/vbox/console.h b/roms/ipxe/src/config/vbox/console.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/ipxe/src/config/vbox/console.h diff --git a/roms/ipxe/src/config/vbox/crypto.h b/roms/ipxe/src/config/vbox/crypto.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/ipxe/src/config/vbox/crypto.h diff --git a/roms/ipxe/src/config/vbox/general.h b/roms/ipxe/src/config/vbox/general.h new file mode 100644 index 000000000..27d15daf2 --- /dev/null +++ b/roms/ipxe/src/config/vbox/general.h @@ -0,0 +1,27 @@ +/* Disabled from config/defaults/pcbios.h */ + +#undef IMAGE_ELF +#undef SANBOOT_PROTO_ISCSI +#undef SANBOOT_PROTO_AOE +#undef SANBOOT_PROTO_IB_SRP +#undef SANBOOT_PROTO_FCP +#undef REBOOT_CMD +#undef CPUID_CMD + +/* Disabled from config/general.h */ + +#undef DOWNLOAD_PROTO_HTTP +#undef CRYPTO_80211_WEP +#undef CRYPTO_80211_WPA +#undef CRYPTO_80211_WPA2 +#undef IWMGMT_CMD +#undef FCMGMT_CMD +#undef SANBOOT_CMD +#undef MENU_CMD +#undef LOGIN_CMD +#undef SYNC_CMD + +/* Ensure ROM banner is not displayed */ + +#undef ROM_BANNER_TIMEOUT +#define ROM_BANNER_TIMEOUT 0 diff --git a/roms/ipxe/src/config/vbox/serial.h b/roms/ipxe/src/config/vbox/serial.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/ipxe/src/config/vbox/serial.h diff --git a/roms/ipxe/src/config/vbox/settings.h b/roms/ipxe/src/config/vbox/settings.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/ipxe/src/config/vbox/settings.h diff --git a/roms/ipxe/src/config/vbox/sideband.h b/roms/ipxe/src/config/vbox/sideband.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roms/ipxe/src/config/vbox/sideband.h diff --git a/roms/ipxe/src/core/debug.c b/roms/ipxe/src/core/debug.c index 2161f9731..7ded47089 100644 --- a/roms/ipxe/src/core/debug.c +++ b/roms/ipxe/src/core/debug.c @@ -119,13 +119,24 @@ void dbg_hex_dump_da ( unsigned long dispaddr, const void *data, } /** + * Base message stream colour + * + * We default to using 31 (red foreground) as the base colour. + */ +#ifndef DBGCOL_MIN +#define DBGCOL_MIN 31 +#endif + +/** * Maximum number of separately coloured message streams * * Six is the realistic maximum; there are 8 basic ANSI colours, one * of which will be the terminal default and one of which will be * invisible on the terminal because it matches the background colour. */ -#define NUM_AUTO_COLOURS 6 +#ifndef DBGCOL_MAX +#define DBGCOL_MAX ( DBGCOL_MIN + 6 - 1 ) +#endif /** A colour assigned to an autocolourised debug message stream */ struct autocolour { @@ -142,7 +153,7 @@ struct autocolour { * @ret colour Colour ID */ static int dbg_autocolour ( unsigned long stream ) { - static struct autocolour acs[NUM_AUTO_COLOURS]; + static struct autocolour acs[ DBGCOL_MAX - DBGCOL_MIN + 1 ]; static unsigned long use; unsigned int i; unsigned int oldest; @@ -180,7 +191,7 @@ static int dbg_autocolour ( unsigned long stream ) { */ void dbg_autocolourise ( unsigned long stream ) { dbg_printf ( "\033[%dm", - ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) ); + ( stream ? ( DBGCOL_MIN + dbg_autocolour ( stream ) ) :0)); } /** diff --git a/roms/ipxe/src/core/main.c b/roms/ipxe/src/core/main.c index c55ca26cb..db09e4c39 100644 --- a/roms/ipxe/src/core/main.c +++ b/roms/ipxe/src/core/main.c @@ -17,8 +17,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> #include <stdio.h> #include <ipxe/init.h> +#include <ipxe/version.h> #include <usr/autoboot.h> -#include <config/general.h> /** * Main entry point @@ -31,7 +31,7 @@ __asmcall int main ( void ) { initialise(); /* Some devices take an unreasonably long time to initialise */ - printf ( PRODUCT_SHORT_NAME " initialising devices..." ); + printf ( "%s initialising devices...", product_short_name ); startup(); printf ( "ok\n" ); diff --git a/roms/ipxe/src/core/malloc.c b/roms/ipxe/src/core/malloc.c index 56ca7edc6..d9c07495d 100644 --- a/roms/ipxe/src/core/malloc.c +++ b/roms/ipxe/src/core/malloc.c @@ -187,6 +187,42 @@ static inline void valgrind_make_blocks_noaccess ( void ) { } /** + * Check integrity of the blocks in the free list + * + */ +static inline void check_blocks ( void ) { + struct memory_block *block; + struct memory_block *prev = NULL; + + if ( ! ASSERTING ) + return; + + list_for_each_entry ( block, &free_blocks, list ) { + + /* Check that list structure is intact */ + list_check ( &block->list ); + + /* Check that block size is not too small */ + assert ( block->size >= sizeof ( *block ) ); + assert ( block->size >= MIN_MEMBLOCK_SIZE ); + + /* Check that block does not wrap beyond end of address space */ + assert ( ( ( void * ) block + block->size ) > + ( ( void * ) block ) ); + + /* Check that blocks remain in ascending order, and + * that adjacent blocks have been merged. + */ + if ( prev ) { + assert ( ( ( void * ) block ) > ( ( void * ) prev ) ); + assert ( ( ( void * ) block ) > + ( ( ( void * ) prev ) + prev->size ) ); + } + prev = block; + } +} + +/** * Discard some cached data * * @ret discarded Number of cached items discarded @@ -237,7 +273,12 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) { struct memory_block *post; struct memory_block *ptr; + /* Sanity checks */ + assert ( size != 0 ); + assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) ); + valgrind_make_blocks_defined(); + check_blocks(); /* Round up size to multiple of MIN_MEMBLOCK_SIZE and * calculate alignment mask. @@ -245,7 +286,8 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) { size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 ); align_mask = ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 ); - DBG ( "Allocating %#zx (aligned %#zx+%zx)\n", size, align, offset ); + DBGC2 ( &heap, "Allocating %#zx (aligned %#zx+%zx)\n", + size, align, offset ); while ( 1 ) { /* Search through blocks for the first one with enough space */ list_for_each_entry ( block, &free_blocks, list ) { @@ -261,10 +303,10 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) { pre = block; block = ( ( ( void * ) pre ) + pre_size ); post = ( ( ( void * ) block ) + size ); - DBG ( "[%p,%p) -> [%p,%p) + [%p,%p)\n", pre, - ( ( ( void * ) pre ) + pre->size ), - pre, block, post, - ( ( ( void * ) pre ) + pre->size ) ); + DBGC2 ( &heap, "[%p,%p) -> [%p,%p) + [%p,%p)\n", + pre, ( ( ( void * ) pre ) + pre->size ), + pre, block, post, + ( ( ( void * ) pre ) + pre->size ) ); /* If there is a "post" block, add it in to * the free list. Leak it if it is too small * (which can happen only at the very end of @@ -291,8 +333,8 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) { /* Update total free memory */ freemem -= size; /* Return allocated block */ - DBG ( "Allocated [%p,%p)\n", block, - ( ( ( void * ) block ) + size ) ); + DBGC2 ( &heap, "Allocated [%p,%p)\n", block, + ( ( ( void * ) block ) + size ) ); ptr = block; goto done; } @@ -301,14 +343,15 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) { /* Try discarding some cached data to free up memory */ if ( ! discard_cache() ) { /* Nothing available to discard */ - DBG ( "Failed to allocate %#zx (aligned %#zx)\n", - size, align ); + DBGC ( &heap, "Failed to allocate %#zx (aligned " + "%#zx)\n", size, align ); ptr = NULL; goto done; } } done: + check_blocks(); valgrind_make_blocks_noaccess(); return ptr; } @@ -333,17 +376,38 @@ void free_memblock ( void *ptr, size_t size ) { return; valgrind_make_blocks_defined(); + check_blocks(); /* Round up size to match actual size that alloc_memblock() * would have used. */ + assert ( size != 0 ); size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 ); freeing = ptr; VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) ); - freeing->size = size; - DBG ( "Freeing [%p,%p)\n", freeing, ( ( ( void * ) freeing ) + size )); + DBGC2 ( &heap, "Freeing [%p,%p)\n", + freeing, ( ( ( void * ) freeing ) + size ) ); + + /* Check that this block does not overlap the free list */ + if ( ASSERTING ) { + list_for_each_entry ( block, &free_blocks, list ) { + if ( ( ( ( void * ) block ) < + ( ( void * ) freeing + size ) ) && + ( ( void * ) freeing < + ( ( void * ) block + block->size ) ) ) { + assert ( 0 ); + DBGC ( &heap, "Double free of [%p,%p) " + "overlapping [%p,%p) detected from %p\n", + freeing, + ( ( ( void * ) freeing ) + size ), block, + ( ( void * ) block + block->size ), + __builtin_return_address ( 0 ) ); + } + } + } /* Insert/merge into free list */ + freeing->size = size; list_for_each_entry_safe ( block, tmp, &free_blocks, list ) { /* Calculate gaps before and after the "freeing" block */ gap_before = ( ( ( void * ) freeing ) - @@ -352,10 +416,11 @@ void free_memblock ( void *ptr, size_t size ) { ( ( ( void * ) freeing ) + freeing->size ) ); /* Merge with immediately preceding block, if possible */ if ( gap_before == 0 ) { - DBG ( "[%p,%p) + [%p,%p) -> [%p,%p)\n", block, - ( ( ( void * ) block ) + block->size ), freeing, - ( ( ( void * ) freeing ) + freeing->size ),block, - ( ( ( void * ) freeing ) + freeing->size ) ); + DBGC2 ( &heap, "[%p,%p) + [%p,%p) -> [%p,%p)\n", block, + ( ( ( void * ) block ) + block->size ), freeing, + ( ( ( void * ) freeing ) + freeing->size ), + block, + ( ( ( void * ) freeing ) + freeing->size ) ); block->size += size; list_del ( &block->list ); freeing = block; @@ -369,13 +434,14 @@ void free_memblock ( void *ptr, size_t size ) { * possible, merge the following block into the "freeing" * block. */ - DBG ( "[%p,%p)\n", freeing, ( ( ( void * ) freeing ) + freeing->size)); + DBGC2 ( &heap, "[%p,%p)\n", + freeing, ( ( ( void * ) freeing ) + freeing->size ) ); list_add_tail ( &freeing->list, &block->list ); if ( gap_after == 0 ) { - DBG ( "[%p,%p) + [%p,%p) -> [%p,%p)\n", freeing, - ( ( ( void * ) freeing ) + freeing->size ), block, - ( ( ( void * ) block ) + block->size ), freeing, - ( ( ( void * ) block ) + block->size ) ); + DBGC2 ( &heap, "[%p,%p) + [%p,%p) -> [%p,%p)\n", freeing, + ( ( ( void * ) freeing ) + freeing->size ), block, + ( ( ( void * ) block ) + block->size ), freeing, + ( ( ( void * ) block ) + block->size ) ); freeing->size += block->size; list_del ( &block->list ); } @@ -383,6 +449,7 @@ void free_memblock ( void *ptr, size_t size ) { /* Update free memory counter */ freemem += size; + check_blocks(); valgrind_make_blocks_noaccess(); } @@ -440,6 +507,7 @@ void * realloc ( void *old_ptr, size_t new_size ) { data ); VALGRIND_MAKE_MEM_DEFINED ( old_block, offsetof ( struct autosized_block, data ) ); old_total_size = old_block->size; + assert ( old_total_size != 0 ); old_size = ( old_total_size - offsetof ( struct autosized_block, data ) ); memcpy ( new_ptr, old_ptr, @@ -449,6 +517,10 @@ void * realloc ( void *old_ptr, size_t new_size ) { VALGRIND_FREELIKE_BLOCK ( old_ptr, 0 ); } + if ( ASSERTED ) { + DBGC ( &heap, "Possible memory corruption detected from %p\n", + __builtin_return_address ( 0 ) ); + } return new_ptr; } @@ -462,7 +534,14 @@ void * realloc ( void *old_ptr, size_t new_size ) { * will be aligned to at least a multiple of sizeof(void*). */ void * malloc ( size_t size ) { - return realloc ( NULL, size ); + void *ptr; + + ptr = realloc ( NULL, size ); + if ( ASSERTED ) { + DBGC ( &heap, "Possible memory corruption detected from %p\n", + __builtin_return_address ( 0 ) ); + } + return ptr; } /** @@ -476,7 +555,12 @@ void * malloc ( size_t size ) { * If @c ptr is NULL, no action is taken. */ void free ( void *ptr ) { + realloc ( ptr, 0 ); + if ( ASSERTED ) { + DBGC ( &heap, "Possible memory corruption detected from %p\n", + __builtin_return_address ( 0 ) ); + } } /** @@ -496,6 +580,10 @@ void * zalloc ( size_t size ) { data = malloc ( size ); if ( data ) memset ( data, 0, size ); + if ( ASSERTED ) { + DBGC ( &heap, "Possible memory corruption detected from %p\n", + __builtin_return_address ( 0 ) ); + } return data; } diff --git a/roms/ipxe/src/core/pinger.c b/roms/ipxe/src/core/pinger.c index c912a64d7..31ea2ce1c 100644 --- a/roms/ipxe/src/core/pinger.c +++ b/roms/ipxe/src/core/pinger.c @@ -68,10 +68,16 @@ struct pinger { size_t len; /** Current sequence number */ uint16_t sequence; + /** Response for current sequence number is still pending */ + int pending; + /** Number of remaining expiry events (zero to continue indefinitely) */ + unsigned int remaining; + /** Return status */ + int rc; /** Callback function * - * @v src Source socket address + * @v src Source socket address, or NULL * @v sequence Sequence number * @v len Payload length * @v rc Status code @@ -159,6 +165,16 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) { struct io_buffer *iobuf; int rc; + /* If no response has been received, notify the callback function */ + if ( pinger->pending && pinger->callback ) + pinger->callback ( NULL, pinger->sequence, 0, -ETIMEDOUT ); + + /* Check for termination */ + if ( pinger->remaining && ( --pinger->remaining == 0 ) ) { + pinger_close ( pinger, pinger->rc ); + return; + } + /* Increase sequence number */ pinger->sequence++; @@ -166,6 +182,7 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) { * case the transmission attempt fails. */ start_timer_fixed ( &pinger->timer, pinger->timeout ); + pinger->pending = 1; /* Allocate I/O buffer */ iobuf = xfer_alloc_iob ( &pinger->xfer, pinger->len ); @@ -203,29 +220,56 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf, struct xfer_metadata *meta ) { size_t len = iob_len ( iobuf ); uint16_t sequence = meta->offset; + int terminate = 0; int rc; + /* Clear response pending flag, if applicable */ + if ( sequence == pinger->sequence ) + pinger->pending = 0; + /* Check for errors */ if ( len != pinger->len ) { + /* Incorrect length: terminate immediately if we are + * not pinging indefinitely. + */ DBGC ( pinger, "PINGER %p received incorrect length %zd " "(expected %zd)\n", pinger, len, pinger->len ); rc = -EPROTO_LEN; + terminate = ( pinger->remaining != 0 ); } else if ( ( rc = pinger_verify ( pinger, iobuf->data ) ) != 0 ) { + /* Incorrect data: terminate immediately if we are not + * pinging indefinitely. + */ DBGC ( pinger, "PINGER %p received incorrect data:\n", pinger ); DBGC_HDA ( pinger, 0, iobuf->data, iob_len ( iobuf ) ); + terminate = ( pinger->remaining != 0 ); } else if ( sequence != pinger->sequence ) { + /* Incorrect sequence number (probably a delayed response): + * report via callback but otherwise ignore. + */ DBGC ( pinger, "PINGER %p received sequence %d (expected %d)\n", pinger, sequence, pinger->sequence ); rc = -EPROTO_SEQ; + terminate = 0; } else { + /* Success: record that a packet was successfully received, + * and terminate if we expect to send no further packets. + */ rc = 0; + pinger->rc = 0; + terminate = ( pinger->remaining == 1 ); } /* Discard I/O buffer */ free_iob ( iobuf ); - /* Notify callback function */ - pinger->callback ( meta->src, sequence, len, rc ); + /* Notify callback function, if applicable */ + if ( pinger->callback ) + pinger->callback ( meta->src, sequence, len, rc ); + + /* Terminate if applicable */ + if ( terminate ) + pinger_close ( pinger, rc ); return rc; } @@ -257,10 +301,12 @@ static struct interface_descriptor pinger_job_desc = * @v hostname Hostname to ping * @v timeout Timeout (in ticks) * @v len Payload length + * @v count Number of packets to send (or zero for no limit) + * @v callback Callback function (or NULL) * @ret rc Return status code */ int create_pinger ( struct interface *job, const char *hostname, - unsigned long timeout, size_t len, + unsigned long timeout, size_t len, unsigned int count, void ( * callback ) ( struct sockaddr *src, unsigned int sequence, size_t len, int rc ) ) { @@ -281,7 +327,9 @@ int create_pinger ( struct interface *job, const char *hostname, timer_init ( &pinger->timer, pinger_expired, &pinger->refcnt ); pinger->timeout = timeout; pinger->len = len; + pinger->remaining = ( count ? ( count + 1 /* Initial packet */ ) : 0 ); pinger->callback = callback; + pinger->rc = -ETIMEDOUT; /* Open socket */ if ( ( rc = xfer_open_named_socket ( &pinger->xfer, SOCK_ECHO, NULL, diff --git a/roms/ipxe/src/core/profile.c b/roms/ipxe/src/core/profile.c index ceaadd6ce..150e6b273 100644 --- a/roms/ipxe/src/core/profile.c +++ b/roms/ipxe/src/core/profile.c @@ -40,6 +40,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * to avoid the use of floating-point instructions. */ +/** Accumulated time excluded from profiling */ +unsigned long profile_excluded; + /** * Format a hex fraction (for debugging) * diff --git a/roms/ipxe/src/core/string.c b/roms/ipxe/src/core/string.c index 190007a47..e53c283c2 100644 --- a/roms/ipxe/src/core/string.c +++ b/roms/ipxe/src/core/string.c @@ -337,11 +337,9 @@ void * memchr(const void *s, int c, size_t n) char * strndup(const char *s, size_t n) { - size_t len = strlen(s); + size_t len = strnlen(s,n); char *new; - if (len>n) - len = n; new = malloc(len+1); if (new) { new[len] = '\0'; diff --git a/roms/ipxe/src/core/version.c b/roms/ipxe/src/core/version.c index 1aa22d8ec..1e1e9daca 100644 --- a/roms/ipxe/src/core/version.c +++ b/roms/ipxe/src/core/version.c @@ -25,12 +25,35 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +#include <wchar.h> #include <ipxe/features.h> #include <ipxe/version.h> +#include <config/general.h> + +/** + * Create wide-character version of string + * + * @v string String + * @ret wstring Wide-character version of string + */ +#define WSTRING( string ) _WSTRING ( string ) +#define _WSTRING( string ) L ## string /** Version number feature */ FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH ); +/** Build timestamp (generated by linker) */ +extern char _build_timestamp[]; + +/** Build ID (generated by linker) */ +extern char _build_id[]; + +/** Build timestamp */ +unsigned long build_timestamp = ( ( unsigned long ) _build_timestamp ); + +/** Build ID */ +unsigned long build_id = ( ( unsigned long ) _build_id ); + /** Product major version */ const int product_major_version = VERSION_MAJOR; @@ -38,4 +61,29 @@ const int product_major_version = VERSION_MAJOR; const int product_minor_version = VERSION_MINOR; /** Product version string */ -const char *product_version = VERSION; +const char product_version[] = VERSION; + +/** Product name string */ +const char product_name[] = PRODUCT_NAME; + +/** Product short name string */ +const char product_short_name[] = PRODUCT_SHORT_NAME; + +/** Build name string */ +const char build_name[] = BUILD_NAME; + +/** Wide-character product version string */ +const wchar_t product_wversion[] = WSTRING ( VERSION ); + +/** Wide-character product name string */ +const wchar_t product_wname[] = WSTRING ( PRODUCT_NAME ); + +/** Wide-character product short name string */ +const wchar_t product_short_wname[] = WSTRING ( PRODUCT_SHORT_NAME ); + +/** Wide-character build name string */ +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; diff --git a/roms/ipxe/src/crypto/ocsp.c b/roms/ipxe/src/crypto/ocsp.c index d4815a1b5..66e47c57e 100644 --- a/roms/ipxe/src/crypto/ocsp.c +++ b/roms/ipxe/src/crypto/ocsp.c @@ -405,12 +405,17 @@ static int ocsp_compare_responder_name ( struct ocsp_check *ocsp, static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp, struct x509_certificate *cert ) { struct ocsp_responder *responder = &ocsp->response.responder; + struct asn1_cursor key_hash; uint8_t ctx[SHA1_CTX_SIZE]; uint8_t digest[SHA1_DIGEST_SIZE]; int difference; + /* Enter responder key hash */ + memcpy ( &key_hash, &responder->id, sizeof ( key_hash ) ); + asn1_enter ( &key_hash, ASN1_OCTET_STRING ); + /* Sanity check */ - difference = ( sizeof ( digest ) - responder->id.len ); + difference = ( sizeof ( digest ) - key_hash.len ); if ( difference ) return difference; @@ -421,8 +426,8 @@ static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp, cert->subject.public_key.raw_bits.len ); digest_final ( &sha1_algorithm, ctx, digest ); - /* Compare responder ID with SHA1 hash of certificate's public key */ - return memcmp ( digest, responder->id.data, sizeof ( digest ) ); + /* Compare responder key hash with hash of certificate's public key */ + return memcmp ( digest, key_hash.data, sizeof ( digest ) ); } /** diff --git a/roms/ipxe/src/crypto/x509.c b/roms/ipxe/src/crypto/x509.c index 0502efa28..4a02dad14 100644 --- a/roms/ipxe/src/crypto/x509.c +++ b/roms/ipxe/src/crypto/x509.c @@ -33,6 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/rsa.h> #include <ipxe/rootcert.h> #include <ipxe/certstore.h> +#include <ipxe/socket.h> +#include <ipxe/in.h> #include <ipxe/x509.h> #include <config/crypto.h> @@ -457,7 +459,7 @@ static int x509_parse_basic_constraints ( struct x509_certificate *cert, return -EINVAL; } basic->path_len = path_len; - DBGC2 ( cert, "X509 %p path length constraint is %u\n", + DBGC2 ( cert, "X509 %p path length constraint is %d\n", cert, basic->path_len ); } @@ -1418,6 +1420,57 @@ static int x509_check_dnsname ( struct x509_certificate *cert, } /** + * Check X.509 certificate alternative iPAddress + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @v name Name + * @ret rc Return status code + */ +static int x509_check_ipaddress ( struct x509_certificate *cert, + const struct asn1_cursor *raw, + const char *name ) { + struct sockaddr sa; + sa_family_t family; + const void *address; + int rc; + + /* Determine address family */ + if ( raw->len == sizeof ( struct in_addr ) ) { + struct sockaddr_in *sin = ( ( struct sockaddr_in * ) &sa ); + family = AF_INET; + address = &sin->sin_addr; + } else if ( raw->len == sizeof ( struct in6_addr ) ) { + struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) &sa ); + family = AF_INET6; + address = &sin6->sin6_addr; + } else { + DBGC ( cert, "X509 %p \"%s\" has iPAddress with unexpected " + "length %zd\n", cert, x509_name ( cert ), raw->len ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL; + } + + /* Attempt to convert name to a socket address */ + if ( ( rc = sock_aton ( name, &sa ) ) != 0 ) { + DBGC2 ( cert, "X509 %p \"%s\" cannot parse \"%s\" as " + "iPAddress: %s\n", cert, x509_name ( cert ), name, + strerror ( rc ) ); + return rc; + } + if ( sa.sa_family != family ) + return -ENOENT; + + /* Compare addresses */ + if ( memcmp ( address, raw->data, raw->len ) != 0 ) + return -ENOENT; + + DBGC2 ( cert, "X509 %p \"%s\" found iPAddress match for \"%s\"\n", + cert, x509_name ( cert ), sock_ntoa ( &sa ) ); + return 0; +} + +/** * Check X.509 certificate alternative name * * @v cert X.509 certificate @@ -1440,6 +1493,8 @@ static int x509_check_alt_name ( struct x509_certificate *cert, switch ( type ) { case X509_GENERAL_NAME_DNS : return x509_check_dnsname ( cert, &alt_name, name ); + case X509_GENERAL_NAME_IP : + return x509_check_ipaddress ( cert, &alt_name, name ); default: DBGC2 ( cert, "X509 %p \"%s\" unknown name of type %#02x:\n", cert, x509_name ( cert ), type ); diff --git a/roms/ipxe/src/drivers/block/ibft.c b/roms/ipxe/src/drivers/block/ibft.c index 0700f8c4f..6aabd766a 100644 --- a/roms/ipxe/src/drivers/block/ibft.c +++ b/roms/ipxe/src/drivers/block/ibft.c @@ -102,17 +102,19 @@ static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) { /** * Fill in an IP address within iBFT from configuration setting * + * @v settings Parent settings block, or NULL * @v ipaddr IP address field * @v setting Configuration setting * @v count Maximum number of IP addresses */ -static void ibft_set_ipaddr_setting ( struct ibft_ipaddr *ipaddr, +static void ibft_set_ipaddr_setting ( struct settings *settings, + struct ibft_ipaddr *ipaddr, const struct setting *setting, unsigned int count ) { struct in_addr in[count]; unsigned int i; - fetch_ipv4_array_setting ( NULL, setting, in, count ); + fetch_ipv4_array_setting ( settings, setting, in, count ); for ( i = 0 ; i < count ; i++ ) { ibft_set_ipaddr ( &ipaddr[i], in[i] ); } @@ -176,12 +178,14 @@ static int ibft_set_string ( struct ibft_strings *strings, /** * Fill in a string field within iBFT from configuration setting * + * @v settings Parent settings block, or NULL * @v strings iBFT string block descriptor * @v string String field * @v setting Configuration setting * @ret rc Return status code */ -static int ibft_set_string_setting ( struct ibft_strings *strings, +static int ibft_set_string_setting ( struct settings *settings, + struct ibft_strings *strings, struct ibft_string *string, const struct setting *setting ) { struct settings *origin; @@ -189,7 +193,7 @@ static int ibft_set_string_setting ( struct ibft_strings *strings, int len; char *dest; - len = fetch_setting ( NULL, setting, &origin, &fetched, NULL, 0 ); + len = fetch_setting ( settings, setting, &origin, &fetched, NULL, 0 ); if ( len < 0 ) { string->offset = 0; string->len = 0; @@ -231,6 +235,8 @@ static int ibft_fill_nic ( struct ibft_nic *nic, struct ll_protocol *ll_protocol = netdev->ll_protocol; struct in_addr netmask_addr = { 0 }; unsigned int netmask_count = 0; + struct settings *parent = netdev_settings ( netdev ); + struct settings *origin; int rc; /* Fill in common header */ @@ -240,24 +246,30 @@ static int ibft_fill_nic ( struct ibft_nic *nic, nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID | IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ); + /* Determine origin of IP address */ + fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 ); + nic->origin = ( ( origin == parent ) ? + IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); + DBG ( "iBFT NIC origin = %d\n", nic->origin ); + /* Extract values from configuration settings */ - ibft_set_ipaddr_setting ( &nic->ip_address, &ip_setting, 1 ); + ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 ); DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) ); - ibft_set_ipaddr_setting ( &nic->gateway, &gateway_setting, 1 ); + ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 ); DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) ); - ibft_set_ipaddr_setting ( &nic->dns[0], &dns_setting, + ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting, ( sizeof ( nic->dns ) / sizeof ( nic->dns[0] ) ) ); DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) ); DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) ); - if ( ( rc = ibft_set_string_setting ( strings, &nic->hostname, + if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname, &hostname_setting ) ) != 0 ) return rc; DBG ( "iBFT NIC hostname = %s\n", ibft_string ( strings, &nic->hostname ) ); /* Derive subnet mask prefix from subnet mask */ - fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr ); + fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr ); while ( netmask_addr.s_addr ) { if ( netmask_addr.s_addr & 0x1 ) netmask_count++; diff --git a/roms/ipxe/src/drivers/block/scsi.c b/roms/ipxe/src/drivers/block/scsi.c index 4245f019b..64d692986 100644 --- a/roms/ipxe/src/drivers/block/scsi.c +++ b/roms/ipxe/src/drivers/block/scsi.c @@ -132,6 +132,33 @@ int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ) { return 0; } +/** + * Parse SCSI sense data + * + * @v data Raw sense data + * @v len Length of raw sense data + * @v sense Descriptor-format sense data to fill in + */ +void scsi_parse_sense ( const void *data, size_t len, + struct scsi_sns_descriptor *sense ) { + const union scsi_sns *sns = data; + + /* Avoid returning uninitialised data */ + memset ( sense, 0, sizeof ( *sense ) ); + + /* Copy, assuming descriptor-format data */ + if ( len < sizeof ( sns->desc ) ) + return; + memcpy ( sense, &sns->desc, sizeof ( *sense ) ); + + /* Convert fixed-format to descriptor-format, if applicable */ + if ( len < sizeof ( sns->fixed ) ) + return; + if ( ! SCSI_SENSE_FIXED ( sns->code ) ) + return; + sense->additional = sns->fixed.additional; +} + /****************************************************************************** * * Interface methods @@ -468,9 +495,10 @@ static void scsicmd_response ( struct scsi_command *scsicmd, underrun = -(response->overrun); DBGC ( scsidev, " underrun -%zd", underrun ); } - DBGC ( scsidev, " sense %02x:%02x:%08x\n", - response->sense.code, response->sense.key, - ntohl ( response->sense.info ) ); + DBGC ( scsidev, " sense %02x key %02x additional %04x\n", + ( response->sense.code & SCSI_SENSE_CODE_MASK ), + ( response->sense.key & SCSI_SENSE_KEY_MASK ), + ntohs ( response->sense.additional ) ); /* Construct error number from sense data */ rc = -EIO_SENSE ( response->sense.key & SCSI_SENSE_KEY_MASK ); diff --git a/roms/ipxe/src/drivers/block/srp.c b/roms/ipxe/src/drivers/block/srp.c index 70a97b2f9..7edf69ace 100644 --- a/roms/ipxe/src/drivers/block/srp.c +++ b/roms/ipxe/src/drivers/block/srp.c @@ -476,12 +476,14 @@ static int srp_rsp ( struct srp_device *srpdev, const struct srp_rsp *rsp = data; struct srp_command *srpcmd; struct scsi_rsp response; - const void *sense; ssize_t data_out_residual_count; ssize_t data_in_residual_count; /* Sanity check */ - if ( len < sizeof ( *rsp ) ) { + if ( ( len < sizeof ( *rsp ) ) || + ( len < ( sizeof ( *rsp ) + + srp_rsp_response_data_len ( rsp ) + + srp_rsp_sense_data_len ( rsp ) ) ) ) { DBGC ( srpdev, "SRP %p RSP too short (%zd bytes)\n", srpdev, len ); return -EINVAL; @@ -523,9 +525,8 @@ static int srp_rsp ( struct srp_device *srpdev, } else if ( rsp->valid & SRP_RSP_VALID_DIUNDER ) { response.overrun = -(data_in_residual_count); } - sense = srp_rsp_sense_data ( rsp ); - if ( sense ) - memcpy ( &response.sense, sense, sizeof ( response.sense ) ); + scsi_parse_sense ( srp_rsp_sense_data ( rsp ), + srp_rsp_sense_data_len ( rsp ), &response.sense ); /* Report SCSI response */ scsi_response ( &srpcmd->scsi, &response ); diff --git a/roms/ipxe/src/drivers/net/efi/nii.c b/roms/ipxe/src/drivers/net/efi/nii.c new file mode 100644 index 000000000..d0d7da95a --- /dev/null +++ b/roms/ipxe/src/drivers/net/efi/nii.c @@ -0,0 +1,1101 @@ +/* + * Copyright (C) 2014 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/umalloc.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_pci.h> +#include <ipxe/efi/efi_utils.h> +#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> +#include <ipxe/efi/IndustryStandard/Acpi10.h> +#include "nii.h" + +/** @file + * + * NII driver + * + */ + +/* Error numbers generated by NII */ +#define EIO_INVALID_CDB __einfo_error ( EINFO_EIO_INVALID_CDB ) +#define EINFO_EIO_INVALID_CDB \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_CDB, \ + "Invalid CDB" ) +#define EIO_INVALID_CPB __einfo_error ( EINFO_EIO_INVALID_CPB ) +#define EINFO_EIO_INVALID_CPB \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_CPB, \ + "Invalid CPB" ) +#define EIO_BUSY __einfo_error ( EINFO_EIO_BUSY ) +#define EINFO_EIO_BUSY \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_BUSY, \ + "Busy" ) +#define EIO_QUEUE_FULL __einfo_error ( EINFO_EIO_QUEUE_FULL ) +#define EINFO_EIO_QUEUE_FULL \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_QUEUE_FULL, \ + "Queue full" ) +#define EIO_ALREADY_STARTED __einfo_error ( EINFO_EIO_ALREADY_STARTED ) +#define EINFO_EIO_ALREADY_STARTED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_ALREADY_STARTED, \ + "Already started" ) +#define EIO_NOT_STARTED __einfo_error ( EINFO_EIO_NOT_STARTED ) +#define EINFO_EIO_NOT_STARTED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_STARTED, \ + "Not started" ) +#define EIO_NOT_SHUTDOWN __einfo_error ( EINFO_EIO_NOT_SHUTDOWN ) +#define EINFO_EIO_NOT_SHUTDOWN \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_SHUTDOWN, \ + "Not shutdown" ) +#define EIO_ALREADY_INITIALIZED __einfo_error ( EINFO_EIO_ALREADY_INITIALIZED ) +#define EINFO_EIO_ALREADY_INITIALIZED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_ALREADY_INITIALIZED, \ + "Already initialized" ) +#define EIO_NOT_INITIALIZED __einfo_error ( EINFO_EIO_NOT_INITIALIZED ) +#define EINFO_EIO_NOT_INITIALIZED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_INITIALIZED, \ + "Not initialized" ) +#define EIO_DEVICE_FAILURE __einfo_error ( EINFO_EIO_DEVICE_FAILURE ) +#define EINFO_EIO_DEVICE_FAILURE \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_DEVICE_FAILURE, \ + "Device failure" ) +#define EIO_NVDATA_FAILURE __einfo_error ( EINFO_EIO_NVDATA_FAILURE ) +#define EINFO_EIO_NVDATA_FAILURE \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NVDATA_FAILURE, \ + "Non-volatile data failure" ) +#define EIO_UNSUPPORTED __einfo_error ( EINFO_EIO_UNSUPPORTED ) +#define EINFO_EIO_UNSUPPORTED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_UNSUPPORTED, \ + "Unsupported" ) +#define EIO_BUFFER_FULL __einfo_error ( EINFO_EIO_BUFFER_FULL ) +#define EINFO_EIO_BUFFER_FULL \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_BUFFER_FULL, \ + "Buffer full" ) +#define EIO_INVALID_PARAMETER __einfo_error ( EINFO_EIO_INVALID_PARAMETER ) +#define EINFO_EIO_INVALID_PARAMETER \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_PARAMETER, \ + "Invalid parameter" ) +#define EIO_INVALID_UNDI __einfo_error ( EINFO_EIO_INVALID_UNDI ) +#define EINFO_EIO_INVALID_UNDI \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_INVALID_UNDI, \ + "Invalid UNDI" ) +#define EIO_IPV4_NOT_SUPPORTED __einfo_error ( EINFO_EIO_IPV4_NOT_SUPPORTED ) +#define EINFO_EIO_IPV4_NOT_SUPPORTED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_IPV4_NOT_SUPPORTED, \ + "IPv4 not supported" ) +#define EIO_IPV6_NOT_SUPPORTED __einfo_error ( EINFO_EIO_IPV6_NOT_SUPPORTED ) +#define EINFO_EIO_IPV6_NOT_SUPPORTED \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_IPV6_NOT_SUPPORTED, \ + "IPv6 not supported" ) +#define EIO_NOT_ENOUGH_MEMORY __einfo_error ( EINFO_EIO_NOT_ENOUGH_MEMORY ) +#define EINFO_EIO_NOT_ENOUGH_MEMORY \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NOT_ENOUGH_MEMORY, \ + "Not enough memory" ) +#define EIO_NO_DATA __einfo_error ( EINFO_EIO_NO_DATA ) +#define EINFO_EIO_NO_DATA \ + __einfo_uniqify ( EINFO_EIO, PXE_STATCODE_NO_DATA, \ + "No data" ) +#define EIO_STAT( stat ) \ + EUNIQ ( EINFO_EIO, -(stat), EIO_INVALID_CDB, EIO_INVALID_CPB, \ + EIO_BUSY, EIO_QUEUE_FULL, EIO_ALREADY_STARTED, \ + EIO_NOT_STARTED, EIO_NOT_SHUTDOWN, EIO_ALREADY_INITIALIZED, \ + EIO_NOT_INITIALIZED, EIO_DEVICE_FAILURE, EIO_NVDATA_FAILURE, \ + EIO_UNSUPPORTED, EIO_BUFFER_FULL, EIO_INVALID_PARAMETER, \ + EIO_INVALID_UNDI, EIO_IPV4_NOT_SUPPORTED, \ + EIO_IPV6_NOT_SUPPORTED, EIO_NOT_ENOUGH_MEMORY, EIO_NO_DATA ) + +/** Maximum PCI BAR + * + * This is defined in <ipxe/efi/IndustryStandard/Pci22.h>, but we + * can't #include that since it collides with <ipxe/pci.h>. + */ +#define PCI_MAX_BAR 6 + +/** An NII NIC */ +struct nii_nic { + /** EFI device */ + struct efi_device *efidev; + /** Network interface identifier protocol */ + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii; + /** !PXE structure */ + PXE_SW_UNDI *undi; + /** Entry point */ + EFIAPI VOID ( * issue ) ( UINT64 cdb ); + /** Generic device */ + struct device dev; + + /** PCI device */ + EFI_HANDLE pci_device; + /** PCI I/O protocol */ + EFI_PCI_IO_PROTOCOL *pci_io; + /** Memory BAR */ + unsigned int mem_bar; + /** I/O BAR */ + unsigned int io_bar; + + /** Broadcast address */ + PXE_MAC_ADDR broadcast; + /** Maximum packet length */ + size_t mtu; + + /** Hardware transmit/receive buffer */ + userptr_t buffer; + /** Hardware transmit/receive buffer length */ + size_t buffer_len; + + /** Saved task priority level */ + EFI_TPL saved_tpl; + + /** Current transmit buffer */ + struct io_buffer *txbuf; + /** Current receive buffer */ + struct io_buffer *rxbuf; +}; + +/** Maximum number of received packets per poll */ +#define NII_RX_QUOTA 4 + +/** + * Open PCI I/O protocol and identify BARs + * + * @v nii NII NIC + * @ret rc Return status code + */ +static int nii_pci_open ( struct nii_nic *nii ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = nii->efidev->device; + EFI_HANDLE pci_device; + union { + EFI_PCI_IO_PROTOCOL *pci_io; + void *interface; + } pci_io; + union { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *acpi; + void *resource; + } desc; + unsigned int bar; + EFI_STATUS efirc; + int rc; + + /* Locate PCI I/O protocol */ + if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid, + &pci_device ) ) != 0 ) { + DBGC ( nii, "NII %s could not locate PCI I/O protocol: %s\n", + nii->dev.name, strerror ( rc ) ); + goto err_locate; + } + nii->pci_device = pci_device; + + /* Open PCI I/O protocol */ + if ( ( efirc = bs->OpenProtocol ( pci_device, &efi_pci_io_protocol_guid, + &pci_io.interface, efi_image_handle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( nii, "NII %s could not open PCI I/O protocol: %s\n", + nii->dev.name, strerror ( rc ) ); + goto err_open; + } + nii->pci_io = pci_io.pci_io; + + /* Identify memory and I/O BARs */ + nii->mem_bar = PCI_MAX_BAR; + nii->io_bar = PCI_MAX_BAR; + for ( bar = 0 ; bar < PCI_MAX_BAR ; bar++ ) { + efirc = nii->pci_io->GetBarAttributes ( nii->pci_io, bar, NULL, + &desc.resource ); + if ( efirc == EFI_UNSUPPORTED ) { + /* BAR not present; ignore */ + continue; + } + if ( efirc != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( nii, "NII %s could not get BAR %d attributes: " + "%s\n", nii->dev.name, bar, strerror ( rc ) ); + goto err_get_bar_attributes; + } + if ( desc.acpi->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM ) { + nii->mem_bar = bar; + } else if ( desc.acpi->ResType == ACPI_ADDRESS_SPACE_TYPE_IO ) { + nii->io_bar = bar; + } + bs->FreePool ( desc.resource ); + } + DBGC ( nii, "NII %s has ", nii->dev.name ); + if ( nii->mem_bar < PCI_MAX_BAR ) { + DBGC ( nii, "memory BAR %d and ", nii->mem_bar ); + } else { + DBGC ( nii, "no memory BAR and " ); + } + if ( nii->io_bar < PCI_MAX_BAR ) { + DBGC ( nii, "I/O BAR %d\n", nii->io_bar ); + } else { + DBGC ( nii, "no I/O BAR\n" ); + } + + return 0; + + err_get_bar_attributes: + bs->CloseProtocol ( pci_device, &efi_pci_io_protocol_guid, + efi_image_handle, device ); + err_open: + err_locate: + return rc; +} + +/** + * Close PCI I/O protocol + * + * @v nii NII NIC + * @ret rc Return status code + */ +static void nii_pci_close ( struct nii_nic *nii ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + bs->CloseProtocol ( nii->pci_device, &efi_pci_io_protocol_guid, + efi_image_handle, nii->efidev->device ); +} + +/** + * I/O callback + * + * @v unique_id NII NIC + * @v op Operations + * @v len Length of data + * @v addr Address + * @v data Data buffer + */ +static EFIAPI VOID nii_io ( UINT64 unique_id, UINT8 op, UINT8 len, UINT64 addr, + UINT64 data ) { + struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id ); + EFI_PCI_IO_PROTOCOL_ACCESS *access; + EFI_PCI_IO_PROTOCOL_IO_MEM io; + EFI_PCI_IO_PROTOCOL_WIDTH width; + unsigned int bar; + EFI_STATUS efirc; + int rc; + + /* Determine accessor and BAR */ + if ( op & ( PXE_MEM_READ | PXE_MEM_WRITE ) ) { + access = &nii->pci_io->Mem; + bar = nii->mem_bar; + } else { + access = &nii->pci_io->Io; + bar = nii->io_bar; + } + + /* Determine operaton */ + io = ( ( op & ( PXE_IO_WRITE | PXE_MEM_WRITE ) ) ? + access->Write : access->Read ); + + /* Determine width */ + width = ( fls ( len ) - 1 ); + + /* Issue operation */ + if ( ( efirc = io ( nii->pci_io, width, bar, addr, 1, + ( ( void * ) ( intptr_t ) data ) ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( nii, "NII %s I/O operation %#x failed: %s\n", + nii->dev.name, op, strerror ( rc ) ); + /* No way to report failure */ + return; + } +} + +/** + * Delay callback + * + * @v unique_id NII NIC + * @v microseconds Delay in microseconds + */ +static EFIAPI VOID nii_delay ( UINT64 unique_id __unused, UINTN microseconds ) { + + udelay ( microseconds ); +} + +/** + * Block callback + * + * @v unique_id NII NIC + * @v acquire Acquire lock + */ +static EFIAPI VOID nii_block ( UINT64 unique_id, UINT32 acquire ) { + struct nii_nic *nii = ( ( void * ) ( intptr_t ) unique_id ); + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* This functionality (which is copied verbatim from the + * SnpDxe implementation of this function) appears to be + * totally brain-dead, since it produces no actual blocking + * behaviour. + */ + if ( acquire ) { + nii->saved_tpl = bs->RaiseTPL ( TPL_NOTIFY ); + } else { + bs->RestoreTPL ( nii->saved_tpl ); + } +} + +/** + * Construct operation from opcode and flags + * + * @v opcode Opcode + * @v opflags Flags + * @ret op Operation + */ +#define NII_OP( opcode, opflags ) ( (opcode) | ( (opflags) << 16 ) ) + +/** + * Extract opcode from operation + * + * @v op Operation + * @ret opcode Opcode + */ +#define NII_OPCODE( op ) ( (op) & 0xffff ) + +/** + * Extract flags from operation + * + * @v op Operation + * @ret opflags Flags + */ +#define NII_OPFLAGS( op ) ( (op) >> 16 ) + +/** + * Issue command with parameter block and data block + * + * @v nii NII NIC + * @v op Operation + * @v cpb Command parameter block, or NULL + * @v cpb_len Command parameter block length + * @v db Data block, or NULL + * @v db_len Data block length + * @ret stat Status flags, or negative status code + */ +static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb, + size_t cpb_len, void *db, size_t db_len ) { + PXE_CDB cdb; + + /* Prepare command descriptor block */ + memset ( &cdb, 0, sizeof ( cdb ) ); + cdb.OpCode = NII_OPCODE ( op ); + cdb.OpFlags = NII_OPFLAGS ( op ); + cdb.CPBaddr = ( ( intptr_t ) cpb ); + cdb.CPBsize = cpb_len; + cdb.DBaddr = ( ( intptr_t ) db ); + cdb.DBsize = db_len; + cdb.IFnum = nii->nii->IfNum; + + /* Issue command */ + nii->issue ( ( intptr_t ) &cdb ); + + /* Check completion status */ + if ( cdb.StatCode != PXE_STATCODE_SUCCESS ) + return -cdb.StatCode; + + /* Return command-specific status flags */ + return ( cdb.StatFlags & ~PXE_STATFLAGS_STATUS_MASK ); +} + +/** + * Issue command with parameter block + * + * @v nii NII NIC + * @v op Operation + * @v cpb Command parameter block, or NULL + * @v cpb_len Command parameter block length + * @ret stat Status flags, or negative status code + */ +static int nii_issue_cpb ( struct nii_nic *nii, unsigned int op, void *cpb, + size_t cpb_len ) { + + return nii_issue_cpb_db ( nii, op, cpb, cpb_len, NULL, 0 ); +} + +/** + * Issue command with data block + * + * @v nii NII NIC + * @v op Operation + * @v db Data block, or NULL + * @v db_len Data block length + * @ret stat Status flags, or negative status code + */ +static int nii_issue_db ( struct nii_nic *nii, unsigned int op, void *db, + size_t db_len ) { + + return nii_issue_cpb_db ( nii, op, NULL, 0, db, db_len ); +} + +/** + * Issue command + * + * + * @v nii NII NIC + * @v op Operation + * @ret stat Status flags, or negative status code + */ +static int nii_issue ( struct nii_nic *nii, unsigned int op ) { + + return nii_issue_cpb_db ( nii, op, NULL, 0, NULL, 0 ); +} + +/** + * Start UNDI + * + * @v nii NII NIC + * @ret rc Return status code + */ +static int nii_start_undi ( struct nii_nic *nii ) { + PXE_CPB_START_31 cpb; + int stat; + int rc; + + /* Construct parameter block */ + memset ( &cpb, 0, sizeof ( cpb ) ); + cpb.Delay = ( ( intptr_t ) nii_delay ); + cpb.Block = ( ( intptr_t ) nii_block ); + cpb.Mem_IO = ( ( intptr_t ) nii_io ); + cpb.Unique_ID = ( ( intptr_t ) nii ); + + /* Issue command */ + if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_START, &cpb, + sizeof ( cpb ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not start: %s\n", + nii->dev.name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Stop UNDI + * + * @v nii NII NIC + */ +static void nii_stop_undi ( struct nii_nic *nii ) { + int stat; + int rc; + + /* Issue command */ + if ( ( stat = nii_issue ( nii, PXE_OPCODE_STOP ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not stop: %s\n", + nii->dev.name, strerror ( rc ) ); + /* Nothing we can do about it */ + return; + } +} + +/** + * Get initialisation information + * + * @v nii NII NIC + * @v netdev Network device to fill in + * @ret rc Return status code + */ +static int nii_get_init_info ( struct nii_nic *nii, + struct net_device *netdev ) { + PXE_DB_GET_INIT_INFO db; + int stat; + int rc; + + /* Issue command */ + if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_GET_INIT_INFO, &db, + sizeof ( db ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not get initialisation info: %s\n", + nii->dev.name, strerror ( rc ) ); + return rc; + } + + /* Determine link layer protocol */ + switch ( db.IFtype ) { + case PXE_IFTYPE_ETHERNET : + netdev->ll_protocol = ðernet_protocol; + break; + default: + DBGC ( nii, "NII %s unknown interface type %#02x\n", + nii->dev.name, db.IFtype ); + return -ENOTSUP; + } + + /* Sanity checks */ + assert ( db.MediaHeaderLen == netdev->ll_protocol->ll_header_len ); + assert ( db.HWaddrLen == netdev->ll_protocol->hw_addr_len ); + assert ( db.HWaddrLen == netdev->ll_protocol->ll_addr_len ); + + /* Extract parameters */ + nii->buffer_len = db.MemoryRequired; + nii->mtu = ( db.FrameDataLen + db.MediaHeaderLen ); + netdev->max_pkt_len = nii->mtu; + + return 0; +} + +/** + * Initialise UNDI + * + * @v nii NII NIC + * @ret rc Return status code + */ +static int nii_initialise ( struct nii_nic *nii ) { + PXE_CPB_INITIALIZE cpb; + unsigned int op; + int stat; + int rc; + + /* Allocate memory buffer */ + nii->buffer = umalloc ( nii->buffer_len ); + if ( ! nii->buffer ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Construct parameter block */ + memset ( &cpb, 0, sizeof ( cpb ) ); + cpb.MemoryAddr = ( ( intptr_t ) nii->buffer ); + cpb.MemoryLength = nii->buffer_len; + + /* Issue command */ + op = NII_OP ( PXE_OPCODE_INITIALIZE, + PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE ); + if ( ( stat = nii_issue_cpb ( nii, op, &cpb, sizeof ( cpb ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not initialise: %s\n", + nii->dev.name, strerror ( rc ) ); + goto err_initialize; + } + + return 0; + + err_initialize: + ufree ( nii->buffer ); + err_alloc: + return rc; +} + +/** + * Shut down UNDI + * + * @v nii NII NIC + */ +static void nii_shutdown ( struct nii_nic *nii ) { + int stat; + int rc; + + /* Issue command */ + if ( ( stat = nii_issue ( nii, PXE_OPCODE_SHUTDOWN ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not shut down: %s\n", + nii->dev.name, strerror ( rc ) ); + /* Leak memory to avoid corruption */ + return; + } + + /* Free buffer */ + ufree ( nii->buffer ); +} + +/** + * Get station addresses + * + * @v nii NII NIC + * @v netdev Network device to fill in + * @ret rc Return status code + */ +static int nii_get_station_address ( struct nii_nic *nii, + struct net_device *netdev ) { + PXE_DB_STATION_ADDRESS db; + int stat; + int rc; + + /* Initialise UNDI */ + if ( ( rc = nii_initialise ( nii ) ) != 0 ) + goto err_initialise; + + /* Issue command */ + if ( ( stat = nii_issue_db ( nii, PXE_OPCODE_STATION_ADDRESS, &db, + sizeof ( db ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not get station address: %s\n", + nii->dev.name, strerror ( rc ) ); + goto err_station_address; + } + + /* Copy MAC addresses */ + memcpy ( netdev->ll_addr, db.StationAddr, + netdev->ll_protocol->ll_addr_len ); + memcpy ( netdev->hw_addr, db.PermanentAddr, + netdev->ll_protocol->hw_addr_len ); + memcpy ( nii->broadcast, db.BroadcastAddr, + sizeof ( nii->broadcast ) ); + + err_station_address: + nii_shutdown ( nii ); + err_initialise: + return rc; +} + +/** + * Set station address + * + * @v nii NII NIC + * @v netdev Network device + * @ret rc Return status code + */ +static int nii_set_station_address ( struct nii_nic *nii, + struct net_device *netdev ) { + PXE_CPB_STATION_ADDRESS cpb; + int stat; + int rc; + + /* Construct parameter block */ + memset ( &cpb, 0, sizeof ( cpb ) ); + memcpy ( cpb.StationAddr, netdev->ll_addr, + netdev->ll_protocol->ll_addr_len ); + + /* Issue command */ + if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_STATION_ADDRESS, + &cpb, sizeof ( cpb ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not set station address: %s\n", + nii->dev.name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Set receive filters + * + * @v nii NII NIC + * @ret rc Return status code + */ +static int nii_set_rx_filters ( struct nii_nic *nii ) { + unsigned int op; + int stat; + int rc; + + /* Issue command */ + op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, + ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE | + PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | + PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST | + PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS | + PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST ) ); + if ( ( stat = nii_issue ( nii, op ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not set receive filters: %s\n", + nii->dev.name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int nii_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct nii_nic *nii = netdev->priv; + PXE_CPB_TRANSMIT cpb; + int stat; + int rc; + + /* Defer the packet if there is already a transmission in progress */ + if ( nii->txbuf ) { + netdev_tx_defer ( netdev, iobuf ); + return 0; + } + + /* Construct parameter block */ + memset ( &cpb, 0, sizeof ( cpb ) ); + cpb.FrameAddr = virt_to_bus ( iobuf->data ); + cpb.DataLen = iob_len ( iobuf ); + cpb.MediaheaderLen = netdev->ll_protocol->ll_header_len; + + /* Transmit packet */ + if ( ( stat = nii_issue_cpb ( nii, PXE_OPCODE_TRANSMIT, &cpb, + sizeof ( cpb ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not transmit: %s\n", + nii->dev.name, strerror ( rc ) ); + return rc; + } + nii->txbuf = iobuf; + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + * @v stat Status flags + */ +static void nii_poll_tx ( struct net_device *netdev, unsigned int stat ) { + struct nii_nic *nii = netdev->priv; + struct io_buffer *iobuf; + + /* Do nothing unless we have a completion */ + if ( stat & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN ) + return; + + /* Sanity check */ + if ( ! nii->txbuf ) { + DBGC ( nii, "NII %s reported spurious TX completion\n", + nii->dev.name ); + netdev_tx_err ( netdev, NULL, -EPIPE ); + return; + } + + /* Complete transmission */ + iobuf = nii->txbuf; + nii->txbuf = NULL; + netdev_tx_complete ( netdev, iobuf ); +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void nii_poll_rx ( struct net_device *netdev ) { + struct nii_nic *nii = netdev->priv; + PXE_CPB_RECEIVE cpb; + PXE_DB_RECEIVE db; + unsigned int quota; + int stat; + int rc; + + /* Retrieve up to NII_RX_QUOTA packets */ + for ( quota = NII_RX_QUOTA ; quota ; quota-- ) { + + /* Allocate buffer, if required */ + if ( ! nii->rxbuf ) { + nii->rxbuf = alloc_iob ( nii->mtu ); + if ( ! nii->rxbuf ) { + /* Leave for next poll */ + break; + } + } + + /* Construct parameter block */ + memset ( &cpb, 0, sizeof ( cpb ) ); + cpb.BufferAddr = virt_to_bus ( nii->rxbuf->data ); + cpb.BufferLen = iob_tailroom ( nii->rxbuf ); + + /* Issue command */ + if ( ( stat = nii_issue_cpb_db ( nii, PXE_OPCODE_RECEIVE, + &cpb, sizeof ( cpb ), + &db, sizeof ( db ) ) ) < 0 ) { + + /* PXE_STATCODE_NO_DATA is just the usual "no packet" + * status indicator; ignore it. + */ + if ( stat == -PXE_STATCODE_NO_DATA ) + break; + + /* Anything else is an error */ + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not receive: %s\n", + nii->dev.name, strerror ( rc ) ); + netdev_rx_err ( netdev, NULL, rc ); + break; + } + + /* Hand off to network stack */ + iob_put ( nii->rxbuf, db.FrameLen ); + netdev_rx ( netdev, nii->rxbuf ); + nii->rxbuf = NULL; + } +} + +/** + * Check for link state changes + * + * @v netdev Network device + * @v stat Status flags + */ +static void nii_poll_link ( struct net_device *netdev, unsigned int stat ) { + int no_media = ( stat & PXE_STATFLAGS_GET_STATUS_NO_MEDIA ); + + if ( no_media && netdev_link_ok ( netdev ) ) { + netdev_link_down ( netdev ); + } else if ( ( ! no_media ) && ( ! netdev_link_ok ( netdev ) ) ) { + netdev_link_up ( netdev ); + } +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void nii_poll ( struct net_device *netdev ) { + struct nii_nic *nii = netdev->priv; + PXE_DB_GET_STATUS db; + unsigned int op; + int stat; + int rc; + + /* Get status */ + op = NII_OP ( PXE_OPCODE_GET_STATUS, + ( PXE_OPFLAGS_GET_INTERRUPT_STATUS | + PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS | + PXE_OPFLAGS_GET_MEDIA_STATUS ) ); + if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) { + rc = -EIO_STAT ( stat ); + DBGC ( nii, "NII %s could not get status: %s\n", + nii->dev.name, strerror ( rc ) ); + return; + } + + /* Process any TX completions */ + nii_poll_tx ( netdev, stat ); + + /* Process any RX completions */ + nii_poll_rx ( netdev ); + + /* Check for link state changes */ + nii_poll_link ( netdev, stat ); +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int nii_open ( struct net_device *netdev ) { + struct nii_nic *nii = netdev->priv; + int rc; + + /* Initialise NIC */ + if ( ( rc = nii_initialise ( nii ) ) != 0 ) + goto err_initialise; + + /* Attempt to set station address */ + if ( ( rc = nii_set_station_address ( nii, netdev ) ) != 0 ) { + DBGC ( nii, "NII %s could not set station address: %s\n", + nii->dev.name, strerror ( rc ) ); + /* Treat as non-fatal */ + } + + /* Set receive filters */ + if ( ( rc = nii_set_rx_filters ( nii ) ) != 0 ) + goto err_set_rx_filters; + + return 0; + + err_set_rx_filters: + nii_shutdown ( nii ); + err_initialise: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void nii_close ( struct net_device *netdev ) { + struct nii_nic *nii = netdev->priv; + + /* Shut down NIC */ + nii_shutdown ( nii ); + + /* Discard transmit buffer, if applicable */ + if ( nii->txbuf ) { + netdev_tx_complete_err ( netdev, nii->txbuf, -ECANCELED ); + nii->txbuf = NULL; + } + + /* Discard receive buffer, if applicable */ + if ( nii->rxbuf ) { + free_iob ( nii->rxbuf ); + nii->rxbuf = NULL; + } +} + +/** NII network device operations */ +static struct net_device_operations nii_operations = { + .open = nii_open, + .close = nii_close, + .transmit = nii_transmit, + .poll = nii_poll, +}; + +/** + * Attach driver to device + * + * @v efidev EFI device + * @ret rc Return status code + */ +int nii_start ( struct efi_device *efidev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efidev->device; + struct net_device *netdev; + struct nii_nic *nii; + void *interface; + EFI_STATUS efirc; + int rc; + + /* Allocate and initialise structure */ + netdev = alloc_netdev ( sizeof ( *nii ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &nii_operations ); + nii = netdev->priv; + nii->efidev = efidev; + netdev->ll_broadcast = nii->broadcast; + efidev_set_drvdata ( efidev, netdev ); + + /* Populate underlying device information */ + efi_device_info ( device, "NII", &nii->dev ); + nii->dev.driver_name = "NII"; + nii->dev.parent = &efidev->dev; + list_add ( &nii->dev.siblings, &efidev->dev.children ); + INIT_LIST_HEAD ( &nii->dev.children ); + netdev->dev = &nii->dev; + + /* Open NII protocol */ + if ( ( efirc = bs->OpenProtocol ( device, &efi_nii31_protocol_guid, + &interface, efi_image_handle, device, + ( EFI_OPEN_PROTOCOL_BY_DRIVER | + EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ + rc = -EEFI ( efirc ); + DBGC ( nii, "NII %s cannot open NII protocol: %s\n", + nii->dev.name, strerror ( rc ) ); + DBGC_EFI_OPENERS ( device, device, &efi_nii31_protocol_guid ); + goto err_open_protocol; + } + nii->nii = interface; + + /* Locate UNDI and entry point */ + nii->undi = ( ( void * ) ( intptr_t ) nii->nii->Id ); + if ( ! nii->undi ) { + DBGC ( nii, "NII %s has no UNDI\n", nii->dev.name ); + rc = -ENODEV; + goto err_no_undi; + } + if ( nii->undi->Implementation & PXE_ROMID_IMP_HW_UNDI ) { + DBGC ( nii, "NII %s is a mythical hardware UNDI\n", + nii->dev.name ); + rc = -ENOTSUP; + goto err_hw_undi; + } + if ( nii->undi->Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR ) { + nii->issue = ( ( void * ) ( intptr_t ) nii->undi->EntryPoint ); + } else { + nii->issue = ( ( ( void * ) nii->undi ) + + nii->undi->EntryPoint ); + } + DBGC ( nii, "NII %s using UNDI v%x.%x at %p entry %p\n", nii->dev.name, + nii->nii->MajorVer, nii->nii->MinorVer, nii->undi, nii->issue ); + + /* Open PCI I/O protocols and locate BARs */ + if ( ( rc = nii_pci_open ( nii ) ) != 0 ) + goto err_pci_open; + + /* Start UNDI */ + if ( ( rc = nii_start_undi ( nii ) ) != 0 ) + goto err_start_undi; + + /* Get initialisation information */ + if ( ( rc = nii_get_init_info ( nii, netdev ) ) != 0 ) + goto err_get_init_info; + + /* Get MAC addresses */ + if ( ( rc = nii_get_station_address ( nii, netdev ) ) != 0 ) + goto err_get_station_address; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + DBGC ( nii, "NII %s registered as %s for %p %s\n", nii->dev.name, + netdev->name, device, efi_handle_name ( device ) ); + + return 0; + + unregister_netdev ( netdev ); + err_register_netdev: + err_get_station_address: + err_get_init_info: + nii_stop_undi ( nii ); + err_start_undi: + nii_pci_close ( nii ); + err_pci_open: + err_hw_undi: + err_no_undi: + bs->CloseProtocol ( device, &efi_nii31_protocol_guid, + efi_image_handle, device ); + err_open_protocol: + list_del ( &nii->dev.siblings ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Detach driver from device + * + * @v efidev EFI device + */ +void nii_stop ( struct efi_device *efidev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct net_device *netdev = efidev_get_drvdata ( efidev ); + struct nii_nic *nii = netdev->priv; + EFI_HANDLE device = efidev->device; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Stop UNDI */ + nii_stop_undi ( nii ); + + /* Close PCI I/O protocols */ + nii_pci_close ( nii ); + + /* Close NII protocol */ + bs->CloseProtocol ( device, &efi_nii31_protocol_guid, + efi_image_handle, device ); + + /* Free network device */ + list_del ( &nii->dev.siblings ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} diff --git a/roms/ipxe/src/drivers/net/efi/nii.h b/roms/ipxe/src/drivers/net/efi/nii.h new file mode 100644 index 000000000..de0ac687b --- /dev/null +++ b/roms/ipxe/src/drivers/net/efi/nii.h @@ -0,0 +1,17 @@ +#ifndef _NII_H +#define _NII_H + +/** @file + * + * NII driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +struct efi_device; + +extern int nii_start ( struct efi_device *efidev ); +extern void nii_stop ( struct efi_device *efidev ); + +#endif /* _NII_H */ diff --git a/roms/ipxe/src/drivers/net/efi/snp.c b/roms/ipxe/src/drivers/net/efi/snp.c new file mode 100644 index 000000000..2b5fc8618 --- /dev/null +++ b/roms/ipxe/src/drivers/net/efi/snp.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2014 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <errno.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_snp.h> +#include "snpnet.h" +#include "nii.h" + +/** @file + * + * SNP driver + * + */ + +/** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int snp_supported ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + + /* Check that this is not a device we are providing ourselves */ + if ( find_snpdev ( device ) != NULL ) { + DBGCP ( device, "SNP %p %s is provided by this binary\n", + device, efi_handle_name ( device ) ); + return -ENOTTY; + } + + /* Test for presence of simple network protocol */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_simple_network_protocol_guid, + NULL, efi_image_handle, device, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ + DBGCP ( device, "SNP %p %s is not an SNP device\n", + device, efi_handle_name ( device ) ); + return -EEFI ( efirc ); + } + DBGC ( device, "SNP %p %s is an SNP device\n", + device, efi_handle_name ( device ) ); + + return 0; +} + +/** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int nii_supported ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + + /* Check that this is not a device we are providing ourselves */ + if ( find_snpdev ( device ) != NULL ) { + DBGCP ( device, "NII %p %s is provided by this binary\n", + device, efi_handle_name ( device ) ); + return -ENOTTY; + } + + /* Test for presence of NII protocol */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_nii31_protocol_guid, + NULL, efi_image_handle, device, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){ + DBGCP ( device, "NII %p %s is not an NII device\n", + device, efi_handle_name ( device ) ); + return -EEFI ( efirc ); + } + DBGC ( device, "NII %p %s is an NII device\n", + device, efi_handle_name ( device ) ); + + return 0; +} + +/** EFI SNP driver */ +struct efi_driver snp_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "SNP", + .supported = snp_supported, + .start = snpnet_start, + .stop = snpnet_stop, +}; + +/** EFI NII driver */ +struct efi_driver nii_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "NII", + .supported = nii_supported, + .start = nii_start, + .stop = nii_stop, +}; diff --git a/roms/ipxe/src/drivers/net/efi/snp.h b/roms/ipxe/src/drivers/net/efi/snp.h deleted file mode 100644 index 4d6b10147..000000000 --- a/roms/ipxe/src/drivers/net/efi/snp.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 VMware, Inc. All Rights Reserved. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _SNP_H -#define _SNP_H - -/** @file - * - * SNP driver - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <ipxe/device.h> -#include <ipxe/netdevice.h> -#include <ipxe/efi/Protocol/SimpleNetwork.h> - -/** A network device that consumes the EFI Simple Network Protocol */ -struct snp_device { - /** Underlying simple network protocol instance */ - EFI_SIMPLE_NETWORK_PROTOCOL *snp; - - /** Generic device */ - struct device dev; - - /** Network device */ - struct net_device *netdev; - - /** State to put the snp in when removing the device */ - uint32 removal_state; -}; - -#endif /* _SNP_H */ diff --git a/roms/ipxe/src/drivers/net/efi/snpnet.c b/roms/ipxe/src/drivers/net/efi/snpnet.c index cd9e7e386..96642c4ca 100644 --- a/roms/ipxe/src/drivers/net/efi/snpnet.c +++ b/roms/ipxe/src/drivers/net/efi/snpnet.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 VMware, Inc. All Rights Reserved. + * Copyright (C) 2014 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 @@ -13,38 +13,137 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ FILE_LICENCE ( GPL2_OR_LATER ); -#include <errno.h> +#include <stdlib.h> +#include <stdio.h> #include <string.h> -#include <ipxe/io.h> +#include <errno.h> #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> -#include <ipxe/if_ether.h> #include <ipxe/ethernet.h> +#include <ipxe/vsprintf.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/SimpleNetwork.h> -#include "snp.h" +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_utils.h> #include "snpnet.h" /** @file * - * SNP network device driver + * SNP NIC driver * */ -/** SNP net device structure */ -struct snpnet_device { - /** The underlying simple network protocol */ +/** An SNP NIC */ +struct snp_nic { + /** EFI device */ + struct efi_device *efidev; + /** Simple network protocol */ EFI_SIMPLE_NETWORK_PROTOCOL *snp; + /** Generic device */ + struct device dev; + + /** Maximum packet size + * + * This is calculated as the sum of MediaHeaderSize and + * MaxPacketSize, and may therefore be an overestimate. + */ + size_t mtu; - /** State that the SNP should be in after close */ - UINT32 close_state; + /** Current transmit buffer */ + struct io_buffer *txbuf; + /** Current receive buffer */ + struct io_buffer *rxbuf; }; +/** Maximum number of received packets per poll */ +#define SNP_RX_QUOTA 4 + +/** + * Format SNP MAC address (for debugging) + * + * @v mac MAC address + * @v len Length of MAC address + * @ret text MAC address as text + */ +static const char * snpnet_mac_text ( EFI_MAC_ADDRESS *mac, size_t len ) { + static char buf[ sizeof ( *mac ) * 3 /* "xx:" or "xx\0" */ ]; + size_t used = 0; + unsigned int i; + + for ( i = 0 ; i < len ; i++ ) { + used += ssnprintf ( &buf[used], ( sizeof ( buf ) - used ), + "%s%02x", ( used ? ":" : "" ), + mac->Addr[i] ); + } + return buf; +} + +/** + * Dump SNP mode information (for debugging) + * + * @v netdev Network device + */ +static void snpnet_dump_mode ( struct net_device *netdev ) { + struct snp_nic *snp = netdev_priv ( netdev ); + EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode; + size_t mac_len = mode->HwAddressSize; + unsigned int i; + + /* Do nothing unless debugging is enabled */ + if ( ! DBG_EXTRA ) + return; + + DBGC2 ( snp, "SNP %s st %d type %d hdr %d pkt %d rxflt %#x/%#x%s " + "nvram %d acc %d mcast %d/%d\n", netdev->name, mode->State, + mode->IfType, mode->MediaHeaderSize, mode->MaxPacketSize, + mode->ReceiveFilterSetting, mode->ReceiveFilterMask, + ( mode->MultipleTxSupported ? " multitx" : "" ), + mode->NvRamSize, mode->NvRamAccessSize, + mode->MCastFilterCount, mode->MaxMCastFilterCount ); + DBGC2 ( snp, "SNP %s hw %s", netdev->name, + snpnet_mac_text ( &mode->PermanentAddress, mac_len ) ); + DBGC2 ( snp, " addr %s%s", + snpnet_mac_text ( &mode->CurrentAddress, mac_len ), + ( mode->MacAddressChangeable ? "" : "(f)" ) ); + DBGC2 ( snp, " bcast %s\n", + snpnet_mac_text ( &mode->BroadcastAddress, mac_len ) ); + for ( i = 0 ; i < mode->MCastFilterCount ; i++ ) { + DBGC2 ( snp, "SNP %s mcast %s\n", netdev->name, + snpnet_mac_text ( &mode->MCastFilter[i], mac_len ) ); + } + DBGC2 ( snp, "SNP %s media %s\n", netdev->name, + ( mode->MediaPresentSupported ? + ( mode->MediaPresent ? "present" : "not present" ) : + "presence not supported" ) ); +} + +/** + * Check link state + * + * @v netdev Network device + */ +static void snpnet_check_link ( struct net_device *netdev ) { + struct snp_nic *snp = netdev_priv ( netdev ); + EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode; + + /* Do nothing unless media presence detection is supported */ + if ( ! mode->MediaPresentSupported ) + return; + + /* Report any link status change */ + if ( mode->MediaPresent && ( ! netdev_link_ok ( netdev ) ) ) { + netdev_link_up ( netdev ); + } else if ( ( ! mode->MediaPresent ) && netdev_link_ok ( netdev ) ) { + netdev_link_down ( netdev ); + } +} + /** * Transmit packet * @@ -54,297 +153,411 @@ struct snpnet_device { */ static int snpnet_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct snpnet_device *snpnetdev = netdev->priv; - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; - void *txbuf=NULL; - size_t len = iob_len ( iobuf ); + struct snp_nic *snp = netdev_priv ( netdev ); EFI_STATUS efirc; int rc; - if ( ( efirc = snp->Transmit ( snp, 0, len, iobuf->data, NULL, NULL, - NULL ) ) != 0 ) { - return -EEFI ( efirc ); + /* Defer the packet if there is already a transmission in progress */ + if ( snp->txbuf ) { + netdev_tx_defer ( netdev, iobuf ); + return 0; } - /* since GetStatus is so inconsistent, don't try more than one outstanding transmit at a time */ - while ( txbuf == NULL ) { - if ( ( efirc = snp->GetStatus ( snp, NULL, &txbuf ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not get status %s\n", snp, - strerror ( rc ) ); - break; - } + /* Transmit packet */ + if ( ( efirc = snp->snp->Transmit ( snp->snp, 0, iob_len ( iobuf ), + iobuf->data, NULL, NULL, + NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( snp, "SNP %s could not transmit: %s\n", + netdev->name, strerror ( rc ) ); + return rc; } - netdev_tx_complete ( netdev, iobuf ); + snp->txbuf = iobuf; + return 0; } /** + * Poll for completed packets + * + * @v netdev Network device + */ +static void snpnet_poll_tx ( struct net_device *netdev ) { + struct snp_nic *snp = netdev->priv; + struct io_buffer *iobuf; + UINT32 irq; + VOID *txbuf; + EFI_STATUS efirc; + int rc; + + /* Get status */ + if ( ( efirc = snp->snp->GetStatus ( snp->snp, &irq, &txbuf ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( snp, "SNP %s could not get status: %s\n", + netdev->name, strerror ( rc ) ); + netdev_rx_err ( netdev, NULL, rc ); + return; + } + + /* Do nothing unless we have a completion */ + if ( ! txbuf ) + return; + + /* Sanity check */ + if ( ! snp->txbuf ) { + DBGC ( snp, "SNP %s reported spurious TX completion\n", + netdev->name ); + netdev_tx_err ( netdev, NULL, -EPIPE ); + return; + } + + /* Complete transmission */ + iobuf = snp->txbuf; + snp->txbuf = NULL; + netdev_tx_complete ( netdev, iobuf ); +} + +/** * Poll for received packets * * @v netdev Network device */ -static void snpnet_poll ( struct net_device *netdev ) { - struct snpnet_device *snpnetdev = netdev->priv; - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; - struct io_buffer *iobuf = NULL; +static void snpnet_poll_rx ( struct net_device *netdev ) { + struct snp_nic *snp = netdev->priv; UINTN len; + unsigned int quota; EFI_STATUS efirc; int rc; - /* Process received packets */ - while ( 1 ) { - /* The spec is not clear if the max packet size refers to the - * payload or the entire packet including headers. The Receive - * function needs a buffer large enough to contain the headers, - * and potentially a 4-byte CRC and 4-byte VLAN tag (?), so add - * some breathing room. - */ - len = snp->Mode->MaxPacketSize + ETH_HLEN + 8; - iobuf = alloc_iob ( len ); - if ( iobuf == NULL ) { - netdev_rx_err ( netdev, NULL, -ENOMEM ); - break; + /* Retrieve up to SNP_RX_QUOTA packets */ + for ( quota = SNP_RX_QUOTA ; quota ; quota-- ) { + + /* Allocate buffer, if required */ + if ( ! snp->rxbuf ) { + snp->rxbuf = alloc_iob ( snp->mtu ); + if ( ! snp->rxbuf ) { + /* Leave for next poll */ + break; + } } - efirc = snp->Receive ( snp, NULL, &len, iobuf->data, - NULL, NULL, NULL ); + /* Receive packet */ + len = iob_tailroom ( snp->rxbuf ); + if ( ( efirc = snp->snp->Receive ( snp->snp, NULL, &len, + snp->rxbuf->data, NULL, + NULL, NULL ) ) != 0 ) { - /* No packets left? */ - if ( efirc == EFI_NOT_READY ) { - free_iob ( iobuf ); - break; - } + /* EFI_NOT_READY is just the usual "no packet" + * status indication; ignore it. + */ + if ( efirc == EFI_NOT_READY ) + break; - /* Other error? */ - if ( efirc != 0 ) { + /* Anything else is an error */ rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p receive packet error: %s " - "(len was %zd, is now %zd)\n", - snp, strerror ( rc ), iob_len(iobuf), - (size_t)len ); - netdev_rx_err ( netdev, iobuf, rc ); + DBGC ( snp, "SNP %s could not receive: %s\n", + netdev->name, strerror ( rc ) ); + netdev_rx_err ( netdev, NULL, rc ); break; } - /* Packet is valid, deliver it */ - iob_put ( iobuf, len ); - netdev_rx ( netdev, iob_disown ( iobuf ) ); + /* Hand off to network stack */ + iob_put ( snp->rxbuf, len ); + netdev_rx ( netdev, snp->rxbuf ); + snp->rxbuf = NULL; } } /** - * Open NIC + * Poll for completed packets * - * @v netdev Net device + * @v netdev Network device + */ +static void snpnet_poll ( struct net_device *netdev ) { + + /* Process any TX completions */ + snpnet_poll_tx ( netdev ); + + /* Process any RX completions */ + snpnet_poll_rx ( netdev ); + + /* Check for link state changes */ + snpnet_check_link ( netdev ); +} + +/** + * Set receive filters + * + * @v netdev Network device * @ret rc Return status code */ -static int snpnet_open ( struct net_device *netdev ) { - struct snpnet_device *snpnetdev = netdev->priv; - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; - EFI_MAC_ADDRESS *mac; - UINT32 enableFlags, disableFlags; +static int snpnet_rx_filters ( struct net_device *netdev ) { + struct snp_nic *snp = netdev->priv; + UINT32 filters[] = { + snp->snp->Mode->ReceiveFilterMask, + ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ), + ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ), + ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST ), + }; + unsigned int i; EFI_STATUS efirc; int rc; - snpnetdev->close_state = snp->Mode->State; - if ( snp->Mode->State != EfiSimpleNetworkInitialized ) { - if ( ( efirc = snp->Initialize ( snp, 0, 0 ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not initialize: %s\n", - snp, strerror ( rc ) ); - return rc; - } + /* Try possible receive filters in turn */ + for ( i = 0; i < ( sizeof ( filters ) / sizeof ( filters[0] ) ); i++ ) { + efirc = snp->snp->ReceiveFilters ( snp->snp, filters[i], + 0, TRUE, 0, NULL ); + if ( efirc == 0 ) + return 0; + rc = -EEFI ( efirc ); + DBGC ( snp, "SNP %s could not set receive filters %#02x (have " + "%#02x): %s\n", netdev->name, filters[i], + snp->snp->Mode->ReceiveFilterSetting, strerror ( rc ) ); } - /* Use the default MAC address */ - mac = ( ( void * ) netdev->ll_addr ); - if ( ( efirc = snp->StationAddress ( snp, FALSE, mac ) ) != 0 ) { + return rc; +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int snpnet_open ( struct net_device *netdev ) { + struct snp_nic *snp = netdev->priv; + EFI_MAC_ADDRESS *mac = ( ( void * ) netdev->ll_addr ); + EFI_STATUS efirc; + int rc; + + /* Try setting MAC address (before initialising) */ + if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){ rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not reset station address: %s\n", - snp, strerror ( rc ) ); + DBGC ( snp, "SNP %s could not set station address before " + "initialising: %s\n", netdev->name, strerror ( rc ) ); + /* Ignore error */ } - /* Set up receive filters to receive unicast and broadcast packets - * always. Also, enable either promiscuous multicast (if possible) or - * promiscuous operation, in order to catch all multicast packets. - */ - enableFlags = snp->Mode->ReceiveFilterMask & - ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | - EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ); - disableFlags = snp->Mode->ReceiveFilterMask & - ( EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | - EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | - EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST ); - if ( snp->Mode->ReceiveFilterMask & - EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST ) { - enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST; - } else if ( snp->Mode->ReceiveFilterMask & - EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS ) { - enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; + /* Initialise NIC */ + if ( ( efirc = snp->snp->Initialize ( snp->snp, 0, 0 ) ) != 0 ) { + rc = -EEFI ( efirc ); + snpnet_dump_mode ( netdev ); + DBGC ( snp, "SNP %s could not initialise: %s\n", + netdev->name, strerror ( rc ) ); + return rc; } - disableFlags &= ~enableFlags; - if ( ( efirc = snp->ReceiveFilters ( snp, enableFlags, disableFlags, - FALSE, 0, NULL ) ) != 0 ) { + + /* Try setting MAC address (after initialising) */ + if ( ( efirc = snp->snp->StationAddress ( snp->snp, FALSE, mac ) ) !=0){ rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not set receive filters: %s\n", - snp, strerror ( rc ) ); + DBGC ( snp, "SNP %s could not set station address after " + "initialising: %s\n", netdev->name, strerror ( rc ) ); + /* Ignore error */ + } + + /* Set receive filters */ + if ( ( rc = snpnet_rx_filters ( netdev ) ) != 0 ) { + /* Ignore error */ } - DBGC ( snp, "SNP %p opened\n", snp ); + /* Dump mode information (for debugging) */ + snpnet_dump_mode ( netdev ); + return 0; } /** - * Close NIC + * Close network device * - * @v netdev Net device + * @v netdev Network device */ static void snpnet_close ( struct net_device *netdev ) { - struct snpnet_device *snpnetdev = netdev->priv; - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; + struct snp_nic *snp = netdev->priv; EFI_STATUS efirc; int rc; - if ( snpnetdev->close_state != EfiSimpleNetworkInitialized ) { - if ( ( efirc = snp->Shutdown ( snp ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not shut down: %s\n", - snp, strerror ( rc ) ); - } + /* Shut down NIC */ + if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( snp, "SNP %s could not shut down: %s\n", + netdev->name, strerror ( rc ) ); + /* Nothing we can do about this */ } -} -/** - * Enable/disable interrupts - * - * @v netdev Net device - * @v enable Interrupts should be enabled - */ -static void snpnet_irq ( struct net_device *netdev, int enable ) { - struct snpnet_device *snpnetdev = netdev->priv; - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; + /* Discard transmit buffer, if applicable */ + if ( snp->txbuf ) { + netdev_tx_complete_err ( netdev, snp->txbuf, -ECANCELED ); + snp->txbuf = NULL; + } - /* On EFI, interrupts are never necessary. (This function is only - * required for BIOS PXE.) If interrupts were required, they could be - * simulated using a fast timer. - */ - DBGC ( snp, "SNP %p cannot %s interrupts\n", - snp, ( enable ? "enable" : "disable" ) ); + /* Discard receive buffer, if applicable */ + if ( snp->rxbuf ) { + free_iob ( snp->rxbuf ); + snp->rxbuf = NULL; + } } /** SNP network device operations */ static struct net_device_operations snpnet_operations = { - .open = snpnet_open, - .close = snpnet_close, - .transmit = snpnet_transmit, - .poll = snpnet_poll, - .irq = snpnet_irq, + .open = snpnet_open, + .close = snpnet_close, + .transmit = snpnet_transmit, + .poll = snpnet_poll, }; /** - * Probe SNP device + * Attach driver to device * - * @v snpdev SNP device + * @v efidev EFI device * @ret rc Return status code */ -int snpnet_probe ( struct snp_device *snpdev ) { - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp; - EFI_STATUS efirc; +int snpnet_start ( struct efi_device *efidev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efidev->device; + EFI_SIMPLE_NETWORK_MODE *mode; struct net_device *netdev; - struct snpnet_device *snpnetdev; + struct snp_nic *snp; + void *interface; + EFI_STATUS efirc; int rc; - DBGC ( snp, "SNP %p probing...\n", snp ); + /* Open SNP protocol */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_simple_network_protocol_guid, + &interface, efi_image_handle, device, + ( EFI_OPEN_PROTOCOL_BY_DRIVER | + EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "SNP %p %s cannot open SNP protocol: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); + DBGC_EFI_OPENERS ( device, device, + &efi_simple_network_protocol_guid ); + goto err_open_protocol; + } - /* Allocate net device */ - netdev = alloc_etherdev ( sizeof ( struct snpnet_device ) ); - if ( ! netdev ) - return -ENOMEM; + /* Allocate and initialise structure */ + netdev = alloc_etherdev ( sizeof ( *snp ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } netdev_init ( netdev, &snpnet_operations ); - netdev->dev = &snpdev->dev; - snpdev->netdev = netdev; - snpnetdev = netdev->priv; - snpnetdev->snp = snp; - snpdev->removal_state = snp->Mode->State; - - /* Start the interface */ - if ( snp->Mode->State == EfiSimpleNetworkStopped ) { - if ( ( efirc = snp->Start ( snp ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not start: %s\n", snp, - strerror ( rc ) ); - goto err_start; - } + snp = netdev->priv; + snp->efidev = efidev; + snp->snp = interface; + mode = snp->snp->Mode; + efidev_set_drvdata ( efidev, netdev ); + + /* Populate underlying device information */ + efi_device_info ( device, "SNP", &snp->dev ); + snp->dev.driver_name = "SNP"; + snp->dev.parent = &efidev->dev; + list_add ( &snp->dev.siblings, &efidev->dev.children ); + INIT_LIST_HEAD ( &snp->dev.children ); + netdev->dev = &snp->dev; + + /* Bring to the Started state */ + if ( ( mode->State == EfiSimpleNetworkStopped ) && + ( ( efirc = snp->snp->Start ( snp->snp ) ) != 0 ) ) { + rc = -EEFI ( efirc ); + DBGC ( device, "SNP %p %s could not start: %s\n", device, + efi_handle_name ( device ), strerror ( rc ) ); + goto err_start; + } + if ( ( mode->State == EfiSimpleNetworkInitialized ) && + ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { + rc = -EEFI ( efirc ); + DBGC ( device, "SNP %p %s could not shut down: %s\n", device, + efi_handle_name ( device ), strerror ( rc ) ); + goto err_shutdown; } - if ( snp->Mode->HwAddressSize > sizeof ( netdev->hw_addr ) ) { - DBGC ( snp, "SNP %p hardware address is too large\n", snp ); - rc = -EINVAL; - goto err_hwaddr; + /* Populate network device parameters */ + if ( mode->HwAddressSize != netdev->ll_protocol->hw_addr_len ) { + DBGC ( device, "SNP %p %s has invalid hardware address " + "length %d\n", device, efi_handle_name ( device ), + mode->HwAddressSize ); + rc = -ENOTSUP; + goto err_hw_addr_len; } - memcpy ( netdev->hw_addr, snp->Mode->PermanentAddress.Addr, - snp->Mode->HwAddressSize ); + memcpy ( netdev->hw_addr, &mode->PermanentAddress, + netdev->ll_protocol->hw_addr_len ); + if ( mode->HwAddressSize != netdev->ll_protocol->ll_addr_len ) { + DBGC ( device, "SNP %p %s has invalid link-layer address " + "length %d\n", device, efi_handle_name ( device ), + mode->HwAddressSize ); + rc = -ENOTSUP; + goto err_ll_addr_len; + } + memcpy ( netdev->ll_addr, &mode->CurrentAddress, + netdev->ll_protocol->ll_addr_len ); + snp->mtu = ( snp->snp->Mode->MaxPacketSize + + snp->snp->Mode->MediaHeaderSize ); /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err_register; - - /* Mark as link up; we don't handle link state */ - netdev_link_up ( netdev ); + goto err_register_netdev; + DBGC ( device, "SNP %p %s registered as %s\n", + device, efi_handle_name ( device ), netdev->name ); + + /* Set initial link state */ + if ( snp->snp->Mode->MediaPresentSupported ) { + snpnet_check_link ( netdev ); + } else { + netdev_link_up ( netdev ); + } - DBGC ( snp, "SNP %p added\n", snp ); return 0; -err_register: -err_hwaddr: - if ( snpdev->removal_state == EfiSimpleNetworkStopped ) - snp->Stop ( snp ); - -err_start: + unregister_netdev ( netdev ); + err_register_netdev: + err_ll_addr_len: + err_hw_addr_len: + err_shutdown: + err_start: + list_del ( &snp->dev.siblings ); netdev_nullify ( netdev ); netdev_put ( netdev ); - snpdev->netdev = NULL; + err_alloc: + bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, + efi_image_handle, device ); + err_open_protocol: return rc; } /** - * Remove SNP device + * Detach driver from device * - * @v snpdev SNP device - */ -void snpnet_remove ( struct snp_device *snpdev ) { - EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp; - struct net_device *netdev = snpdev->netdev; + * @v efidev EFI device + */ +void snpnet_stop ( struct efi_device *efidev ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct net_device *netdev = efidev_get_drvdata ( efidev ); + struct snp_nic *snp = netdev->priv; + EFI_HANDLE device = efidev->device; EFI_STATUS efirc; int rc; - if ( snp->Mode->State == EfiSimpleNetworkInitialized && - snpdev->removal_state != EfiSimpleNetworkInitialized ) { - DBGC ( snp, "SNP %p shutting down\n", snp ); - if ( ( efirc = snp->Shutdown ( snp ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not shut down: %s\n", - snp, strerror ( rc ) ); - } - } + /* Unregister network device */ + unregister_netdev ( netdev ); - if ( snp->Mode->State == EfiSimpleNetworkStarted && - snpdev->removal_state == EfiSimpleNetworkStopped ) { - DBGC ( snp, "SNP %p stopping\n", snp ); - if ( ( efirc = snp->Stop ( snp ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( snp, "SNP %p could not be stopped: %s\n", - snp, strerror ( rc ) ); - } + /* Stop SNP protocol */ + if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "SNP %p %s could not stop: %s\n", device, + efi_handle_name ( device ), strerror ( rc ) ); + /* Nothing we can do about this */ } - /* Unregister net device */ - unregister_netdev ( netdev ); - /* Free network device */ + list_del ( &snp->dev.siblings ); netdev_nullify ( netdev ); netdev_put ( netdev ); - DBGC ( snp, "SNP %p removed\n", snp ); + /* Close SNP protocol */ + bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, + efi_image_handle, device ); } diff --git a/roms/ipxe/src/drivers/net/efi/snpnet.h b/roms/ipxe/src/drivers/net/efi/snpnet.h index 72b4a7d65..e6d31d5e4 100644 --- a/roms/ipxe/src/drivers/net/efi/snpnet.h +++ b/roms/ipxe/src/drivers/net/efi/snpnet.h @@ -1,35 +1,17 @@ -/* - * Copyright (C) 2010 VMware, Inc. All Rights Reserved. - * - * 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 St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - #ifndef _SNPNET_H #define _SNPNET_H /** @file * - * EFI Simple Network Protocol network device driver + * SNP NIC driver * */ FILE_LICENCE ( GPL2_OR_LATER ); -struct snp_device; +struct efi_device; -extern int snpnet_probe ( struct snp_device *snpdev ); -extern void snpnet_remove ( struct snp_device *snpdev ); +extern int snpnet_start ( struct efi_device *efidev ); +extern void snpnet_stop ( struct efi_device *efidev ); #endif /* _SNPNET_H */ diff --git a/roms/ipxe/src/drivers/net/efi/snponly.c b/roms/ipxe/src/drivers/net/efi/snponly.c index 6fcc54a01..99f264bca 100644 --- a/roms/ipxe/src/drivers/net/efi/snponly.c +++ b/roms/ipxe/src/drivers/net/efi/snponly.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 VMware, Inc. All Rights Reserved. + * Copyright (C) 2014 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 @@ -13,117 +13,196 @@ * * 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 St, Fifth Floor, Boston, MA 02110-1301 USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ FILE_LICENCE ( GPL2_OR_LATER ); #include <string.h> #include <errno.h> -#include <ipxe/device.h> #include <ipxe/init.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_utils.h> #include <ipxe/efi/Protocol/SimpleNetwork.h> -#include "snp.h" +#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> #include "snpnet.h" +#include "nii.h" /** @file * - * Chain-loading Simple Network Protocol Bus Driver + * EFI chainloaded-device-only driver * - * This bus driver allows iPXE to use the EFI Simple Network Protocol provided - * by the platform to transmit and receive packets. It attaches to only the - * device handle that iPXE was loaded from, that is, it will only use the - * Simple Network Protocol on the current loaded image's device handle. - * - * Eseentially, this driver provides the EFI equivalent of the "undionly" - * driver. */ -/** The one and only SNP network device */ -static struct snp_device snponly_dev; +/** A chainloaded protocol */ +struct chained_protocol { + /** Protocol GUID */ + EFI_GUID *protocol; + /** + * Protocol instance installed on the loaded image's device handle + * + * We match against the protocol instance (rather than simply + * matching against the device handle itself) because some + * systems load us via a child of the underlying device, with + * a duplicate protocol installed on the child handle. + */ + void *interface; +}; + +/** Chainloaded SNP protocol */ +static struct chained_protocol chained_snp = { + .protocol = &efi_simple_network_protocol_guid, +}; -/** EFI simple network protocol GUID */ -static EFI_GUID efi_simple_network_protocol_guid - = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; +/** Chainloaded NII protocol */ +static struct chained_protocol chained_nii = { + .protocol = &efi_nii31_protocol_guid, +}; /** - * Probe SNP root bus + * Locate chainloaded protocol instance * - * @v rootdev SNP bus root device - * - * Look at the loaded image's device handle and see if the simple network - * protocol exists. If so, register a driver for it. + * @v chained Chainloaded protocol + * @ret rc Return status code */ -static int snpbus_probe ( struct root_device *rootdev ) { +static int chained_locate ( struct chained_protocol *chained ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efi_loaded_image->DeviceHandle; + EFI_HANDLE parent; EFI_STATUS efirc; int rc; - void *snp; - - efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle, - &efi_simple_network_protocol_guid, - &snp, efi_image_handle, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ); - if ( efirc ) { - DBG ( "Could not find Simple Network Protocol!\n" ); - return -ENODEV; + + /* Locate handle supporting this protocol */ + if ( ( rc = efi_locate_device ( device, chained->protocol, + &parent ) ) != 0 ) { + DBGC ( device, "CHAINED %p %s does not support %s: %s\n", + device, efi_handle_name ( device ), + efi_guid_ntoa ( chained->protocol ), strerror ( rc ) ); + goto err_locate_device; } - snponly_dev.snp = snp; + DBGC ( device, "CHAINED %p %s found %s on ", device, + efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol )); + DBGC ( device, "%p %s\n", parent, efi_handle_name ( parent ) ); + + /* Get protocol instance */ + if ( ( efirc = bs->OpenProtocol ( parent, chained->protocol, + &chained->interface, efi_image_handle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "CHAINED %p %s could not open %s on ", + device, efi_handle_name ( device ), + efi_guid_ntoa ( chained->protocol ) ); + DBGC ( device, "%p %s: %s\n", + parent, efi_handle_name ( parent ), strerror ( rc ) ); + goto err_open_protocol; + } + + err_locate_device: + bs->CloseProtocol ( parent, chained->protocol, efi_image_handle, + device ); + err_open_protocol: + return rc; +} + +/** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @v chained Chainloaded protocol + * @ret rc Return status code + */ +static int chained_supported ( EFI_HANDLE device, + struct chained_protocol *chained ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + void *interface; + int rc; - /* Add to device hierarchy */ - strncpy ( snponly_dev.dev.name, "EFI SNP", - ( sizeof ( snponly_dev.dev.name ) - 1 ) ); - snponly_dev.dev.parent = &rootdev->dev; - list_add ( &snponly_dev.dev.siblings, &rootdev->dev.children); - INIT_LIST_HEAD ( &snponly_dev.dev.children ); + /* Get protocol */ + if ( ( efirc = bs->OpenProtocol ( device, chained->protocol, &interface, + efi_image_handle, device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGCP ( device, "CHAINED %p %s is not a %s device\n", + device, efi_handle_name ( device ), + efi_guid_ntoa ( chained->protocol ) ); + goto err_open_protocol; + } - /* Create network device */ - if ( ( rc = snpnet_probe ( &snponly_dev ) ) != 0 ) - goto err; + /* Test for a match against the chainloading device */ + if ( interface != chained->interface ) { + DBGC ( device, "CHAINED %p %s %p is not the chainloaded " + "%s\n", device, efi_handle_name ( device ), + interface, efi_guid_ntoa ( chained->protocol ) ); + rc = -ENOTTY; + goto err_no_match; + } - return 0; + /* Success */ + rc = 0; + DBGC ( device, "CHAINED %p %s %p is the chainloaded %s\n", + device, efi_handle_name ( device ), interface, + efi_guid_ntoa ( chained->protocol ) ); -err: - list_del ( &snponly_dev.dev.siblings ); + err_no_match: + bs->CloseProtocol ( device, chained->protocol, efi_image_handle, + device ); + err_open_protocol: return rc; } /** - * Remove SNP root bus + * Check to see if driver supports a device * - * @v rootdev SNP bus root device + * @v device EFI device handle + * @ret rc Return status code */ -static void snpbus_remove ( struct root_device *rootdev __unused ) { - snpnet_remove ( &snponly_dev ); - list_del ( &snponly_dev.dev.siblings ); +static int snponly_supported ( EFI_HANDLE device ) { + + return chained_supported ( device, &chained_snp ); } -/** SNP bus root device driver */ -static struct root_driver snp_root_driver = { - .probe = snpbus_probe, - .remove = snpbus_remove, +/** + * Check to see if driver supports a device + * + * @v device EFI device handle + * @ret rc Return status code + */ +static int niionly_supported ( EFI_HANDLE device ) { + + return chained_supported ( device, &chained_nii ); +} + +/** EFI SNP chainloading-device-only driver */ +struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "SNPONLY", + .supported = snponly_supported, + .start = snpnet_start, + .stop = snpnet_stop, }; -/** SNP bus root device */ -struct root_device snp_root_device __root_device = { - .dev = { .name = "EFI SNP" }, - .driver = &snp_root_driver, +/** EFI NII chainloading-device-only driver */ +struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "NIIONLY", + .supported = niionly_supported, + .start = nii_start, + .stop = nii_stop, }; /** - * Prepare for exit + * Initialise EFI chainloaded-device-only driver * - * @v booting System is shutting down for OS boot */ -static void snponly_shutdown ( int booting ) { - /* If we are shutting down to boot an OS, make sure the SNP does not - * stay active. - */ - if ( booting ) - snponly_dev.removal_state = EfiSimpleNetworkStopped; +static void chained_init ( void ) { + + chained_locate ( &chained_snp ); + chained_locate ( &chained_nii ); } -struct startup_fn startup_snponly __startup_fn ( STARTUP_LATE ) = { - .shutdown = snponly_shutdown, +/** EFI chainloaded-device-only initialisation function */ +struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = { + .initialise = chained_init, }; diff --git a/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c b/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c index cd189ecb0..aace5ad56 100644 --- a/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c +++ b/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c @@ -617,6 +617,10 @@ static int igbvf_open ( struct net_device *netdev ) DBG ("igbvf_open\n"); + /* Update MAC address */ + memcpy ( adapter->hw.mac.addr, netdev->ll_addr, ETH_ALEN ); + igbvf_reset( adapter ); + /* allocate transmit descriptors */ err = igbvf_setup_tx_resources ( adapter ); if (err) { @@ -871,20 +875,14 @@ int igbvf_probe ( struct pci_device *pdev ) DBG ("Error reading MAC address\n"); goto err_hw_init; } + if ( ! is_valid_ether_addr(adapter->hw.mac.addr) ) { + /* Assign random MAC address */ + eth_random_addr(adapter->hw.mac.addr); + } } memcpy ( netdev->hw_addr, adapter->hw.mac.addr, ETH_ALEN ); - if ( ! is_valid_ether_addr( netdev->hw_addr ) ) { - DBG ("Invalid MAC Address: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->hw_addr[0], netdev->hw_addr[1], - netdev->hw_addr[2], netdev->hw_addr[3], - netdev->hw_addr[4], netdev->hw_addr[5]); - err = -EIO; - goto err_hw_init; - } - /* reset the hardware with the new settings */ igbvf_reset ( adapter ); diff --git a/roms/ipxe/src/drivers/net/intel.c b/roms/ipxe/src/drivers/net/intel.c index 6684bdbd9..a89f947b2 100644 --- a/roms/ipxe/src/drivers/net/intel.c +++ b/roms/ipxe/src/drivers/net/intel.c @@ -232,16 +232,16 @@ static int intel_fetch_mac ( struct intel_nic *intel, uint8_t *hw_addr ) { DBGC ( intel, "INTEL %p has autoloaded MAC address %s\n", intel, eth_ntoa ( mac.raw ) ); - /* Try to read address from EEPROM */ - if ( ( rc = intel_fetch_mac_eeprom ( intel, hw_addr ) ) == 0 ) - return 0; - /* Use current address if valid */ if ( is_valid_ether_addr ( mac.raw ) ) { memcpy ( hw_addr, mac.raw, ETH_ALEN ); return 0; } + /* Otherwise, try to read address from EEPROM */ + if ( ( rc = intel_fetch_mac_eeprom ( intel, hw_addr ) ) == 0 ) + return 0; + DBGC ( intel, "INTEL %p has no MAC address to use\n", intel ); return -ENOENT; } @@ -287,18 +287,23 @@ static void __attribute__ (( unused )) intel_diag ( struct intel_nic *intel ) { */ static int intel_reset ( struct intel_nic *intel ) { uint32_t pbs; + uint32_t pba; uint32_t ctrl; uint32_t status; /* Force RX and TX packet buffer allocation, to work around an * errata in ICH devices. */ - pbs = readl ( intel->regs + INTEL_PBS ); - if ( ( pbs == 0x14 ) || ( pbs == 0x18 ) ) { + if ( intel->flags & INTEL_PBS_ERRATA ) { DBGC ( intel, "INTEL %p WARNING: applying ICH PBS/PBA errata\n", intel ); + pbs = readl ( intel->regs + INTEL_PBS ); + pba = readl ( intel->regs + INTEL_PBA ); writel ( 0x08, intel->regs + INTEL_PBA ); writel ( 0x10, intel->regs + INTEL_PBS ); + DBGC ( intel, "INTEL %p PBS %#08x->%#08x PBA %#08x->%#08x\n", + intel, pbs, readl ( intel->regs + INTEL_PBS ), + pba, readl ( intel->regs + INTEL_PBA ) ); } /* Always reset MAC. Required to reset the TX and RX rings. */ @@ -496,6 +501,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { profile_start ( &intel_vm_refill_profiler ); writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT ); profile_stop ( &intel_vm_refill_profiler ); + profile_exclude ( &intel_vm_refill_profiler ); } } @@ -634,6 +640,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { profile_start ( &intel_vm_tx_profiler ); writel ( tx_tail, intel->regs + intel->tx.reg + INTEL_xDT ); profile_stop ( &intel_vm_tx_profiler ); + profile_exclude ( &intel_vm_tx_profiler ); DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx, ( ( unsigned long long ) address ), @@ -728,6 +735,7 @@ static void intel_poll ( struct net_device *netdev ) { profile_start ( &intel_vm_poll_profiler ); icr = readl ( intel->regs + INTEL_ICR ); profile_stop ( &intel_vm_poll_profiler ); + profile_exclude ( &intel_vm_poll_profiler ); if ( ! icr ) return; @@ -808,6 +816,7 @@ static int intel_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); + intel->flags = pci->id->driver_data; intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD ); intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD ); @@ -816,6 +825,10 @@ static int intel_probe ( struct pci_device *pci ) { /* Map registers */ intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE ); + if ( ! intel->regs ) { + rc = -ENODEV; + goto err_ioremap; + } /* Reset the NIC */ if ( ( rc = intel_reset ( intel ) ) != 0 ) @@ -840,6 +853,7 @@ static int intel_probe ( struct pci_device *pci ) { intel_reset ( intel ); err_reset: iounmap ( intel->regs ); + err_ioremap: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: @@ -898,11 +912,11 @@ static struct pci_device_id intel_nics[] = { PCI_ROM ( 0x8086, 0x1026, "82545gm", "82545GM", 0 ), PCI_ROM ( 0x8086, 0x1027, "82545gm-1", "82545GM", 0 ), PCI_ROM ( 0x8086, 0x1028, "82545gm-2", "82545GM", 0 ), - PCI_ROM ( 0x8086, 0x1049, "82566mm", "82566MM", 0 ), - PCI_ROM ( 0x8086, 0x104a, "82566dm", "82566DM", 0 ), - PCI_ROM ( 0x8086, 0x104b, "82566dc", "82566DC", 0 ), - PCI_ROM ( 0x8086, 0x104c, "82562v", "82562V 10/100", 0 ), - PCI_ROM ( 0x8086, 0x104d, "82566mc", "82566MC", 0 ), + PCI_ROM ( 0x8086, 0x1049, "82566mm", "82566MM", INTEL_PBS_ERRATA ), + PCI_ROM ( 0x8086, 0x104a, "82566dm", "82566DM", INTEL_PBS_ERRATA ), + PCI_ROM ( 0x8086, 0x104b, "82566dc", "82566DC", INTEL_PBS_ERRATA ), + PCI_ROM ( 0x8086, 0x104c, "82562v", "82562V", INTEL_PBS_ERRATA ), + PCI_ROM ( 0x8086, 0x104d, "82566mc", "82566MC", INTEL_PBS_ERRATA ), PCI_ROM ( 0x8086, 0x105e, "82571eb", "82571EB", 0 ), PCI_ROM ( 0x8086, 0x105f, "82571eb-1", "82571EB", 0 ), PCI_ROM ( 0x8086, 0x1060, "82571eb-2", "82571EB", 0 ), @@ -935,11 +949,11 @@ static struct pci_device_id intel_nics[] = { PCI_ROM ( 0x8086, 0x10bc, "82571eb", "82571EB (Copper)", 0 ), PCI_ROM ( 0x8086, 0x10bd, "82566dm-2", "82566DM-2", 0 ), PCI_ROM ( 0x8086, 0x10bf, "82567lf", "82567LF", 0 ), - PCI_ROM ( 0x8086, 0x10c0, "82562v-2", "82562V-2 10/100", 0 ), - PCI_ROM ( 0x8086, 0x10c2, "82562g-2", "82562G-2 10/100", 0 ), - PCI_ROM ( 0x8086, 0x10c3, "82562gt-2", "82562GT-2 10/100", 0 ), - PCI_ROM ( 0x8086, 0x10c4, "82562gt", "82562GT 10/100", 0 ), - PCI_ROM ( 0x8086, 0x10c5, "82562g", "82562G 10/100", 0 ), + PCI_ROM ( 0x8086, 0x10c0, "82562v-2", "82562V-2", 0 ), + PCI_ROM ( 0x8086, 0x10c2, "82562g-2", "82562G-2", 0 ), + PCI_ROM ( 0x8086, 0x10c3, "82562gt-2", "82562GT-2", 0 ), + PCI_ROM ( 0x8086, 0x10c4, "82562gt", "82562GT", INTEL_PBS_ERRATA ), + PCI_ROM ( 0x8086, 0x10c5, "82562g", "82562G", INTEL_PBS_ERRATA ), PCI_ROM ( 0x8086, 0x10c9, "82576", "82576", 0 ), PCI_ROM ( 0x8086, 0x10cb, "82567v", "82567V", 0 ), PCI_ROM ( 0x8086, 0x10cc, "82567lm-2", "82567LM-2", 0 ), @@ -962,7 +976,7 @@ static struct pci_device_id intel_nics[] = { PCI_ROM ( 0x8086, 0x10f0, "82578dc", "82578DC", 0 ), PCI_ROM ( 0x8086, 0x10f5, "82567lm", "82567LM", 0 ), PCI_ROM ( 0x8086, 0x10f6, "82574l", "82574L", 0 ), - PCI_ROM ( 0x8086, 0x1501, "82567v-3", "82567V-3", 0 ), + PCI_ROM ( 0x8086, 0x1501, "82567v-3", "82567V-3", INTEL_PBS_ERRATA ), PCI_ROM ( 0x8086, 0x1502, "82579lm", "82579LM", 0 ), PCI_ROM ( 0x8086, 0x1503, "82579v", "82579V", 0 ), PCI_ROM ( 0x8086, 0x150a, "82576ns", "82576NS", 0 ), @@ -982,7 +996,8 @@ static struct pci_device_id intel_nics[] = { PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ), PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ), PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ), - PCI_ROM ( 0x8086, 0x153b, "i217", "I217", 0 ), + PCI_ROM ( 0x8086, 0x153a, "i217lm", "I217-LM", 0 ), + PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ), PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ), PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ), }; diff --git a/roms/ipxe/src/drivers/net/intel.h b/roms/ipxe/src/drivers/net/intel.h index 8ce9ea973..8c4479bb4 100644 --- a/roms/ipxe/src/drivers/net/intel.h +++ b/roms/ipxe/src/drivers/net/intel.h @@ -138,10 +138,10 @@ enum intel_descriptor_status { * Minimum value is 8, since the descriptor ring length must be a * multiple of 128. */ -#define INTEL_NUM_RX_DESC 8 +#define INTEL_NUM_RX_DESC 16 /** Receive descriptor ring fill level */ -#define INTEL_RX_FILL 4 +#define INTEL_RX_FILL 8 /** Receive buffer length */ #define INTEL_RX_MAX_LEN 2048 @@ -229,6 +229,8 @@ struct intel_nic { void *regs; /** Port number (for multi-port devices) */ unsigned int port; + /** Flags */ + unsigned int flags; /** EEPROM */ struct nvs_device eeprom; @@ -245,6 +247,12 @@ struct intel_nic { struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; }; +/** Driver flags */ +enum intel_flags { + /** PBS/PBA errata workaround required */ + INTEL_PBS_ERRATA = 0x0001, +}; + extern int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ); extern void intel_destroy_ring ( struct intel_nic *intel, diff --git a/roms/ipxe/src/drivers/net/intelx.c b/roms/ipxe/src/drivers/net/intelx.c index eb8b2a640..d69900e41 100644 --- a/roms/ipxe/src/drivers/net/intelx.c +++ b/roms/ipxe/src/drivers/net/intelx.c @@ -400,6 +400,10 @@ static int intelx_probe ( struct pci_device *pci ) { /* Map registers */ intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE ); + if ( ! intel->regs ) { + rc = -ENODEV; + goto err_ioremap; + } /* Reset the NIC */ if ( ( rc = intelx_reset ( intel ) ) != 0 ) @@ -424,6 +428,7 @@ static int intelx_probe ( struct pci_device *pci ) { intelx_reset ( intel ); err_reset: iounmap ( intel->regs ); + err_ioremap: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: @@ -456,6 +461,7 @@ static struct pci_device_id intelx_nics[] = { PCI_ROM ( 0x8086, 0x10fb, "82599", "82599", 0 ), PCI_ROM ( 0x8086, 0x1528, "x540at2", "X540-AT2", 0 ), PCI_ROM ( 0x8086, 0x154d, "x520", "X520", 0 ), + PCI_ROM ( 0x8086, 0x1557, "82599", "82599", 0 ), }; /** PCI driver */ diff --git a/roms/ipxe/src/drivers/net/myson.c b/roms/ipxe/src/drivers/net/myson.c index 237f87210..6abb55660 100644 --- a/roms/ipxe/src/drivers/net/myson.c +++ b/roms/ipxe/src/drivers/net/myson.c @@ -603,6 +603,10 @@ static int myson_probe ( struct pci_device *pci ) { /* Map registers */ myson->regs = ioremap ( pci->membase, MYSON_BAR_SIZE ); + if ( ! myson->regs ) { + rc = -ENODEV; + goto err_ioremap; + } /* Reset the NIC */ if ( ( rc = myson_reset ( myson ) ) != 0 ) @@ -627,6 +631,7 @@ static int myson_probe ( struct pci_device *pci ) { myson_reset ( myson ); err_reset: iounmap ( myson->regs ); + err_ioremap: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: diff --git a/roms/ipxe/src/drivers/net/natsemi.c b/roms/ipxe/src/drivers/net/natsemi.c index 669fb8775..9f2c3029c 100644 --- a/roms/ipxe/src/drivers/net/natsemi.c +++ b/roms/ipxe/src/drivers/net/natsemi.c @@ -854,6 +854,10 @@ static int natsemi_probe ( struct pci_device *pci ) { /* Map registers */ natsemi->regs = ioremap ( pci->membase, NATSEMI_BAR_SIZE ); + if ( ! natsemi->regs ) { + rc = -ENODEV; + goto err_ioremap; + } /* Reset the NIC */ if ( ( rc = natsemi_reset ( natsemi ) ) != 0 ) @@ -881,6 +885,7 @@ static int natsemi_probe ( struct pci_device *pci ) { natsemi_reset ( natsemi ); err_reset: iounmap ( natsemi->regs ); + err_ioremap: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: diff --git a/roms/ipxe/src/drivers/net/netfront.c b/roms/ipxe/src/drivers/net/netfront.c new file mode 100644 index 000000000..4b816329e --- /dev/null +++ b/roms/ipxe/src/drivers/net/netfront.c @@ -0,0 +1,940 @@ +/* + * Copyright (C) 2014 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 (at your option) 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> +#include <ipxe/malloc.h> +#include <ipxe/base16.h> +#include <ipxe/xen.h> +#include <ipxe/xenstore.h> +#include <ipxe/xenbus.h> +#include <ipxe/xengrant.h> +#include <ipxe/xenevent.h> +#include "netfront.h" + +/** @file + * + * Xen netfront driver + * + */ + +/* Disambiguate the various error causes */ +#define EIO_NETIF_RSP_ERROR \ + __einfo_error ( EINFO_EIO_NETIF_RSP_ERROR ) +#define EINFO_EIO_NETIF_RSP_ERROR \ + __einfo_uniqify ( EINFO_EIO, -NETIF_RSP_ERROR, \ + "Unspecified network error" ) +#define EIO_NETIF_RSP_DROPPED \ + __einfo_error ( EINFO_EIO_NETIF_RSP_DROPPED ) +#define EINFO_EIO_NETIF_RSP_DROPPED \ + __einfo_uniqify ( EINFO_EIO, -NETIF_RSP_DROPPED, \ + "Packet dropped" ) +#define EIO_NETIF_RSP( status ) \ + EUNIQ ( EINFO_EIO, -(status), \ + EIO_NETIF_RSP_ERROR, EIO_NETIF_RSP_DROPPED ) + +/****************************************************************************** + * + * XenStore interface + * + ****************************************************************************** + */ + +/** + * Reset device + * + * @v netfront Netfront device + * @ret rc Return status code + */ +static int netfront_reset ( struct netfront_nic *netfront ) { + struct xen_device *xendev = netfront->xendev; + int state; + int rc; + + /* Get current backend state */ + if ( ( state = xenbus_backend_state ( xendev ) ) < 0 ) { + rc = state; + DBGC ( netfront, "NETFRONT %s could not read backend state: " + "%s\n", xendev->key, strerror ( rc ) ); + return rc; + } + + /* If the backend is not already in InitWait, then mark + * frontend as Closed to shut down the backend. + */ + if ( state != XenbusStateInitWait ) { + + /* Set state to Closed */ + xenbus_set_state ( xendev, XenbusStateClosed ); + + /* Wait for backend to reach Closed */ + if ( ( rc = xenbus_backend_wait ( xendev, + XenbusStateClosed ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s backend did not reach " + "Closed: %s\n", xendev->key, strerror ( rc ) ); + return rc; + } + } + + /* Reset state to Initialising */ + xenbus_set_state ( xendev, XenbusStateInitialising ); + + /* Wait for backend to reach InitWait */ + if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateInitWait ) ) != 0){ + DBGC ( netfront, "NETFRONT %s backend did not reach InitWait: " + "%s\n", xendev->key, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Fetch MAC address + * + * @v netfront Netfront device + * @v hw_addr Hardware address to fill in + * @ret rc Return status code + */ +static int netfront_read_mac ( struct netfront_nic *netfront, void *hw_addr ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + char *mac; + int len; + int rc; + + /* Fetch MAC address */ + if ( ( rc = xenstore_read ( xen, &mac, xendev->key, "mac", NULL ) )!=0){ + DBGC ( netfront, "NETFRONT %s could not read MAC address: %s\n", + xendev->key, strerror ( rc ) ); + goto err_xenstore_read; + } + DBGC2 ( netfront, "NETFRONT %s has MAC address \"%s\"\n", + xendev->key, mac ); + + /* Decode MAC address */ + len = hex_decode ( mac, ':', hw_addr, ETH_ALEN ); + if ( len < 0 ) { + rc = len; + DBGC ( netfront, "NETFRONT %s could not decode MAC address " + "\"%s\": %s\n", xendev->key, mac, strerror ( rc ) ); + goto err_decode; + } + + /* Success */ + rc = 0; + + err_decode: + free ( mac ); + err_xenstore_read: + return rc; +} + +/** + * Write XenStore numeric value + * + * @v netfront Netfront device + * @v subkey Subkey + * @v num Numeric value + * @ret rc Return status code + */ +static int netfront_write_num ( struct netfront_nic *netfront, + const char *subkey, unsigned long num ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + int rc; + + /* Write value */ + if ( ( rc = xenstore_write_num ( xen, num, xendev->key, subkey, + NULL ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not set %s=\"%ld\": %s\n", + xendev->key, subkey, num, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Write XenStore flag value + * + * @v netfront Netfront device + * @v subkey Subkey + * @v num Numeric value + * @ret rc Return status code + */ +static int netfront_write_flag ( struct netfront_nic *netfront, + const char *subkey ) { + + return netfront_write_num ( netfront, subkey, 1 ); +} + +/** + * Delete XenStore value + * + * @v netfront Netfront device + * @v subkey Subkey + * @ret rc Return status code + */ +static int netfront_rm ( struct netfront_nic *netfront, const char *subkey ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + int rc; + + /* Remove value */ + if ( ( rc = xenstore_rm ( xen, xendev->key, subkey, NULL ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not delete %s: %s\n", + xendev->key, subkey, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/****************************************************************************** + * + * Events + * + ****************************************************************************** + */ + +/** + * Create event channel + * + * @v netfront Netfront device + * @ret rc Return status code + */ +static int netfront_create_event ( struct netfront_nic *netfront ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + struct evtchn_alloc_unbound alloc_unbound; + struct evtchn_close close; + int xenrc; + int rc; + + /* Allocate event */ + alloc_unbound.dom = DOMID_SELF; + alloc_unbound.remote_dom = xendev->backend_id; + if ( ( xenrc = xenevent_alloc_unbound ( xen, &alloc_unbound ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( netfront, "NETFRONT %s could not allocate event: %s\n", + xendev->key, strerror ( rc ) ); + goto err_alloc_unbound; + } + netfront->event.port = alloc_unbound.port; + + /* Publish event channel */ + if ( ( rc = netfront_write_num ( netfront, "event-channel", + netfront->event.port ) ) != 0 ) + goto err_write_num; + + DBGC ( netfront, "NETFRONT %s event-channel=\"%d\"\n", + xendev->key, netfront->event.port ); + return 0; + + netfront_rm ( netfront, "event-channel" ); + err_write_num: + close.port = netfront->event.port; + xenevent_close ( xen, &close ); + err_alloc_unbound: + return rc; +} + +/** + * Send event + * + * @v netfront Netfront device + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +netfront_send_event ( struct netfront_nic *netfront ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + int xenrc; + int rc; + + /* Send event */ + if ( ( xenrc = xenevent_send ( xen, &netfront->event ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( netfront, "NETFRONT %s could not send event: %s\n", + xendev->key, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Destroy event channel + * + * @v netfront Netfront device + */ +static void netfront_destroy_event ( struct netfront_nic *netfront ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + struct evtchn_close close; + + /* Unpublish event channel */ + netfront_rm ( netfront, "event-channel" ); + + /* Close event channel */ + close.port = netfront->event.port; + xenevent_close ( xen, &close ); +} + +/****************************************************************************** + * + * Descriptor rings + * + ****************************************************************************** + */ + +/** + * Create descriptor ring + * + * @v netfront Netfront device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int netfront_create_ring ( struct netfront_nic *netfront, + struct netfront_ring *ring ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + unsigned int i; + int rc; + + /* Initialise buffer ID ring */ + for ( i = 0 ; i < ring->count ; i++ ) { + ring->ids[i] = i; + assert ( ring->iobufs[i] == NULL ); + } + ring->id_prod = 0; + ring->id_cons = 0; + + /* Allocate and initialise shared ring */ + ring->sring.raw = malloc_dma ( PAGE_SIZE, PAGE_SIZE ); + if ( ! ring->sring.raw ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Grant access to shared ring */ + if ( ( rc = xengrant_permit_access ( xen, ring->ref, xendev->backend_id, + 0, ring->sring.raw ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not permit access to " + "%#08lx: %s\n", xendev->key, + virt_to_phys ( ring->sring.raw ), strerror ( rc ) ); + goto err_permit_access; + } + + /* Publish shared ring reference */ + if ( ( rc = netfront_write_num ( netfront, ring->ref_key, + ring->ref ) ) != 0 ) + goto err_write_num; + + DBGC ( netfront, "NETFRONT %s %s=\"%d\" [%08lx,%08lx)\n", + xendev->key, ring->ref_key, ring->ref, + virt_to_phys ( ring->sring.raw ), + ( virt_to_phys ( ring->sring.raw ) + PAGE_SIZE ) ); + return 0; + + netfront_rm ( netfront, ring->ref_key ); + err_write_num: + xengrant_invalidate ( xen, ring->ref ); + err_permit_access: + free_dma ( ring->sring.raw, PAGE_SIZE ); + err_alloc: + return rc; +} + +/** + * Add buffer to descriptor ring + * + * @v netfront Netfront device + * @v ring Descriptor ring + * @v iobuf I/O buffer + * @v id Buffer ID to fill in + * @v ref Grant reference to fill in + * @ret rc Return status code + * + * The caller is responsible for ensuring that there is space in the + * ring. + */ +static int netfront_push ( struct netfront_nic *netfront, + struct netfront_ring *ring, struct io_buffer *iobuf, + uint16_t *id, grant_ref_t *ref ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + unsigned int next_id; + unsigned int next_ref; + int rc; + + /* Sanity check */ + assert ( ! netfront_ring_is_full ( ring ) ); + + /* Allocate buffer ID */ + next_id = ring->ids[ ring->id_prod & ( ring->count - 1 ) ]; + next_ref = ring->refs[next_id]; + + /* Grant access to I/O buffer page. I/O buffers are naturally + * aligned, so we never need to worry about crossing a page + * boundary. + */ + if ( ( rc = xengrant_permit_access ( xen, next_ref, xendev->backend_id, + 0, iobuf->data ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not permit access to " + "%#08lx: %s\n", xendev->key, + virt_to_phys ( iobuf->data ), strerror ( rc ) ); + return rc; + } + + /* Store I/O buffer */ + assert ( ring->iobufs[next_id] == NULL ); + ring->iobufs[next_id] = iobuf; + + /* Consume buffer ID */ + ring->id_prod++; + + /* Return buffer ID and grant reference */ + *id = next_id; + *ref = next_ref; + + return 0; +} + +/** + * Remove buffer from descriptor ring + * + * @v netfront Netfront device + * @v ring Descriptor ring + * @v id Buffer ID + * @ret iobuf I/O buffer + */ +static struct io_buffer * netfront_pull ( struct netfront_nic *netfront, + struct netfront_ring *ring, + unsigned int id ) { + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + struct io_buffer *iobuf; + + /* Sanity check */ + assert ( id < ring->count ); + + /* Revoke access from I/O buffer page */ + xengrant_invalidate ( xen, ring->refs[id] ); + + /* Retrieve I/O buffer */ + iobuf = ring->iobufs[id]; + assert ( iobuf != NULL ); + ring->iobufs[id] = NULL; + + /* Free buffer ID */ + ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = id; + + return iobuf; +} + +/** + * Destroy descriptor ring + * + * @v netfront Netfront device + * @v ring Descriptor ring + * @v discard Method used to discard outstanding buffer, or NULL + */ +static void netfront_destroy_ring ( struct netfront_nic *netfront, + struct netfront_ring *ring, + void ( * discard ) ( struct io_buffer * ) ){ + struct xen_device *xendev = netfront->xendev; + struct xen_hypervisor *xen = xendev->xen; + struct io_buffer *iobuf; + unsigned int id; + + /* Flush any outstanding buffers */ + while ( ! netfront_ring_is_empty ( ring ) ) { + id = ring->ids[ ring->id_cons & ( ring->count - 1 ) ]; + iobuf = netfront_pull ( netfront, ring, id ); + if ( discard ) + discard ( iobuf ); + } + + /* Unpublish shared ring reference */ + netfront_rm ( netfront, ring->ref_key ); + + /* Revoke access from shared ring */ + xengrant_invalidate ( xen, ring->ref ); + + /* Free page */ + free_dma ( ring->sring.raw, PAGE_SIZE ); + ring->sring.raw = NULL; +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Refill receive descriptor ring + * + * @v netdev Network device + */ +static void netfront_refill_rx ( struct net_device *netdev ) { + struct netfront_nic *netfront = netdev->priv; + struct xen_device *xendev = netfront->xendev; + struct io_buffer *iobuf; + struct netif_rx_request *request; + int notify; + int rc; + + /* Do nothing if ring is already full */ + if ( netfront_ring_is_full ( &netfront->rx ) ) + return; + + /* Refill ring */ + do { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( PAGE_SIZE ); + if ( ! iobuf ) { + /* Wait for next refill */ + break; + } + + /* Add to descriptor ring */ + request = RING_GET_REQUEST ( &netfront->rx_fring, + netfront->rx_fring.req_prod_pvt ); + if ( ( rc = netfront_push ( netfront, &netfront->rx, + iobuf, &request->id, + &request->gref ) ) != 0 ) { + netdev_rx_err ( netdev, iobuf, rc ); + break; + } + DBGC2 ( netfront, "NETFRONT %s RX id %d ref %d is %#08lx+%zx\n", + xendev->key, request->id, request->gref, + virt_to_phys ( iobuf->data ), iob_tailroom ( iobuf ) ); + + /* Move to next descriptor */ + netfront->rx_fring.req_prod_pvt++; + + } while ( ! netfront_ring_is_full ( &netfront->rx ) ); + + /* Push new descriptors and notify backend if applicable */ + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring, notify ); + if ( notify ) + netfront_send_event ( netfront ); +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int netfront_open ( struct net_device *netdev ) { + struct netfront_nic *netfront = netdev->priv; + struct xen_device *xendev = netfront->xendev; + int rc; + + /* Ensure device is in a suitable initial state */ + if ( ( rc = netfront_reset ( netfront ) ) != 0 ) + goto err_reset; + + /* Create transmit descriptor ring */ + if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 ) + goto err_create_tx; + SHARED_RING_INIT ( netfront->tx_sring ); + FRONT_RING_INIT ( &netfront->tx_fring, netfront->tx_sring, PAGE_SIZE ); + assert ( RING_SIZE ( &netfront->tx_fring ) >= netfront->tx.count ); + + /* Create receive descriptor ring */ + if ( ( rc = netfront_create_ring ( netfront, &netfront->rx ) ) != 0 ) + goto err_create_rx; + SHARED_RING_INIT ( netfront->rx_sring ); + FRONT_RING_INIT ( &netfront->rx_fring, netfront->rx_sring, PAGE_SIZE ); + assert ( RING_SIZE ( &netfront->rx_fring ) >= netfront->rx.count ); + + /* Create event channel */ + if ( ( rc = netfront_create_event ( netfront ) ) != 0 ) + goto err_create_event; + + /* "Request" the rx-copy feature. Current versions of + * xen_netback.ko will fail silently if this parameter is not + * present. + */ + if ( ( rc = netfront_write_flag ( netfront, "request-rx-copy" ) ) != 0 ) + goto err_request_rx_copy; + + /* Disable checksum offload, since we will always do the work anyway */ + if ( ( rc = netfront_write_flag ( netfront, + "feature-no-csum-offload" ) ) != 0 ) + goto err_feature_no_csum_offload; + + /* Set state to Connected */ + if ( ( rc = xenbus_set_state ( xendev, XenbusStateConnected ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not set state=\"%d\": %s\n", + xendev->key, XenbusStateConnected, strerror ( rc ) ); + goto err_set_state; + } + + /* Wait for backend to connect */ + if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateConnected ) ) !=0){ + DBGC ( netfront, "NETFRONT %s could not connect to backend: " + "%s\n", xendev->key, strerror ( rc ) ); + goto err_backend_wait; + } + + /* Refill receive descriptor ring */ + netfront_refill_rx ( netdev ); + + /* Set link up */ + netdev_link_up ( netdev ); + + return 0; + + err_backend_wait: + netfront_reset ( netfront ); + err_set_state: + netfront_rm ( netfront, "feature-no-csum-offload" ); + err_feature_no_csum_offload: + netfront_rm ( netfront, "request-rx-copy" ); + err_request_rx_copy: + netfront_destroy_event ( netfront ); + err_create_event: + netfront_destroy_ring ( netfront, &netfront->rx, NULL ); + err_create_rx: + netfront_destroy_ring ( netfront, &netfront->tx, NULL ); + err_create_tx: + err_reset: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void netfront_close ( struct net_device *netdev ) { + struct netfront_nic *netfront = netdev->priv; + struct xen_device *xendev = netfront->xendev; + int rc; + + /* Reset devic, thereby ensuring that grant references are no + * longer in use, etc. + */ + if ( ( rc = netfront_reset ( netfront ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not disconnect from " + "backend: %s\n", xendev->key, strerror ( rc ) ); + /* Things will probably go _very_ badly wrong if this + * happens, since it means the backend may still write + * to the outstanding RX buffers that we are about to + * free. The best we can do is report the error via + * the link status, but there's a good chance the + * machine will crash soon. + */ + netdev_link_err ( netdev, rc ); + } else { + netdev_link_down ( netdev ); + } + + /* Delete flags */ + netfront_rm ( netfront, "feature-no-csum-offload" ); + netfront_rm ( netfront, "request-rx-copy" ); + + /* Destroy event channel */ + netfront_destroy_event ( netfront ); + + /* Destroy receive descriptor ring, freeing any outstanding + * I/O buffers. + */ + netfront_destroy_ring ( netfront, &netfront->rx, free_iob ); + + /* Destroy transmit descriptor ring. Leave any outstanding + * I/O buffers to be freed by netdev_tx_flush(). + */ + netfront_destroy_ring ( netfront, &netfront->tx, NULL ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int netfront_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct netfront_nic *netfront = netdev->priv; + struct xen_device *xendev = netfront->xendev; + struct netif_tx_request *request; + int notify; + int rc; + + /* Check that we have space in the ring */ + if ( netfront_ring_is_full ( &netfront->tx ) ) { + DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n", + xendev->key ); + return -ENOBUFS; + } + + /* Add to descriptor ring */ + request = RING_GET_REQUEST ( &netfront->tx_fring, + netfront->tx_fring.req_prod_pvt ); + if ( ( rc = netfront_push ( netfront, &netfront->tx, iobuf, + &request->id, &request->gref ) ) != 0 ) { + return rc; + } + request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) ); + request->flags = NETTXF_data_validated; + request->size = iob_len ( iobuf ); + DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n", + xendev->key, request->id, request->gref, + virt_to_phys ( iobuf->data ), iob_len ( iobuf ) ); + + /* Consume descriptor */ + netfront->tx_fring.req_prod_pvt++; + + /* Push new descriptor and notify backend if applicable */ + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify ); + if ( notify ) + netfront_send_event ( netfront ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void netfront_poll_tx ( struct net_device *netdev ) { + struct netfront_nic *netfront = netdev->priv; + struct xen_device *xendev = netfront->xendev; + struct netif_tx_response *response; + struct io_buffer *iobuf; + unsigned int status; + int rc; + + /* Consume any unconsumed responses */ + while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->tx_fring ) ) { + + /* Get next response */ + response = RING_GET_RESPONSE ( &netfront->tx_fring, + netfront->tx_fring.rsp_cons++ ); + + /* Retrieve from descriptor ring */ + iobuf = netfront_pull ( netfront, &netfront->tx, response->id ); + status = response->status; + if ( status == NETIF_RSP_OKAY ) { + DBGC2 ( netfront, "NETFRONT %s TX id %d complete\n", + xendev->key, response->id ); + netdev_tx_complete ( netdev, iobuf ); + } else { + rc = -EIO_NETIF_RSP ( status ); + DBGC2 ( netfront, "NETFRONT %s TX id %d error %d: %s\n", + xendev->key, response->id, status, + strerror ( rc ) ); + netdev_tx_complete_err ( netdev, iobuf, rc ); + } + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void netfront_poll_rx ( struct net_device *netdev ) { + struct netfront_nic *netfront = netdev->priv; + struct xen_device *xendev = netfront->xendev; + struct netif_rx_response *response; + struct io_buffer *iobuf; + int status; + size_t len; + int rc; + + /* Consume any unconsumed responses */ + while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->rx_fring ) ) { + + /* Get next response */ + response = RING_GET_RESPONSE ( &netfront->rx_fring, + netfront->rx_fring.rsp_cons++ ); + + /* Retrieve from descriptor ring */ + iobuf = netfront_pull ( netfront, &netfront->rx, response->id ); + status = response->status; + if ( status >= 0 ) { + len = status; + iob_reserve ( iobuf, response->offset ); + iob_put ( iobuf, len ); + DBGC2 ( netfront, "NETFRONT %s RX id %d complete " + "%#08lx+%zx\n", xendev->key, response->id, + virt_to_phys ( iobuf->data ), len ); + netdev_rx ( netdev, iobuf ); + } else { + rc = -EIO_NETIF_RSP ( status ); + DBGC2 ( netfront, "NETFRONT %s RX id %d error %d: %s\n", + xendev->key, response->id, status, + strerror ( rc ) ); + netdev_rx_err ( netdev, iobuf, rc ); + } + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void netfront_poll ( struct net_device *netdev ) { + + /* Poll for TX completions */ + netfront_poll_tx ( netdev ); + + /* Poll for RX completions */ + netfront_poll_rx ( netdev ); + + /* Refill RX descriptor ring */ + netfront_refill_rx ( netdev ); +} + +/** Network device operations */ +static struct net_device_operations netfront_operations = { + .open = netfront_open, + .close = netfront_close, + .transmit = netfront_transmit, + .poll = netfront_poll, +}; + +/****************************************************************************** + * + * Xen device bus interface + * + ****************************************************************************** + */ + +/** + * Probe Xen device + * + * @v xendev Xen device + * @ret rc Return status code + */ +static int netfront_probe ( struct xen_device *xendev ) { + struct xen_hypervisor *xen = xendev->xen; + struct net_device *netdev; + struct netfront_nic *netfront; + int rc; + + /* Allocate and initialise structure */ + netdev = alloc_etherdev ( sizeof ( *netfront ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &netfront_operations ); + netdev->dev = &xendev->dev; + netfront = netdev->priv; + netfront->xendev = xendev; + DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n", + xendev->key, xendev->backend, xendev->backend_id ); + + /* Allocate grant references and initialise descriptor rings */ + if ( ( rc = xengrant_alloc ( xen, netfront->refs, + NETFRONT_REF_COUNT ) ) != 0 ) { + DBGC ( netfront, "NETFRONT %s could not allocate grant " + "references: %s\n", xendev->key, strerror ( rc ) ); + goto err_grant_alloc; + } + netfront_init_ring ( &netfront->tx, "tx-ring-ref", + netfront->refs[NETFRONT_REF_TX_RING], + NETFRONT_NUM_TX_DESC, netfront->tx_iobufs, + &netfront->refs[NETFRONT_REF_TX_BASE], + netfront->tx_ids ); + netfront_init_ring ( &netfront->rx, "rx-ring-ref", + netfront->refs[NETFRONT_REF_RX_RING], + NETFRONT_NUM_RX_DESC, netfront->rx_iobufs, + &netfront->refs[NETFRONT_REF_RX_BASE], + netfront->rx_ids ); + + /* Fetch MAC address */ + if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 ) + goto err_read_mac; + + /* Reset device. Ignore failures; allow the device to be + * registered so that reset errors can be observed by the user + * when attempting to open the device. + */ + netfront_reset ( netfront ); + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + netdev_link_down ( netdev ); + + xen_set_drvdata ( xendev, netdev ); + return 0; + + unregister_netdev ( netdev ); + err_register_netdev: + err_read_mac: + xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT ); + err_grant_alloc: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove Xen device + * + * @v xendev Xen device + */ +static void netfront_remove ( struct xen_device *xendev ) { + struct net_device *netdev = xen_get_drvdata ( xendev ); + struct netfront_nic *netfront = netdev->priv; + struct xen_hypervisor *xen = xendev->xen; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Free resources */ + xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Xen netfront driver */ +struct xen_driver netfront_driver __xen_driver = { + .name = "netfront", + .type = "vif", + .probe = netfront_probe, + .remove = netfront_remove, +}; diff --git a/roms/ipxe/src/drivers/net/netfront.h b/roms/ipxe/src/drivers/net/netfront.h new file mode 100644 index 000000000..b3f899f3c --- /dev/null +++ b/roms/ipxe/src/drivers/net/netfront.h @@ -0,0 +1,153 @@ +#ifndef _NETFRONT_H +#define _NETFRONT_H + +/** @file + * + * Xen netfront driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/xen.h> +#include <xen/io/netif.h> + +/** Number of transmit ring entries */ +#define NETFRONT_NUM_TX_DESC 16 + +/** Number of receive ring entries */ +#define NETFRONT_NUM_RX_DESC 8 + +/** Grant reference indices */ +enum netfront_ref_index { + /** Transmit ring grant reference index */ + NETFRONT_REF_TX_RING = 0, + /** Transmit descriptor grant reference base index */ + NETFRONT_REF_TX_BASE, + /** Receive ring grant reference index */ + NETFRONT_REF_RX_RING = ( NETFRONT_REF_TX_BASE + NETFRONT_NUM_TX_DESC ), + /** Receive descriptor grant reference base index */ + NETFRONT_REF_RX_BASE, + /** Total number of grant references required */ + NETFRONT_REF_COUNT = ( NETFRONT_REF_RX_BASE + NETFRONT_NUM_RX_DESC ) +}; + +/** A netfront descriptor ring */ +struct netfront_ring { + /** Shared ring */ + union { + /** Transmit shared ring */ + netif_tx_sring_t *tx; + /** Receive shared ring */ + netif_rx_sring_t *rx; + /** Raw pointer */ + void *raw; + } sring; + /** Shared ring grant reference key */ + const char *ref_key; + /** Shared ring grant reference */ + grant_ref_t ref; + + /** Maximum number of used descriptors */ + size_t count; + /** I/O buffers, indexed by buffer ID */ + struct io_buffer **iobufs; + /** I/O buffer grant references, indexed by buffer ID */ + grant_ref_t *refs; + + /** Buffer ID ring */ + uint8_t *ids; + /** Buffer ID ring producer counter */ + unsigned int id_prod; + /** Buffer ID ring consumer counter */ + unsigned int id_cons; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v ref_key Shared ring grant reference key + * @v ref Shared ring grant reference + * @v count Maxium number of used descriptors + * @v iobufs I/O buffers + * @v refs I/O buffer grant references + * @v ids Buffer IDs + */ +static inline __attribute__ (( always_inline )) void +netfront_init_ring ( struct netfront_ring *ring, const char *ref_key, + grant_ref_t ref, unsigned int count, + struct io_buffer **iobufs, grant_ref_t *refs, + uint8_t *ids ) { + + ring->ref_key = ref_key; + ring->ref = ref; + ring->count = count; + ring->iobufs = iobufs; + ring->refs = refs; + ring->ids = ids; +} + +/** + * Check whether or not descriptor ring is full + * + * @v ring Descriptor ring + * @v is_full Ring is full + */ +static inline __attribute__ (( always_inline )) int +netfront_ring_is_full ( struct netfront_ring *ring ) { + unsigned int fill_level; + + fill_level = ( ring->id_prod - ring->id_cons ); + assert ( fill_level <= ring->count ); + return ( fill_level >= ring->count ); +} + +/** + * Check whether or not descriptor ring is empty + * + * @v ring Descriptor ring + * @v is_empty Ring is empty + */ +static inline __attribute__ (( always_inline )) int +netfront_ring_is_empty ( struct netfront_ring *ring ) { + + return ( ring->id_prod == ring->id_cons ); +} + +/** A netfront NIC */ +struct netfront_nic { + /** Xen device */ + struct xen_device *xendev; + /** Grant references */ + grant_ref_t refs[NETFRONT_REF_COUNT]; + + /** Transmit ring */ + struct netfront_ring tx; + /** Transmit front ring */ + netif_tx_front_ring_t tx_fring; + /** Transmit I/O buffers */ + struct io_buffer *tx_iobufs[NETFRONT_NUM_TX_DESC]; + /** Transmit I/O buffer IDs */ + uint8_t tx_ids[NETFRONT_NUM_TX_DESC]; + + /** Receive ring */ + struct netfront_ring rx; + /** Receive front ring */ + netif_rx_front_ring_t rx_fring; + /** Receive I/O buffers */ + struct io_buffer *rx_iobufs[NETFRONT_NUM_RX_DESC]; + /** Receive I/O buffer IDs */ + uint8_t rx_ids[NETFRONT_NUM_RX_DESC]; + + /** Event channel */ + struct evtchn_send event; +}; + +/** Transmit shared ring field */ +#define tx_sring tx.sring.tx + +/** Receive shared ring field */ +#define rx_sring rx.sring.rx + +#endif /* _NETFRONT_H */ diff --git a/roms/ipxe/src/drivers/net/realtek.c b/roms/ipxe/src/drivers/net/realtek.c index 7964475a2..0aca8c77f 100644 --- a/roms/ipxe/src/drivers/net/realtek.c +++ b/roms/ipxe/src/drivers/net/realtek.c @@ -1119,6 +1119,10 @@ static int realtek_probe ( struct pci_device *pci ) { /* Map registers */ rtl->regs = ioremap ( pci->membase, RTL_BAR_SIZE ); + if ( ! rtl->regs ) { + rc = -ENODEV; + goto err_ioremap; + } /* Reset the NIC */ if ( ( rc = realtek_reset ( rtl ) ) != 0 ) @@ -1177,6 +1181,7 @@ static int realtek_probe ( struct pci_device *pci ) { realtek_reset ( rtl ); err_reset: iounmap ( rtl->regs ); + err_ioremap: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: diff --git a/roms/ipxe/src/drivers/net/skeleton.c b/roms/ipxe/src/drivers/net/skeleton.c index e50b778a8..365111b8d 100644 --- a/roms/ipxe/src/drivers/net/skeleton.c +++ b/roms/ipxe/src/drivers/net/skeleton.c @@ -241,6 +241,10 @@ static int skeleton_probe ( struct pci_device *pci ) { /* Map registers */ skel->regs = ioremap ( pci->membase, SKELETON_BAR_SIZE ); + if ( ! skel->regs ) { + rc = -ENODEV; + goto err_ioremap; + } /* Reset the NIC */ if ( ( rc = skeleton_reset ( skel ) ) != 0 ) @@ -269,6 +273,7 @@ static int skeleton_probe ( struct pci_device *pci ) { skeleton_reset ( skel ); err_reset: iounmap ( skel->regs ); + err_ioremap: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc: diff --git a/roms/ipxe/src/drivers/net/smc9000.c b/roms/ipxe/src/drivers/net/smc9000.c index 31e418a97..c9762d580 100644 --- a/roms/ipxe/src/drivers/net/smc9000.c +++ b/roms/ipxe/src/drivers/net/smc9000.c @@ -882,7 +882,7 @@ static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) { /* is it using AUI or 10BaseT ? */ SMC_SELECT_BANK(nic->ioaddr, 1); - if (inw(nic->ioaddr + CONFIG) & CFG_AUI_SELECT) + if (inw(nic->ioaddr + CFG) & CFG_AUI_SELECT) media = 2; else media = 1; @@ -911,12 +911,12 @@ static int smc9000_probe ( struct nic *nic, struct isa_device *isa ) { /* Select which interface to use */ SMC_SELECT_BANK(nic->ioaddr, 1); if ( media == 1 ) { - _outw( inw( nic->ioaddr + CONFIG ) & ~CFG_AUI_SELECT, - nic->ioaddr + CONFIG ); + _outw( inw( nic->ioaddr + CFG ) & ~CFG_AUI_SELECT, + nic->ioaddr + CFG ); } else if ( media == 2 ) { - _outw( inw( nic->ioaddr + CONFIG ) | CFG_AUI_SELECT, - nic->ioaddr + CONFIG ); + _outw( inw( nic->ioaddr + CFG ) | CFG_AUI_SELECT, + nic->ioaddr + CFG ); } smc_phy_configure(nic->ioaddr); diff --git a/roms/ipxe/src/drivers/net/smc9000.h b/roms/ipxe/src/drivers/net/smc9000.h index 02b1c831c..8e655f08d 100644 --- a/roms/ipxe/src/drivers/net/smc9000.h +++ b/roms/ipxe/src/drivers/net/smc9000.h @@ -131,7 +131,7 @@ typedef unsigned long int dword; #define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) /* BANK 1 */ -#define CONFIG 0 +#define CFG 0 #define CFG_AUI_SELECT 0x100 #define BASE 2 #define ADDR0 4 diff --git a/roms/ipxe/src/drivers/net/vmxnet3.c b/roms/ipxe/src/drivers/net/vmxnet3.c index 9401c110e..31082bf6f 100644 --- a/roms/ipxe/src/drivers/net/vmxnet3.c +++ b/roms/ipxe/src/drivers/net/vmxnet3.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/pci.h> #include <ipxe/io.h> #include <ipxe/malloc.h> +#include <ipxe/profile.h> #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> #include <ipxe/if_ether.h> @@ -39,6 +40,22 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** VM command profiler */ +static struct profiler vmxnet3_vm_command_profiler __profiler = + { .name = "vmxnet3.vm_command" }; + +/** VM transmit profiler */ +static struct profiler vmxnet3_vm_tx_profiler __profiler = + { .name = "vmxnet3.vm_tx" }; + +/** VM receive refill profiler */ +static struct profiler vmxnet3_vm_refill_profiler __profiler = + { .name = "vmxnet3.vm_refill" }; + +/** VM event profiler */ +static struct profiler vmxnet3_vm_event_profiler __profiler = + { .name = "vmxnet3.vm_event" }; + /** * Issue command * @@ -48,10 +65,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ static inline uint32_t vmxnet3_command ( struct vmxnet3_nic *vmxnet, uint32_t command ) { + uint32_t result; /* Issue command */ + profile_start ( &vmxnet3_vm_command_profiler ); writel ( command, ( vmxnet->vd + VMXNET3_VD_CMD ) ); - return readl ( vmxnet->vd + VMXNET3_VD_CMD ); + result = readl ( vmxnet->vd + VMXNET3_VD_CMD ); + profile_stop ( &vmxnet3_vm_command_profiler ); + profile_exclude ( &vmxnet3_vm_command_profiler ); + + return result; } /** @@ -92,8 +115,11 @@ static int vmxnet3_transmit ( struct net_device *netdev, /* Hand over descriptor to NIC */ wmb(); + profile_start ( &vmxnet3_vm_tx_profiler ); writel ( ( vmxnet->count.tx_prod % VMXNET3_NUM_TX_DESC ), ( vmxnet->pt + VMXNET3_PT_TXPROD ) ); + profile_stop ( &vmxnet3_vm_tx_profiler ); + profile_exclude ( &vmxnet3_vm_tx_profiler ); return 0; } @@ -212,8 +238,11 @@ static void vmxnet3_refill_rx ( struct net_device *netdev ) { /* Hand over any new descriptors to NIC */ if ( vmxnet->count.rx_prod != orig_rx_prod ) { wmb(); + profile_start ( &vmxnet3_vm_refill_profiler ); writel ( ( vmxnet->count.rx_prod % VMXNET3_NUM_RX_DESC ), ( vmxnet->pt + VMXNET3_PT_RXPROD ) ); + profile_stop ( &vmxnet3_vm_refill_profiler ); + profile_exclude ( &vmxnet3_vm_refill_profiler ); } } @@ -331,7 +360,10 @@ static void vmxnet3_poll_events ( struct net_device *netdev ) { events = le32_to_cpu ( vmxnet->dma->shared.ecr ); /* Acknowledge these events */ + profile_start ( &vmxnet3_vm_event_profiler ); writel ( events, ( vmxnet->vd + VMXNET3_VD_ECR ) ); + profile_stop ( &vmxnet3_vm_event_profiler ); + profile_exclude ( &vmxnet3_vm_event_profiler ); /* Check for link state change */ if ( events & VMXNET3_ECR_LINK ) { @@ -602,8 +634,16 @@ static int vmxnet3_probe ( struct pci_device *pci ) { /* Map PCI BARs */ vmxnet->pt = ioremap ( pci_bar_start ( pci, VMXNET3_PT_BAR ), VMXNET3_PT_LEN ); + if ( ! vmxnet->pt ) { + rc = -ENODEV; + goto err_ioremap_pt; + } vmxnet->vd = ioremap ( pci_bar_start ( pci, VMXNET3_VD_BAR ), VMXNET3_VD_LEN ); + if ( ! vmxnet->vd ) { + rc = -ENODEV; + goto err_ioremap_vd; + } /* Version check */ if ( ( rc = vmxnet3_check_version ( vmxnet ) ) != 0 ) @@ -633,7 +673,9 @@ static int vmxnet3_probe ( struct pci_device *pci ) { err_reset: err_check_version: iounmap ( vmxnet->vd ); + err_ioremap_vd: iounmap ( vmxnet->pt ); + err_ioremap_pt: netdev_nullify ( netdev ); netdev_put ( netdev ); err_alloc_etherdev: diff --git a/roms/ipxe/src/hci/commands/ping_cmd.c b/roms/ipxe/src/hci/commands/ping_cmd.c index d514a2a27..34807696f 100644 --- a/roms/ipxe/src/hci/commands/ping_cmd.c +++ b/roms/ipxe/src/hci/commands/ping_cmd.c @@ -48,6 +48,10 @@ struct ping_options { unsigned int size; /** Timeout (in ms) */ unsigned long timeout; + /** Number of packets to send (or zero for no limit) */ + unsigned int count; + /** Inhibit output */ + int quiet; }; /** "ping" option list */ @@ -56,6 +60,10 @@ static struct option_descriptor ping_opts[] = { struct ping_options, size, parse_integer ), OPTION_DESC ( "timeout", 't', required_argument, struct ping_options, timeout, parse_timeout ), + OPTION_DESC ( "count", 'c', required_argument, + struct ping_options, count, parse_integer ), + OPTION_DESC ( "quiet", 'q', no_argument, + struct ping_options, quiet, parse_flag ), }; /** "ping" command descriptor */ @@ -87,7 +95,8 @@ static int ping_exec ( int argc, char **argv ) { hostname = argv[optind]; /* Ping */ - if ( ( rc = ping ( hostname, opts.timeout, opts.size ) ) != 0 ) + if ( ( rc = ping ( hostname, opts.timeout, opts.size, + opts.count, opts.quiet ) ) != 0 ) return rc; return 0; diff --git a/roms/ipxe/src/hci/editstring.c b/roms/ipxe/src/hci/editstring.c index 8c56d2337..5f6f04d51 100644 --- a/roms/ipxe/src/hci/editstring.c +++ b/roms/ipxe/src/hci/editstring.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <assert.h> #include <string.h> +#include <ctype.h> #include <ipxe/keys.h> #include <ipxe/editstring.h> @@ -37,6 +38,8 @@ static void insert_character ( struct edit_string *string, unsigned int character ) __nonnull; static void delete_character ( struct edit_string *string ) __nonnull; static void backspace ( struct edit_string *string ) __nonnull; +static void previous_word ( struct edit_string *string ) __nonnull; +static void kill_word ( struct edit_string *string ) __nonnull; static void kill_sol ( struct edit_string *string ) __nonnull; static void kill_eol ( struct edit_string *string ) __nonnull; @@ -111,9 +114,36 @@ static void backspace ( struct edit_string *string ) { } /** + * Move to start of previous word + * + * @v string Editable string + */ +static void previous_word ( struct edit_string *string ) { + while ( string->cursor && + isspace ( string->buf[ string->cursor - 1 ] ) ) { + string->cursor--; + } + while ( string->cursor && + ( ! isspace ( string->buf[ string->cursor - 1 ] ) ) ) { + string->cursor--; + } +} + +/** + * Delete to end of previous word + * + * @v string Editable string + */ +static void kill_word ( struct edit_string *string ) { + size_t old_cursor = string->cursor; + previous_word ( string ); + insert_delete ( string, ( old_cursor - string->cursor ), NULL ); +} + +/** * Delete to start of line * - * @v string Editable string + * @v string Editable string */ static void kill_sol ( struct edit_string *string ) { size_t old_cursor = string->cursor; @@ -181,6 +211,10 @@ int edit_string ( struct edit_string *string, int key ) { /* Delete character */ delete_character ( string ); break; + case CTRL_W: + /* Delete word */ + kill_word ( string ); + break; case CTRL_U: /* Delete to start of line */ kill_sol ( string ); diff --git a/roms/ipxe/src/hci/readline.c b/roms/ipxe/src/hci/readline.c index d67980b2c..40aa59787 100644 --- a/roms/ipxe/src/hci/readline.c +++ b/roms/ipxe/src/hci/readline.c @@ -266,6 +266,9 @@ int readline_history ( const char *prompt, const char *prefill, if ( prompt ) printf ( "%s", prompt ); + /* Ensure cursor is visible */ + printf ( "\033[?25h" ); + /* Initialise editable string */ memset ( &string, 0, sizeof ( string ) ); init_editstring ( &string, buf, sizeof ( buf ) ); diff --git a/roms/ipxe/src/image/efi_image.c b/roms/ipxe/src/image/efi_image.c index 5de915b0a..b7d8f9c6e 100644 --- a/roms/ipxe/src/image/efi_image.c +++ b/roms/ipxe/src/image/efi_image.c @@ -26,8 +26,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/efi/efi_snp.h> #include <ipxe/efi/efi_download.h> #include <ipxe/efi/efi_file.h> -#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_utils.h> #include <ipxe/efi/efi_strings.h> +#include <ipxe/efi/efi_wrap.h> #include <ipxe/image.h> #include <ipxe/init.h> #include <ipxe/features.h> @@ -51,10 +52,6 @@ FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 ); "Could not start image" ) #define EEFI_START( efirc ) EPLATFORM ( EINFO_EEFI_START, efirc ) -/** EFI loaded image protocol GUID */ -static EFI_GUID efi_loaded_image_protocol_guid = - EFI_LOADED_IMAGE_PROTOCOL_GUID; - /** * Create device path for image * @@ -156,21 +153,21 @@ static int efi_image_exec ( struct image *image ) { } /* Install file I/O protocols */ - if ( ( rc = efi_file_install ( &snpdev->handle ) ) != 0 ) { + if ( ( rc = efi_file_install ( snpdev->handle ) ) != 0 ) { DBGC ( image, "EFIIMAGE %p could not install file protocol: " "%s\n", image, strerror ( rc ) ); goto err_file_install; } /* Install iPXE download protocol */ - if ( ( rc = efi_download_install ( &snpdev->handle ) ) != 0 ) { + if ( ( rc = efi_download_install ( snpdev->handle ) ) != 0 ) { DBGC ( image, "EFIIMAGE %p could not install iPXE download " "protocol: %s\n", image, strerror ( rc ) ); goto err_download_install; } /* Create device path for image */ - path = efi_image_path ( image, &snpdev->path ); + path = efi_image_path ( image, snpdev->path ); if ( ! path ) { DBGC ( image, "EFIIMAGE %p could not create device path\n", image ); @@ -208,6 +205,13 @@ static int efi_image_exec ( struct image *image ) { goto err_open_protocol; } + /* Some EFI 1.10 implementations seem not to fill in DeviceHandle */ + if ( loaded.image->DeviceHandle == NULL ) { + DBGC ( image, "EFIIMAGE %p filling in missing DeviceHandle\n", + image ); + loaded.image->DeviceHandle = snpdev->handle; + } + /* Sanity checks */ assert ( loaded.image->ParentHandle == efi_image_handle ); assert ( loaded.image->DeviceHandle == snpdev->handle ); @@ -222,11 +226,14 @@ static int efi_image_exec ( struct image *image ) { /* Release network devices for use via SNP */ efi_snp_release(); + /* Wrap calls made by the loaded image (for debugging) */ + efi_wrap ( handle ); + /* Start the image */ if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) { rc = -EEFI_START ( efirc ); - DBGC ( image, "EFIIMAGE %p returned with status %s\n", - image, strerror ( rc ) ); + DBGC ( image, "EFIIMAGE %p could not start (or returned with " + "error): %s\n", image, strerror ( rc ) ); goto err_start_image; } @@ -236,14 +243,22 @@ static int efi_image_exec ( struct image *image ) { err_start_image: efi_snp_claim(); err_open_protocol: - /* Unload the image. We can't leave it loaded, because we - * have no "unload" operation. + /* If there was no error, then the image must have been + * started and returned successfully. It either unloaded + * itself, or it intended to remain loaded (e.g. it was a + * driver). We therefore do not unload successful images. + * + * If there was an error, attempt to unload the image. This + * may not work. In particular, there is no way to tell + * whether an error returned from StartImage() was due to + * being unable to start the image (in which case we probably + * should call UnloadImage()), or due to the image itself + * returning an error (in which case we probably should not + * call UnloadImage()). We therefore ignore any failures from + * the UnloadImage() call itself. */ - if ( ( efirc = bs->UnloadImage ( handle ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( image, "EFIIMAGE %p could not unload: %s\n", - image, strerror ( rc ) ); - } + if ( rc != 0 ) + bs->UnloadImage ( handle ); err_load_image: free ( cmdline ); err_cmdline: @@ -265,12 +280,17 @@ static int efi_image_exec ( struct image *image ) { */ static int efi_image_probe ( struct image *image ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + static EFI_DEVICE_PATH_PROTOCOL empty_path = { + .Type = END_DEVICE_PATH_TYPE, + .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, + .Length[0] = sizeof ( empty_path ), + }; EFI_HANDLE handle; EFI_STATUS efirc; int rc; /* Attempt loading image */ - if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL, + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, &empty_path, user_to_virt ( image->data, 0 ), image->len, &handle ) ) != 0 ) { /* Not an EFI image */ diff --git a/roms/ipxe/src/include/assert.h b/roms/ipxe/src/include/assert.h index 655cbdc03..a33f6017c 100644 --- a/roms/ipxe/src/include/assert.h +++ b/roms/ipxe/src/include/assert.h @@ -20,6 +20,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); extern unsigned int assertion_failures; +#define ASSERTED ( ASSERTING && ( assertion_failures != 0 ) ) + /** printf() for assertions * * This function exists so that the assert() macro can expand to diff --git a/roms/ipxe/src/include/ipxe/device.h b/roms/ipxe/src/include/ipxe/device.h index c59697c03..7202a6966 100644 --- a/roms/ipxe/src/include/ipxe/device.h +++ b/roms/ipxe/src/include/ipxe/device.h @@ -57,6 +57,12 @@ struct device_description { /** TAP bus type */ #define BUS_TYPE_TAP 6 +/** EFI bus type */ +#define BUS_TYPE_EFI 7 + +/** Xen bus type */ +#define BUS_TYPE_XEN 8 + /** A hardware device */ struct device { /** Name */ diff --git a/roms/ipxe/src/include/ipxe/efi/Base.h b/roms/ipxe/src/include/ipxe/efi/Base.h index 2fb4ec6f6..844f428f1 100644 --- a/roms/ipxe/src/include/ipxe/efi/Base.h +++ b/roms/ipxe/src/include/ipxe/efi/Base.h @@ -6,7 +6,7 @@ environment. There are a set of base libraries in the Mde Package that can be used to implement base modules. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -81,21 +81,20 @@ VERIFY_SIZE_OF (CHAR16, 2); #endif // -// For symbol name in GNU assembly code, an extra "_" is necessary +// For symbol name in assembly code, an extra "_" is sometimes necessary // -#if defined(__GNUC__) - /// - /// Private worker functions for ASM_PFX() - /// - #define _CONCATENATE(a, b) __CONCATENATE(a, b) - #define __CONCATENATE(a, b) a ## b - /// - /// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix - /// on symbols in assembly language. - /// - #define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) -#endif +/// +/// Private worker functions for ASM_PFX() +/// +#define _CONCATENATE(a, b) __CONCATENATE(a, b) +#define __CONCATENATE(a, b) a ## b + +/// +/// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix +/// on symbols in assembly language. +/// +#define ASM_PFX(name) _CONCATENATE (__USER_LABEL_PREFIX__, name) #if __APPLE__ // @@ -208,6 +207,17 @@ struct _LIST_ENTRY { /// #define NULL ((VOID *) 0) +/// +/// Maximum values for common UEFI Data Types +/// +#define MAX_INT8 ((INT8)0x7F) +#define MAX_UINT8 ((UINT8)0xFF) +#define MAX_INT16 ((INT16)0x7FFF) +#define MAX_UINT16 ((UINT16)0xFFFF) +#define MAX_INT32 ((INT32)0x7FFFFFFF) +#define MAX_UINT32 ((UINT32)0xFFFFFFFF) +#define MAX_INT64 ((INT64)0x7FFFFFFFFFFFFFFFULL) +#define MAX_UINT64 ((UINT64)0xFFFFFFFFFFFFFFFFULL) #define BIT0 0x00000001 #define BIT1 0x00000002 diff --git a/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h b/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h index 89bce6ff9..16e30b358 100644 --- a/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h +++ b/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h @@ -1,7 +1,7 @@ /** @file Processor or Compiler specific defines and types for IA-32 architecture. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -229,6 +229,12 @@ typedef INT32 INTN; #define MAX_ADDRESS 0xFFFFFFFF /// +/// Maximum legal IA-32 INTN and UINTN values. +/// +#define MAX_INTN ((INTN)0x7FFFFFFF) +#define MAX_UINTN ((UINTN)0xFFFFFFFF) + +/// /// The stack alignment required for IA-32. /// #define CPU_STACK_ALIGNMENT sizeof(UINTN) @@ -280,5 +286,9 @@ typedef INT32 INTN; **/ #define FUNCTION_ENTRY_POINT(FunctionPointer) (VOID *)(UINTN)(FunctionPointer) +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + #endif diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Acpi10.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Acpi10.h new file mode 100644 index 000000000..78570479b --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Acpi10.h @@ -0,0 +1,663 @@ +/** @file + ACPI 1.0b definitions from the ACPI Specification, revision 1.0b + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#ifndef _ACPI_1_0_H_ +#define _ACPI_1_0_H_ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/IndustryStandard/AcpiAml.h> + +/// +/// Common table header, this prefaces all ACPI tables, including FACS, but +/// excluding the RSD PTR structure. +/// +typedef struct { + UINT32 Signature; + UINT32 Length; +} EFI_ACPI_COMMON_HEADER; + +#pragma pack(1) +/// +/// The common ACPI description table header. This structure prefaces most ACPI tables. +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT8 Revision; + UINT8 Checksum; + UINT8 OemId[6]; + UINT64 OemTableId; + UINT32 OemRevision; + UINT32 CreatorId; + UINT32 CreatorRevision; +} EFI_ACPI_DESCRIPTION_HEADER; +#pragma pack() + +// +// Define for Desriptor +// +#define ACPI_SMALL_ITEM_FLAG 0x00 +#define ACPI_LARGE_ITEM_FLAG 0x01 + +// +// Small Item Descriptor Name +// +#define ACPI_SMALL_IRQ_DESCRIPTOR_NAME 0x04 +#define ACPI_SMALL_DMA_DESCRIPTOR_NAME 0x05 +#define ACPI_SMALL_START_DEPENDENT_DESCRIPTOR_NAME 0x06 +#define ACPI_SMALL_END_DEPENDENT_DESCRIPTOR_NAME 0x07 +#define ACPI_SMALL_IO_PORT_DESCRIPTOR_NAME 0x08 +#define ACPI_SMALL_FIXED_IO_PORT_DESCRIPTOR_NAME 0x09 +#define ACPI_SMALL_VENDOR_DEFINED_DESCRIPTOR_NAME 0x0E +#define ACPI_SMALL_END_TAG_DESCRIPTOR_NAME 0x0F + +// +// Large Item Descriptor Name +// +#define ACPI_LARGE_24_BIT_MEMORY_RANGE_DESCRIPTOR_NAME 0x01 +#define ACPI_LARGE_VENDOR_DEFINED_DESCRIPTOR_NAME 0x04 +#define ACPI_LARGE_32_BIT_MEMORY_RANGE_DESCRIPTOR_NAME 0x05 +#define ACPI_LARGE_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR_NAME 0x06 +#define ACPI_LARGE_DWORD_ADDRESS_SPACE_DESCRIPTOR_NAME 0x07 +#define ACPI_LARGE_WORD_ADDRESS_SPACE_DESCRIPTOR_NAME 0x08 +#define ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME 0x09 +#define ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME 0x0A + +// +// Small Item Descriptor Value +// +#define ACPI_IRQ_NOFLAG_DESCRIPTOR 0x22 +#define ACPI_IRQ_DESCRIPTOR 0x23 +#define ACPI_DMA_DESCRIPTOR 0x2A +#define ACPI_START_DEPENDENT_DESCRIPTOR 0x30 +#define ACPI_START_DEPENDENT_EX_DESCRIPTOR 0x31 +#define ACPI_END_DEPENDENT_DESCRIPTOR 0x38 +#define ACPI_IO_PORT_DESCRIPTOR 0x47 +#define ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR 0x4B +#define ACPI_END_TAG_DESCRIPTOR 0x79 + +// +// Large Item Descriptor Value +// +#define ACPI_24_BIT_MEMORY_RANGE_DESCRIPTOR 0x81 +#define ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR 0x85 +#define ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR 0x86 +#define ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR 0x87 +#define ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR 0x88 +#define ACPI_EXTENDED_INTERRUPT_DESCRIPTOR 0x89 +#define ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR 0x8A +#define ACPI_ADDRESS_SPACE_DESCRIPTOR 0x8A + +// +// Resource Type +// +#define ACPI_ADDRESS_SPACE_TYPE_MEM 0x00 +#define ACPI_ADDRESS_SPACE_TYPE_IO 0x01 +#define ACPI_ADDRESS_SPACE_TYPE_BUS 0x02 + +/// +/// Power Management Timer frequency is fixed at 3.579545MHz. +/// +#define ACPI_TIMER_FREQUENCY 3579545 + +// +// Ensure proper structure formats +// +#pragma pack(1) + +/// +/// The commond definition of QWORD, DWORD, and WORD +/// Address Space Descriptors. +/// +typedef PACKED struct { + UINT8 Desc; + UINT16 Len; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT64 AddrSpaceGranularity; + UINT64 AddrRangeMin; + UINT64 AddrRangeMax; + UINT64 AddrTranslationOffset; + UINT64 AddrLen; +} EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR; + +typedef PACKED union { + UINT8 Byte; + PACKED struct { + UINT8 Length : 3; + UINT8 Name : 4; + UINT8 Type : 1; + } Bits; +} ACPI_SMALL_RESOURCE_HEADER; + +typedef PACKED struct { + PACKED union { + UINT8 Byte; + PACKED struct { + UINT8 Name : 7; + UINT8 Type : 1; + }Bits; + } Header; + UINT16 Length; +} ACPI_LARGE_RESOURCE_HEADER; + +/// +/// IRQ Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 Mask; +} EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR; + +/// +/// IRQ Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 Mask; + UINT8 Information; +} EFI_ACPI_IRQ_DESCRIPTOR; + +/// +/// DMA Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT8 ChannelMask; + UINT8 Information; +} EFI_ACPI_DMA_DESCRIPTOR; + +/// +/// I/O Port Descriptor +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT8 Information; + UINT16 BaseAddressMin; + UINT16 BaseAddressMax; + UINT8 Alignment; + UINT8 Length; +} EFI_ACPI_IO_PORT_DESCRIPTOR; + +/// +/// Fixed Location I/O Port Descriptor. +/// +typedef PACKED struct { + ACPI_SMALL_RESOURCE_HEADER Header; + UINT16 BaseAddress; + UINT8 Length; +} EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR; + +/// +/// 24-Bit Memory Range Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 Information; + UINT16 BaseAddressMin; + UINT16 BaseAddressMax; + UINT16 Alignment; + UINT16 Length; +} EFI_ACPI_24_BIT_MEMORY_RANGE_DESCRIPTOR; + +/// +/// 32-Bit Memory Range Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 Information; + UINT32 BaseAddressMin; + UINT32 BaseAddressMax; + UINT32 Alignment; + UINT32 Length; +} EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR; + +/// +/// Fixed 32-Bit Fixed Memory Range Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 Information; + UINT32 BaseAddress; + UINT32 Length; +} EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR; + +/// +/// QWORD Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT64 AddrSpaceGranularity; + UINT64 AddrRangeMin; + UINT64 AddrRangeMax; + UINT64 AddrTranslationOffset; + UINT64 AddrLen; +} EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR; + +/// +/// DWORD Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT32 AddrSpaceGranularity; + UINT32 AddrRangeMin; + UINT32 AddrRangeMax; + UINT32 AddrTranslationOffset; + UINT32 AddrLen; +} EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR; + +/// +/// WORD Address Space Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 ResType; + UINT8 GenFlag; + UINT8 SpecificFlag; + UINT16 AddrSpaceGranularity; + UINT16 AddrRangeMin; + UINT16 AddrRangeMax; + UINT16 AddrTranslationOffset; + UINT16 AddrLen; +} EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR; + +/// +/// Extended Interrupt Descriptor +/// +typedef PACKED struct { + ACPI_LARGE_RESOURCE_HEADER Header; + UINT8 InterruptVectorFlags; + UINT8 InterruptTableLength; + UINT32 InterruptNumber[1]; +} EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR; + +#pragma pack() + +/// +/// The End tag identifies an end of resource data. +/// +typedef struct { + UINT8 Desc; + UINT8 Checksum; +} EFI_ACPI_END_TAG_DESCRIPTOR; + +// +// General use definitions +// +#define EFI_ACPI_RESERVED_BYTE 0x00 +#define EFI_ACPI_RESERVED_WORD 0x0000 +#define EFI_ACPI_RESERVED_DWORD 0x00000000 +#define EFI_ACPI_RESERVED_QWORD 0x0000000000000000 + +// +// Resource Type Specific Flags +// Ref ACPI specification 6.4.3.5.5 +// +// Bit [0] : Write Status, _RW +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_READ_WRITE (1 << 0) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_READ_ONLY (0 << 0) +// +// Bit [2:1] : Memory Attributes, _MEM +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_NON_CACHEABLE (0 << 1) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE (1 << 1) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_WRITE_COMBINING (2 << 1) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE (3 << 1) +// +// Bit [4:3] : Memory Attributes, _MTP +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_MEMORY (0 << 3) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_RESERVED (1 << 3) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_ACPI (2 << 3) +#define EFI_APCI_MEMORY_RESOURCE_SPECIFIC_FLAG_ADDRESS_RANGE_NVS (3 << 3) +// +// Bit [5] : Memory to I/O Translation, _TTP +// +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_TYPE_TRANSLATION (1 << 5) +#define EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_TYPE_STATIC (0 << 5) + +// +// IRQ Information +// Ref ACPI specification 6.4.2.1 +// +#define EFI_ACPI_IRQ_SHARABLE_MASK 0x10 +#define EFI_ACPI_IRQ_SHARABLE 0x10 + +#define EFI_ACPI_IRQ_POLARITY_MASK 0x08 +#define EFI_ACPI_IRQ_HIGH_TRUE 0x00 +#define EFI_ACPI_IRQ_LOW_FALSE 0x08 + +#define EFI_ACPI_IRQ_MODE 0x01 +#define EFI_ACPI_IRQ_LEVEL_TRIGGERED 0x00 +#define EFI_ACPI_IRQ_EDGE_TRIGGERED 0x01 + +// +// DMA Information +// Ref ACPI specification 6.4.2.2 +// +#define EFI_ACPI_DMA_SPEED_TYPE_MASK 0x60 +#define EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY 0x00 +#define EFI_ACPI_DMA_SPEED_TYPE_A 0x20 +#define EFI_ACPI_DMA_SPEED_TYPE_B 0x40 +#define EFI_ACPI_DMA_SPEED_TYPE_F 0x60 + +#define EFI_ACPI_DMA_BUS_MASTER_MASK 0x04 +#define EFI_ACPI_DMA_BUS_MASTER 0x04 + +#define EFI_ACPI_DMA_TRANSFER_TYPE_MASK 0x03 +#define EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT 0x00 +#define EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT_AND_16_BIT 0x01 +#define EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT 0x10 + +// +// IO Information +// Ref ACPI specification 6.4.2.5 +// +#define EFI_ACPI_IO_DECODE_MASK 0x01 +#define EFI_ACPI_IO_DECODE_16_BIT 0x01 +#define EFI_ACPI_IO_DECODE_10_BIT 0x00 + +// +// Memory Information +// Ref ACPI specification 6.4.3.4 +// +#define EFI_ACPI_MEMORY_WRITE_STATUS_MASK 0x01 +#define EFI_ACPI_MEMORY_WRITABLE 0x01 +#define EFI_ACPI_MEMORY_NON_WRITABLE 0x00 + +// +// Ensure proper structure formats +// +#pragma pack(1) +// +// ACPI 1.0b table structures +// + +/// +/// Root System Description Pointer Structure. +/// +typedef struct { + UINT64 Signature; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 Reserved; + UINT32 RsdtAddress; +} EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER; + +// +// Root System Description Table +// No definition needed as it is a common description table header, the same with +// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT32 table pointers. +// + +/// +/// RSDT Revision (as defined in ACPI 1.0b specification). +/// +#define EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Fixed ACPI Description Table Structure (FADT). +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 FirmwareCtrl; + UINT32 Dsdt; + UINT8 IntModel; + UINT8 Reserved1; + UINT16 SciInt; + UINT32 SmiCmd; + UINT8 AcpiEnable; + UINT8 AcpiDisable; + UINT8 S4BiosReq; + UINT8 Reserved2; + UINT32 Pm1aEvtBlk; + UINT32 Pm1bEvtBlk; + UINT32 Pm1aCntBlk; + UINT32 Pm1bCntBlk; + UINT32 Pm2CntBlk; + UINT32 PmTmrBlk; + UINT32 Gpe0Blk; + UINT32 Gpe1Blk; + UINT8 Pm1EvtLen; + UINT8 Pm1CntLen; + UINT8 Pm2CntLen; + UINT8 PmTmLen; + UINT8 Gpe0BlkLen; + UINT8 Gpe1BlkLen; + UINT8 Gpe1Base; + UINT8 Reserved3; + UINT16 PLvl2Lat; + UINT16 PLvl3Lat; + UINT16 FlushSize; + UINT16 FlushStride; + UINT8 DutyOffset; + UINT8 DutyWidth; + UINT8 DayAlrm; + UINT8 MonAlrm; + UINT8 Century; + UINT8 Reserved4; + UINT8 Reserved5; + UINT8 Reserved6; + UINT32 Flags; +} EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE; + +/// +/// FADT Version (as defined in ACPI 1.0b specification). +/// +#define EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION 0x01 + +#define EFI_ACPI_1_0_INT_MODE_DUAL_PIC 0 +#define EFI_ACPI_1_0_INT_MODE_MULTIPLE_APIC 1 + +// +// Fixed ACPI Description Table Fixed Feature Flags +// All other bits are reserved and must be set to 0. +// +#define EFI_ACPI_1_0_WBINVD BIT0 +#define EFI_ACPI_1_0_WBINVD_FLUSH BIT1 +#define EFI_ACPI_1_0_PROC_C1 BIT2 +#define EFI_ACPI_1_0_P_LVL2_UP BIT3 +#define EFI_ACPI_1_0_PWR_BUTTON BIT4 +#define EFI_ACPI_1_0_SLP_BUTTON BIT5 +#define EFI_ACPI_1_0_FIX_RTC BIT6 +#define EFI_ACPI_1_0_RTC_S4 BIT7 +#define EFI_ACPI_1_0_TMR_VAL_EXT BIT8 +#define EFI_ACPI_1_0_DCK_CAP BIT9 + +/// +/// Firmware ACPI Control Structure. +/// +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT32 HardwareSignature; + UINT32 FirmwareWakingVector; + UINT32 GlobalLock; + UINT32 Flags; + UINT8 Reserved[40]; +} EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE; + +/// +/// Firmware Control Structure Feature Flags. +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_1_0_S4BIOS_F BIT0 + +/// +/// Multiple APIC Description Table header definition. The rest of the table +/// must be defined in a platform-specific manner. +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 LocalApicAddress; + UINT32 Flags; +} EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER; + +/// +/// MADT Revision (as defined in ACPI 1.0b specification). +/// +#define EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION 0x01 + +/// +/// Multiple APIC Flags +/// All other bits are reserved and must be set to 0. +/// +#define EFI_ACPI_1_0_PCAT_COMPAT BIT0 + +// +// Multiple APIC Description Table APIC structure types +// All other values between 0x05 an 0xFF are reserved and +// will be ignored by OSPM. +// +#define EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC 0x00 +#define EFI_ACPI_1_0_IO_APIC 0x01 +#define EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE 0x02 +#define EFI_ACPI_1_0_NON_MASKABLE_INTERRUPT_SOURCE 0x03 +#define EFI_ACPI_1_0_LOCAL_APIC_NMI 0x04 + +// +// APIC Structure Definitions +// + +/// +/// Processor Local APIC Structure Definition. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT32 Flags; +} EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE; + +/// +/// Local APIC Flags. All other bits are reserved and must be 0. +/// +#define EFI_ACPI_1_0_LOCAL_APIC_ENABLED BIT0 + +/// +/// IO APIC Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 IoApicId; + UINT8 Reserved; + UINT32 IoApicAddress; + UINT32 SystemVectorBase; +} EFI_ACPI_1_0_IO_APIC_STRUCTURE; + +/// +/// Interrupt Source Override Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 Bus; + UINT8 Source; + UINT32 GlobalSystemInterruptVector; + UINT16 Flags; +} EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE; + +/// +/// Non-Maskable Interrupt Source Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT16 Flags; + UINT32 GlobalSystemInterruptVector; +} EFI_ACPI_1_0_NON_MASKABLE_INTERRUPT_SOURCE_STRUCTURE; + +/// +/// Local APIC NMI Structure. +/// +typedef struct { + UINT8 Type; + UINT8 Length; + UINT8 AcpiProcessorId; + UINT16 Flags; + UINT8 LocalApicInti; +} EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE; + +/// +/// Smart Battery Description Table (SBST) +/// +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT32 WarningEnergyLevel; + UINT32 LowEnergyLevel; + UINT32 CriticalEnergyLevel; +} EFI_ACPI_1_0_SMART_BATTERY_DESCRIPTION_TABLE; + +// +// Known table signatures +// + +/// +/// "RSD PTR " Root System Description Pointer. +/// +#define EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') + +/// +/// "APIC" Multiple APIC Description Table. +/// +#define EFI_ACPI_1_0_APIC_SIGNATURE SIGNATURE_32('A', 'P', 'I', 'C') + +/// +/// "DSDT" Differentiated System Description Table. +/// +#define EFI_ACPI_1_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('D', 'S', 'D', 'T') + +/// +/// "FACS" Firmware ACPI Control Structure. +/// +#define EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'S') + +/// +/// "FACP" Fixed ACPI Description Table. +/// +#define EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('F', 'A', 'C', 'P') + +/// +/// "PSDT" Persistent System Description Table. +/// +#define EFI_ACPI_1_0_PERSISTENT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('P', 'S', 'D', 'T') + +/// +/// "RSDT" Root System Description Table. +/// +#define EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('R', 'S', 'D', 'T') + +/// +/// "SBST" Smart Battery Specification Table. +/// +#define EFI_ACPI_1_0_SMART_BATTERY_SPECIFICATION_TABLE_SIGNATURE SIGNATURE_32('S', 'B', 'S', 'T') + +/// +/// "SSDT" Secondary System Description Table. +/// +#define EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE SIGNATURE_32('S', 'S', 'D', 'T') + +#pragma pack() + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/AcpiAml.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/AcpiAml.h new file mode 100644 index 000000000..a9186b40f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/AcpiAml.h @@ -0,0 +1,177 @@ +/** @file + This file contains AML code definition in the latest ACPI spec. + + Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _ACPI_AML_H_ +#define _ACPI_AML_H_ + +FILE_LICENCE ( BSD3 ); + +// +// ACPI AML definition +// + +// +// Primary OpCode +// +#define AML_ZERO_OP 0x00 +#define AML_ONE_OP 0x01 +#define AML_ALIAS_OP 0x06 +#define AML_NAME_OP 0x08 +#define AML_BYTE_PREFIX 0x0a +#define AML_WORD_PREFIX 0x0b +#define AML_DWORD_PREFIX 0x0c +#define AML_STRING_PREFIX 0x0d +#define AML_QWORD_PREFIX 0x0e +#define AML_SCOPE_OP 0x10 +#define AML_BUFFER_OP 0x11 +#define AML_PACKAGE_OP 0x12 +#define AML_VAR_PACKAGE_OP 0x13 +#define AML_METHOD_OP 0x14 +#define AML_DUAL_NAME_PREFIX 0x2e +#define AML_MULTI_NAME_PREFIX 0x2f +#define AML_NAME_CHAR_A 0x41 +#define AML_NAME_CHAR_B 0x42 +#define AML_NAME_CHAR_C 0x43 +#define AML_NAME_CHAR_D 0x44 +#define AML_NAME_CHAR_E 0x45 +#define AML_NAME_CHAR_F 0x46 +#define AML_NAME_CHAR_G 0x47 +#define AML_NAME_CHAR_H 0x48 +#define AML_NAME_CHAR_I 0x49 +#define AML_NAME_CHAR_J 0x4a +#define AML_NAME_CHAR_K 0x4b +#define AML_NAME_CHAR_L 0x4c +#define AML_NAME_CHAR_M 0x4d +#define AML_NAME_CHAR_N 0x4e +#define AML_NAME_CHAR_O 0x4f +#define AML_NAME_CHAR_P 0x50 +#define AML_NAME_CHAR_Q 0x51 +#define AML_NAME_CHAR_R 0x52 +#define AML_NAME_CHAR_S 0x53 +#define AML_NAME_CHAR_T 0x54 +#define AML_NAME_CHAR_U 0x55 +#define AML_NAME_CHAR_V 0x56 +#define AML_NAME_CHAR_W 0x57 +#define AML_NAME_CHAR_X 0x58 +#define AML_NAME_CHAR_Y 0x59 +#define AML_NAME_CHAR_Z 0x5a +#define AML_ROOT_CHAR 0x5c +#define AML_PARENT_PREFIX_CHAR 0x5e +#define AML_NAME_CHAR__ 0x5f +#define AML_LOCAL0 0x60 +#define AML_LOCAL1 0x61 +#define AML_LOCAL2 0x62 +#define AML_LOCAL3 0x63 +#define AML_LOCAL4 0x64 +#define AML_LOCAL5 0x65 +#define AML_LOCAL6 0x66 +#define AML_LOCAL7 0x67 +#define AML_ARG0 0x68 +#define AML_ARG1 0x69 +#define AML_ARG2 0x6a +#define AML_ARG3 0x6b +#define AML_ARG4 0x6c +#define AML_ARG5 0x6d +#define AML_ARG6 0x6e +#define AML_STORE_OP 0x70 +#define AML_REF_OF_OP 0x71 +#define AML_ADD_OP 0x72 +#define AML_CONCAT_OP 0x73 +#define AML_SUBTRACT_OP 0x74 +#define AML_INCREMENT_OP 0x75 +#define AML_DECREMENT_OP 0x76 +#define AML_MULTIPLY_OP 0x77 +#define AML_DIVIDE_OP 0x78 +#define AML_SHIFT_LEFT_OP 0x79 +#define AML_SHIFT_RIGHT_OP 0x7a +#define AML_AND_OP 0x7b +#define AML_NAND_OP 0x7c +#define AML_OR_OP 0x7d +#define AML_NOR_OP 0x7e +#define AML_XOR_OP 0x7f +#define AML_NOT_OP 0x80 +#define AML_FIND_SET_LEFT_BIT_OP 0x81 +#define AML_FIND_SET_RIGHT_BIT_OP 0x82 +#define AML_DEREF_OF_OP 0x83 +#define AML_CONCAT_RES_OP 0x84 +#define AML_MOD_OP 0x85 +#define AML_NOTIFY_OP 0x86 +#define AML_SIZE_OF_OP 0x87 +#define AML_INDEX_OP 0x88 +#define AML_MATCH_OP 0x89 +#define AML_CREATE_DWORD_FIELD_OP 0x8a +#define AML_CREATE_WORD_FIELD_OP 0x8b +#define AML_CREATE_BYTE_FIELD_OP 0x8c +#define AML_CREATE_BIT_FIELD_OP 0x8d +#define AML_OBJECT_TYPE_OP 0x8e +#define AML_CREATE_QWORD_FIELD_OP 0x8f +#define AML_LAND_OP 0x90 +#define AML_LOR_OP 0x91 +#define AML_LNOT_OP 0x92 +#define AML_LEQUAL_OP 0x93 +#define AML_LGREATER_OP 0x94 +#define AML_LLESS_OP 0x95 +#define AML_TO_BUFFER_OP 0x96 +#define AML_TO_DEC_STRING_OP 0x97 +#define AML_TO_HEX_STRING_OP 0x98 +#define AML_TO_INTEGER_OP 0x99 +#define AML_TO_STRING_OP 0x9c +#define AML_COPY_OBJECT_OP 0x9d +#define AML_MID_OP 0x9e +#define AML_CONTINUE_OP 0x9f +#define AML_IF_OP 0xa0 +#define AML_ELSE_OP 0xa1 +#define AML_WHILE_OP 0xa2 +#define AML_NOOP_OP 0xa3 +#define AML_RETURN_OP 0xa4 +#define AML_BREAK_OP 0xa5 +#define AML_BREAK_POINT_OP 0xcc +#define AML_ONES_OP 0xff + +// +// Extended OpCode +// +#define AML_EXT_OP 0x5b + +#define AML_EXT_MUTEX_OP 0x01 +#define AML_EXT_EVENT_OP 0x02 +#define AML_EXT_COND_REF_OF_OP 0x12 +#define AML_EXT_CREATE_FIELD_OP 0x13 +#define AML_EXT_LOAD_TABLE_OP 0x1f +#define AML_EXT_LOAD_OP 0x20 +#define AML_EXT_STALL_OP 0x21 +#define AML_EXT_SLEEP_OP 0x22 +#define AML_EXT_ACQUIRE_OP 0x23 +#define AML_EXT_SIGNAL_OP 0x24 +#define AML_EXT_WAIT_OP 0x25 +#define AML_EXT_RESET_OP 0x26 +#define AML_EXT_RELEASE_OP 0x27 +#define AML_EXT_FROM_BCD_OP 0x28 +#define AML_EXT_TO_BCD_OP 0x29 +#define AML_EXT_UNLOAD_OP 0x2a +#define AML_EXT_REVISION_OP 0x30 +#define AML_EXT_DEBUG_OP 0x31 +#define AML_EXT_FATAL_OP 0x32 +#define AML_EXT_TIMER_OP 0x33 +#define AML_EXT_REGION_OP 0x80 +#define AML_EXT_FIELD_OP 0x81 +#define AML_EXT_DEVICE_OP 0x82 +#define AML_EXT_PROCESSOR_OP 0x83 +#define AML_EXT_POWER_RES_OP 0x84 +#define AML_EXT_THERMAL_ZONE_OP 0x85 +#define AML_EXT_INDEX_FIELD_OP 0x86 +#define AML_EXT_BANK_FIELD_OP 0x87 +#define AML_EXT_DATA_REGION_OP 0x88 + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h index 53654ee42..a73820f69 100644 --- a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h @@ -6,7 +6,10 @@ PCI-to-PCI Bridge Architecture Specification, Revision 1.2 PC Card Standard, 8.0 + + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -657,6 +660,42 @@ typedef struct { } EFI_PCI_CAPABILITY_PMI; /// +/// PMC - Power Management Capabilities +/// Section 3.2.3, PCI Power Management Interface Specifiction, Revision 1.2 +/// +typedef union { + struct { + UINT16 Version : 3; + UINT16 PmeClock : 1; + UINT16 : 1; + UINT16 DeviceSpecificInitialization : 1; + UINT16 AuxCurrent : 3; + UINT16 D1Support : 1; + UINT16 D2Support : 1; + UINT16 PmeSupport : 5; + } Bits; + UINT16 Data; +} EFI_PCI_PMC; + +#define EFI_PCI_PMC_D3_COLD_MASK (BIT15) + +/// +/// PMCSR - Power Management Control/Status +/// Section 3.2.4, PCI Power Management Interface Specifiction, Revision 1.2 +/// +typedef union { + struct { + UINT16 PowerState : 2; + UINT16 : 6; + UINT16 PmeEnable : 1; + UINT16 DataSelect : 4; + UINT16 DataScale : 2; + UINT16 PmeStatus : 1; + } Bits; + UINT16 Data; +} EFI_PCI_PMCSR; + +/// /// A.G.P Capability /// Section 6.1.4, Accelerated Graphics Port Interface Specification, Revision 1.0 /// diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h index fb4c2aaa2..9499bb7f5 100644 --- a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/PeImage.h @@ -4,7 +4,7 @@ EFI_IMAGE_NT_HEADERS64 is for PE32+. This file is coded to the Visual Studio, Microsoft Portable Executable and - Common Object File Format Specification, Revision 8.0 - May 16, 2006. + Common Object File Format Specification, Revision 8.3 - February 6, 2013. This file also includes some definitions in PI Specification, Revision 1.0. Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> @@ -41,6 +41,7 @@ FILE_LICENCE ( BSD3 ); #define IMAGE_FILE_MACHINE_EBC 0x0EBC #define IMAGE_FILE_MACHINE_X64 0x8664 #define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x01c2 +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // // EXE file formats diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Tpm12.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Tpm12.h new file mode 100644 index 000000000..509425cc2 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Tpm12.h @@ -0,0 +1,2175 @@ +/** @file + TPM Specification data structures (TCG TPM Specification Version 1.2 Revision 103) + See http://trustedcomputinggroup.org for latest specification updates + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + + +#ifndef _TPM12_H_ +#define _TPM12_H_ + +FILE_LICENCE ( BSD3 ); + +/// +/// The start of TPM return codes +/// +#define TPM_BASE 0 + +// +// All structures MUST be packed on a byte boundary. +// + +#pragma pack (1) + +// +// Part 2, section 2.2.3: Helper redefinitions +// +/// +/// Indicates the conditions where it is required that authorization be presented +/// +typedef UINT8 TPM_AUTH_DATA_USAGE; +/// +/// The information as to what the payload is in an encrypted structure +/// +typedef UINT8 TPM_PAYLOAD_TYPE; +/// +/// The version info breakdown +/// +typedef UINT8 TPM_VERSION_BYTE; +/// +/// The state of the dictionary attack mitigation logic +/// +typedef UINT8 TPM_DA_STATE; +/// +/// The request or response authorization type +/// +typedef UINT16 TPM_TAG; +/// +/// The protocol in use +/// +typedef UINT16 TPM_PROTOCOL_ID; +/// +/// Indicates the start state +/// +typedef UINT16 TPM_STARTUP_TYPE; +/// +/// The definition of the encryption scheme +/// +typedef UINT16 TPM_ENC_SCHEME; +/// +/// The definition of the signature scheme +/// +typedef UINT16 TPM_SIG_SCHEME; +/// +/// The definition of the migration scheme +/// +typedef UINT16 TPM_MIGRATE_SCHEME; +/// +/// Sets the state of the physical presence mechanism +/// +typedef UINT16 TPM_PHYSICAL_PRESENCE; +/// +/// Indicates the types of entity that are supported by the TPM +/// +typedef UINT16 TPM_ENTITY_TYPE; +/// +/// Indicates the permitted usage of the key +/// +typedef UINT16 TPM_KEY_USAGE; +/// +/// The type of asymmetric encrypted structure in use by the endorsement key +/// +typedef UINT16 TPM_EK_TYPE; +/// +/// The tag for the structure +/// +typedef UINT16 TPM_STRUCTURE_TAG; +/// +/// The platform specific spec to which the information relates to +/// +typedef UINT16 TPM_PLATFORM_SPECIFIC; +/// +/// The command ordinal +/// +typedef UINT32 TPM_COMMAND_CODE; +/// +/// Identifies a TPM capability area +/// +typedef UINT32 TPM_CAPABILITY_AREA; +/// +/// Indicates information regarding a key +/// +typedef UINT32 TPM_KEY_FLAGS; +/// +/// Indicates the type of algorithm +/// +typedef UINT32 TPM_ALGORITHM_ID; +/// +/// The locality modifier +/// +typedef UINT32 TPM_MODIFIER_INDICATOR; +/// +/// The actual number of a counter +/// +typedef UINT32 TPM_ACTUAL_COUNT; +/// +/// Attributes that define what options are in use for a transport session +/// +typedef UINT32 TPM_TRANSPORT_ATTRIBUTES; +/// +/// Handle to an authorization session +/// +typedef UINT32 TPM_AUTHHANDLE; +/// +/// Index to a DIR register +/// +typedef UINT32 TPM_DIRINDEX; +/// +/// The area where a key is held assigned by the TPM +/// +typedef UINT32 TPM_KEY_HANDLE; +/// +/// Index to a PCR register +/// +typedef UINT32 TPM_PCRINDEX; +/// +/// The return code from a function +/// +typedef UINT32 TPM_RESULT; +/// +/// The types of resources that a TPM may have using internal resources +/// +typedef UINT32 TPM_RESOURCE_TYPE; +/// +/// Allows for controlling of the key when loaded and how to handle TPM_Startup issues +/// +typedef UINT32 TPM_KEY_CONTROL; +/// +/// The index into the NV storage area +/// +typedef UINT32 TPM_NV_INDEX; +/// +/// The family ID. Family IDs are automatically assigned a sequence number by the TPM. +/// A trusted process can set the FamilyID value in an individual row to NULL, which +/// invalidates that row. The family ID resets to NULL on each change of TPM Owner. +/// +typedef UINT32 TPM_FAMILY_ID; +/// +/// IA value used as a label for the most recent verification of this family. Set to zero when not in use. +/// +typedef UINT32 TPM_FAMILY_VERIFICATION; +/// +/// How the TPM handles var +/// +typedef UINT32 TPM_STARTUP_EFFECTS; +/// +/// The mode of a symmetric encryption +/// +typedef UINT32 TPM_SYM_MODE; +/// +/// The family flags +/// +typedef UINT32 TPM_FAMILY_FLAGS; +/// +/// The index value for the delegate NV table +/// +typedef UINT32 TPM_DELEGATE_INDEX; +/// +/// The restrictions placed on delegation of CMK commands +/// +typedef UINT32 TPM_CMK_DELEGATE; +/// +/// The ID value of a monotonic counter +/// +typedef UINT32 TPM_COUNT_ID; +/// +/// A command to execute +/// +typedef UINT32 TPM_REDIT_COMMAND; +/// +/// A transport session handle +/// +typedef UINT32 TPM_TRANSHANDLE; +/// +/// A generic handle could be key, transport etc +/// +typedef UINT32 TPM_HANDLE; +/// +/// What operation is happening +/// +typedef UINT32 TPM_FAMILY_OPERATION; + +// +// Part 2, section 2.2.4: Vendor specific +// The following defines allow for the quick specification of a +// vendor specific item. +// +#define TPM_Vendor_Specific32 ((UINT32) 0x00000400) +#define TPM_Vendor_Specific8 ((UINT8) 0x80) + +// +// Part 2, section 3.1: TPM_STRUCTURE_TAG +// +#define TPM_TAG_CONTEXTBLOB ((TPM_STRUCTURE_TAG) 0x0001) +#define TPM_TAG_CONTEXT_SENSITIVE ((TPM_STRUCTURE_TAG) 0x0002) +#define TPM_TAG_CONTEXTPOINTER ((TPM_STRUCTURE_TAG) 0x0003) +#define TPM_TAG_CONTEXTLIST ((TPM_STRUCTURE_TAG) 0x0004) +#define TPM_TAG_SIGNINFO ((TPM_STRUCTURE_TAG) 0x0005) +#define TPM_TAG_PCR_INFO_LONG ((TPM_STRUCTURE_TAG) 0x0006) +#define TPM_TAG_PERSISTENT_FLAGS ((TPM_STRUCTURE_TAG) 0x0007) +#define TPM_TAG_VOLATILE_FLAGS ((TPM_STRUCTURE_TAG) 0x0008) +#define TPM_TAG_PERSISTENT_DATA ((TPM_STRUCTURE_TAG) 0x0009) +#define TPM_TAG_VOLATILE_DATA ((TPM_STRUCTURE_TAG) 0x000A) +#define TPM_TAG_SV_DATA ((TPM_STRUCTURE_TAG) 0x000B) +#define TPM_TAG_EK_BLOB ((TPM_STRUCTURE_TAG) 0x000C) +#define TPM_TAG_EK_BLOB_AUTH ((TPM_STRUCTURE_TAG) 0x000D) +#define TPM_TAG_COUNTER_VALUE ((TPM_STRUCTURE_TAG) 0x000E) +#define TPM_TAG_TRANSPORT_INTERNAL ((TPM_STRUCTURE_TAG) 0x000F) +#define TPM_TAG_TRANSPORT_LOG_IN ((TPM_STRUCTURE_TAG) 0x0010) +#define TPM_TAG_TRANSPORT_LOG_OUT ((TPM_STRUCTURE_TAG) 0x0011) +#define TPM_TAG_AUDIT_EVENT_IN ((TPM_STRUCTURE_TAG) 0x0012) +#define TPM_TAG_AUDIT_EVENT_OUT ((TPM_STRUCTURE_TAG) 0x0013) +#define TPM_TAG_CURRENT_TICKS ((TPM_STRUCTURE_TAG) 0x0014) +#define TPM_TAG_KEY ((TPM_STRUCTURE_TAG) 0x0015) +#define TPM_TAG_STORED_DATA12 ((TPM_STRUCTURE_TAG) 0x0016) +#define TPM_TAG_NV_ATTRIBUTES ((TPM_STRUCTURE_TAG) 0x0017) +#define TPM_TAG_NV_DATA_PUBLIC ((TPM_STRUCTURE_TAG) 0x0018) +#define TPM_TAG_NV_DATA_SENSITIVE ((TPM_STRUCTURE_TAG) 0x0019) +#define TPM_TAG_DELEGATIONS ((TPM_STRUCTURE_TAG) 0x001A) +#define TPM_TAG_DELEGATE_PUBLIC ((TPM_STRUCTURE_TAG) 0x001B) +#define TPM_TAG_DELEGATE_TABLE_ROW ((TPM_STRUCTURE_TAG) 0x001C) +#define TPM_TAG_TRANSPORT_AUTH ((TPM_STRUCTURE_TAG) 0x001D) +#define TPM_TAG_TRANSPORT_PUBLIC ((TPM_STRUCTURE_TAG) 0x001E) +#define TPM_TAG_PERMANENT_FLAGS ((TPM_STRUCTURE_TAG) 0x001F) +#define TPM_TAG_STCLEAR_FLAGS ((TPM_STRUCTURE_TAG) 0x0020) +#define TPM_TAG_STANY_FLAGS ((TPM_STRUCTURE_TAG) 0x0021) +#define TPM_TAG_PERMANENT_DATA ((TPM_STRUCTURE_TAG) 0x0022) +#define TPM_TAG_STCLEAR_DATA ((TPM_STRUCTURE_TAG) 0x0023) +#define TPM_TAG_STANY_DATA ((TPM_STRUCTURE_TAG) 0x0024) +#define TPM_TAG_FAMILY_TABLE_ENTRY ((TPM_STRUCTURE_TAG) 0x0025) +#define TPM_TAG_DELEGATE_SENSITIVE ((TPM_STRUCTURE_TAG) 0x0026) +#define TPM_TAG_DELG_KEY_BLOB ((TPM_STRUCTURE_TAG) 0x0027) +#define TPM_TAG_KEY12 ((TPM_STRUCTURE_TAG) 0x0028) +#define TPM_TAG_CERTIFY_INFO2 ((TPM_STRUCTURE_TAG) 0x0029) +#define TPM_TAG_DELEGATE_OWNER_BLOB ((TPM_STRUCTURE_TAG) 0x002A) +#define TPM_TAG_EK_BLOB_ACTIVATE ((TPM_STRUCTURE_TAG) 0x002B) +#define TPM_TAG_DAA_BLOB ((TPM_STRUCTURE_TAG) 0x002C) +#define TPM_TAG_DAA_CONTEXT ((TPM_STRUCTURE_TAG) 0x002D) +#define TPM_TAG_DAA_ENFORCE ((TPM_STRUCTURE_TAG) 0x002E) +#define TPM_TAG_DAA_ISSUER ((TPM_STRUCTURE_TAG) 0x002F) +#define TPM_TAG_CAP_VERSION_INFO ((TPM_STRUCTURE_TAG) 0x0030) +#define TPM_TAG_DAA_SENSITIVE ((TPM_STRUCTURE_TAG) 0x0031) +#define TPM_TAG_DAA_TPM ((TPM_STRUCTURE_TAG) 0x0032) +#define TPM_TAG_CMK_MIGAUTH ((TPM_STRUCTURE_TAG) 0x0033) +#define TPM_TAG_CMK_SIGTICKET ((TPM_STRUCTURE_TAG) 0x0034) +#define TPM_TAG_CMK_MA_APPROVAL ((TPM_STRUCTURE_TAG) 0x0035) +#define TPM_TAG_QUOTE_INFO2 ((TPM_STRUCTURE_TAG) 0x0036) +#define TPM_TAG_DA_INFO ((TPM_STRUCTURE_TAG) 0x0037) +#define TPM_TAG_DA_LIMITED ((TPM_STRUCTURE_TAG) 0x0038) +#define TPM_TAG_DA_ACTION_TYPE ((TPM_STRUCTURE_TAG) 0x0039) + +// +// Part 2, section 4: TPM Types +// + +// +// Part 2, section 4.1: TPM_RESOURCE_TYPE +// +#define TPM_RT_KEY ((TPM_RESOURCE_TYPE) 0x00000001) ///< The handle is a key handle and is the result of a LoadKey type operation +#define TPM_RT_AUTH ((TPM_RESOURCE_TYPE) 0x00000002) ///< The handle is an authorization handle. Auth handles come from TPM_OIAP, TPM_OSAP and TPM_DSAP +#define TPM_RT_HASH ((TPM_RESOURCE_TYPE) 0x00000003) ///< Reserved for hashes +#define TPM_RT_TRANS ((TPM_RESOURCE_TYPE) 0x00000004) ///< The handle is for a transport session. Transport handles come from TPM_EstablishTransport +#define TPM_RT_CONTEXT ((TPM_RESOURCE_TYPE) 0x00000005) ///< Resource wrapped and held outside the TPM using the context save/restore commands +#define TPM_RT_COUNTER ((TPM_RESOURCE_TYPE) 0x00000006) ///< Reserved for counters +#define TPM_RT_DELEGATE ((TPM_RESOURCE_TYPE) 0x00000007) ///< The handle is for a delegate row. These are the internal rows held in NV storage by the TPM +#define TPM_RT_DAA_TPM ((TPM_RESOURCE_TYPE) 0x00000008) ///< The value is a DAA TPM specific blob +#define TPM_RT_DAA_V0 ((TPM_RESOURCE_TYPE) 0x00000009) ///< The value is a DAA V0 parameter +#define TPM_RT_DAA_V1 ((TPM_RESOURCE_TYPE) 0x0000000A) ///< The value is a DAA V1 parameter + +// +// Part 2, section 4.2: TPM_PAYLOAD_TYPE +// +#define TPM_PT_ASYM ((TPM_PAYLOAD_TYPE) 0x01) ///< The entity is an asymmetric key +#define TPM_PT_BIND ((TPM_PAYLOAD_TYPE) 0x02) ///< The entity is bound data +#define TPM_PT_MIGRATE ((TPM_PAYLOAD_TYPE) 0x03) ///< The entity is a migration blob +#define TPM_PT_MAINT ((TPM_PAYLOAD_TYPE) 0x04) ///< The entity is a maintenance blob +#define TPM_PT_SEAL ((TPM_PAYLOAD_TYPE) 0x05) ///< The entity is sealed data +#define TPM_PT_MIGRATE_RESTRICTED ((TPM_PAYLOAD_TYPE) 0x06) ///< The entity is a restricted-migration asymmetric key +#define TPM_PT_MIGRATE_EXTERNAL ((TPM_PAYLOAD_TYPE) 0x07) ///< The entity is a external migratable key +#define TPM_PT_CMK_MIGRATE ((TPM_PAYLOAD_TYPE) 0x08) ///< The entity is a CMK migratable blob +#define TPM_PT_VENDOR_SPECIFIC ((TPM_PAYLOAD_TYPE) 0x80) ///< 0x80 - 0xFF Vendor specific payloads + +// +// Part 2, section 4.3: TPM_ENTITY_TYPE +// +#define TPM_ET_KEYHANDLE ((UINT16) 0x0001) ///< The entity is a keyHandle or key +#define TPM_ET_OWNER ((UINT16) 0x0002) ///< The entity is the TPM Owner +#define TPM_ET_DATA ((UINT16) 0x0003) ///< The entity is some data +#define TPM_ET_SRK ((UINT16) 0x0004) ///< The entity is the SRK +#define TPM_ET_KEY ((UINT16) 0x0005) ///< The entity is a key or keyHandle +#define TPM_ET_REVOKE ((UINT16) 0x0006) ///< The entity is the RevokeTrust value +#define TPM_ET_DEL_OWNER_BLOB ((UINT16) 0x0007) ///< The entity is a delegate owner blob +#define TPM_ET_DEL_ROW ((UINT16) 0x0008) ///< The entity is a delegate row +#define TPM_ET_DEL_KEY_BLOB ((UINT16) 0x0009) ///< The entity is a delegate key blob +#define TPM_ET_COUNTER ((UINT16) 0x000A) ///< The entity is a counter +#define TPM_ET_NV ((UINT16) 0x000B) ///< The entity is a NV index +#define TPM_ET_OPERATOR ((UINT16) 0x000C) ///< The entity is the operator +#define TPM_ET_RESERVED_HANDLE ((UINT16) 0x0040) ///< Reserved. This value avoids collisions with the handle MSB setting. +// +// TPM_ENTITY_TYPE MSB Values: The MSB is used to indicate the ADIP encryption sheme when applicable +// +#define TPM_ET_XOR ((UINT16) 0x0000) ///< ADIP encryption scheme: XOR +#define TPM_ET_AES128 ((UINT16) 0x0006) ///< ADIP encryption scheme: AES 128 bits + +// +// Part 2, section 4.4.1: Reserved Key Handles +// +#define TPM_KH_SRK ((TPM_KEY_HANDLE) 0x40000000) ///< The handle points to the SRK +#define TPM_KH_OWNER ((TPM_KEY_HANDLE) 0x40000001) ///< The handle points to the TPM Owner +#define TPM_KH_REVOKE ((TPM_KEY_HANDLE) 0x40000002) ///< The handle points to the RevokeTrust value +#define TPM_KH_TRANSPORT ((TPM_KEY_HANDLE) 0x40000003) ///< The handle points to the EstablishTransport static authorization +#define TPM_KH_OPERATOR ((TPM_KEY_HANDLE) 0x40000004) ///< The handle points to the Operator auth +#define TPM_KH_ADMIN ((TPM_KEY_HANDLE) 0x40000005) ///< The handle points to the delegation administration auth +#define TPM_KH_EK ((TPM_KEY_HANDLE) 0x40000006) ///< The handle points to the PUBEK, only usable with TPM_OwnerReadInternalPub + +// +// Part 2, section 4.5: TPM_STARTUP_TYPE +// +#define TPM_ST_CLEAR ((TPM_STARTUP_TYPE) 0x0001) ///< The TPM is starting up from a clean state +#define TPM_ST_STATE ((TPM_STARTUP_TYPE) 0x0002) ///< The TPM is starting up from a saved state +#define TPM_ST_DEACTIVATED ((TPM_STARTUP_TYPE) 0x0003) ///< The TPM is to startup and set the deactivated flag to TRUE + +// +// Part 2, section 4.6: TPM_STATUP_EFFECTS +// The table makeup is still an open issue. +// + +// +// Part 2, section 4.7: TPM_PROTOCOL_ID +// +#define TPM_PID_OIAP ((TPM_PROTOCOL_ID) 0x0001) ///< The OIAP protocol. +#define TPM_PID_OSAP ((TPM_PROTOCOL_ID) 0x0002) ///< The OSAP protocol. +#define TPM_PID_ADIP ((TPM_PROTOCOL_ID) 0x0003) ///< The ADIP protocol. +#define TPM_PID_ADCP ((TPM_PROTOCOL_ID) 0x0004) ///< The ADCP protocol. +#define TPM_PID_OWNER ((TPM_PROTOCOL_ID) 0x0005) ///< The protocol for taking ownership of a TPM. +#define TPM_PID_DSAP ((TPM_PROTOCOL_ID) 0x0006) ///< The DSAP protocol +#define TPM_PID_TRANSPORT ((TPM_PROTOCOL_ID) 0x0007) ///< The transport protocol + +// +// Part 2, section 4.8: TPM_ALGORITHM_ID +// The TPM MUST support the algorithms TPM_ALG_RSA, TPM_ALG_SHA, TPM_ALG_HMAC, +// TPM_ALG_MGF1 +// +#define TPM_ALG_RSA ((TPM_ALGORITHM_ID) 0x00000001) ///< The RSA algorithm. +#define TPM_ALG_DES ((TPM_ALGORITHM_ID) 0x00000002) ///< The DES algorithm +#define TPM_ALG_3DES ((TPM_ALGORITHM_ID) 0x00000003) ///< The 3DES algorithm in EDE mode +#define TPM_ALG_SHA ((TPM_ALGORITHM_ID) 0x00000004) ///< The SHA1 algorithm +#define TPM_ALG_HMAC ((TPM_ALGORITHM_ID) 0x00000005) ///< The RFC 2104 HMAC algorithm +#define TPM_ALG_AES128 ((TPM_ALGORITHM_ID) 0x00000006) ///< The AES algorithm, key size 128 +#define TPM_ALG_MGF1 ((TPM_ALGORITHM_ID) 0x00000007) ///< The XOR algorithm using MGF1 to create a string the size of the encrypted block +#define TPM_ALG_AES192 ((TPM_ALGORITHM_ID) 0x00000008) ///< AES, key size 192 +#define TPM_ALG_AES256 ((TPM_ALGORITHM_ID) 0x00000009) ///< AES, key size 256 +#define TPM_ALG_XOR ((TPM_ALGORITHM_ID) 0x0000000A) ///< XOR using the rolling nonces + +// +// Part 2, section 4.9: TPM_PHYSICAL_PRESENCE +// +#define TPM_PHYSICAL_PRESENCE_HW_DISABLE ((TPM_PHYSICAL_PRESENCE) 0x0200) ///< Sets the physicalPresenceHWEnable to FALSE +#define TPM_PHYSICAL_PRESENCE_CMD_DISABLE ((TPM_PHYSICAL_PRESENCE) 0x0100) ///< Sets the physicalPresenceCMDEnable to FALSE +#define TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK ((TPM_PHYSICAL_PRESENCE) 0x0080) ///< Sets the physicalPresenceLifetimeLock to TRUE +#define TPM_PHYSICAL_PRESENCE_HW_ENABLE ((TPM_PHYSICAL_PRESENCE) 0x0040) ///< Sets the physicalPresenceHWEnable to TRUE +#define TPM_PHYSICAL_PRESENCE_CMD_ENABLE ((TPM_PHYSICAL_PRESENCE) 0x0020) ///< Sets the physicalPresenceCMDEnable to TRUE +#define TPM_PHYSICAL_PRESENCE_NOTPRESENT ((TPM_PHYSICAL_PRESENCE) 0x0010) ///< Sets PhysicalPresence = FALSE +#define TPM_PHYSICAL_PRESENCE_PRESENT ((TPM_PHYSICAL_PRESENCE) 0x0008) ///< Sets PhysicalPresence = TRUE +#define TPM_PHYSICAL_PRESENCE_LOCK ((TPM_PHYSICAL_PRESENCE) 0x0004) ///< Sets PhysicalPresenceLock = TRUE + +// +// Part 2, section 4.10: TPM_MIGRATE_SCHEME +// +#define TPM_MS_MIGRATE ((TPM_MIGRATE_SCHEME) 0x0001) ///< A public key that can be used with all TPM migration commands other than 'ReWrap' mode. +#define TPM_MS_REWRAP ((TPM_MIGRATE_SCHEME) 0x0002) ///< A public key that can be used for the ReWrap mode of TPM_CreateMigrationBlob. +#define TPM_MS_MAINT ((TPM_MIGRATE_SCHEME) 0x0003) ///< A public key that can be used for the Maintenance commands +#define TPM_MS_RESTRICT_MIGRATE ((TPM_MIGRATE_SCHEME) 0x0004) ///< The key is to be migrated to a Migration Authority. +#define TPM_MS_RESTRICT_APPROVE_DOUBLE ((TPM_MIGRATE_SCHEME) 0x0005) ///< The key is to be migrated to an entity approved by a Migration Authority using double wrapping + +// +// Part 2, section 4.11: TPM_EK_TYPE +// +#define TPM_EK_TYPE_ACTIVATE ((TPM_EK_TYPE) 0x0001) ///< The blob MUST be TPM_EK_BLOB_ACTIVATE +#define TPM_EK_TYPE_AUTH ((TPM_EK_TYPE) 0x0002) ///< The blob MUST be TPM_EK_BLOB_AUTH + +// +// Part 2, section 4.12: TPM_PLATFORM_SPECIFIC +// +#define TPM_PS_PC_11 ((TPM_PLATFORM_SPECIFIC) 0x0001) ///< PC Specific version 1.1 +#define TPM_PS_PC_12 ((TPM_PLATFORM_SPECIFIC) 0x0002) ///< PC Specific version 1.2 +#define TPM_PS_PDA_12 ((TPM_PLATFORM_SPECIFIC) 0x0003) ///< PDA Specific version 1.2 +#define TPM_PS_Server_12 ((TPM_PLATFORM_SPECIFIC) 0x0004) ///< Server Specific version 1.2 +#define TPM_PS_Mobile_12 ((TPM_PLATFORM_SPECIFIC) 0x0005) ///< Mobil Specific version 1.2 + +// +// Part 2, section 5: Basic Structures +// + +/// +/// Part 2, section 5.1: TPM_STRUCT_VER +/// +typedef struct tdTPM_STRUCT_VER { + UINT8 major; + UINT8 minor; + UINT8 revMajor; + UINT8 revMinor; +} TPM_STRUCT_VER; + +/// +/// Part 2, section 5.3: TPM_VERSION +/// +typedef struct tdTPM_VERSION { + TPM_VERSION_BYTE major; + TPM_VERSION_BYTE minor; + UINT8 revMajor; + UINT8 revMinor; +} TPM_VERSION; + + +#define TPM_SHA1_160_HASH_LEN 0x14 +#define TPM_SHA1BASED_NONCE_LEN TPM_SHA1_160_HASH_LEN + +/// +/// Part 2, section 5.4: TPM_DIGEST +/// +typedef struct tdTPM_DIGEST{ + UINT8 digest[TPM_SHA1_160_HASH_LEN]; +} TPM_DIGEST; + +/// +/// This SHALL be the digest of the chosen identityLabel and privacyCA for a new TPM identity +/// +typedef TPM_DIGEST TPM_CHOSENID_HASH; +/// +/// This SHALL be the hash of a list of PCR indexes and PCR values that a key or data is bound to +/// +typedef TPM_DIGEST TPM_COMPOSITE_HASH; +/// +/// This SHALL be the value of a DIR register +/// +typedef TPM_DIGEST TPM_DIRVALUE; + +typedef TPM_DIGEST TPM_HMAC; +/// +/// The value inside of the PCR +/// +typedef TPM_DIGEST TPM_PCRVALUE; +/// +/// This SHALL be the value of the current internal audit state +/// +typedef TPM_DIGEST TPM_AUDITDIGEST; + +/// +/// Part 2, section 5.5: TPM_NONCE +/// +typedef struct tdTPM_NONCE{ + UINT8 nonce[20]; +} TPM_NONCE; + +/// +/// This SHALL be a random value generated by a TPM immediately after the EK is installed +/// in that TPM, whenever an EK is installed in that TPM +/// +typedef TPM_NONCE TPM_DAA_TPM_SEED; +/// +/// This SHALL be a random value +/// +typedef TPM_NONCE TPM_DAA_CONTEXT_SEED; + +// +// Part 2, section 5.6: TPM_AUTHDATA +// +/// +/// The AuthData data is the information that is saved or passed to provide proof of ownership +/// 296 of an entity +/// +typedef UINT8 tdTPM_AUTHDATA[20]; + +typedef tdTPM_AUTHDATA TPM_AUTHDATA; +/// +/// A secret plaintext value used in the authorization process +/// +typedef TPM_AUTHDATA TPM_SECRET; +/// +/// A ciphertext (encrypted) version of AuthData data. The encryption mechanism depends on the context +/// +typedef TPM_AUTHDATA TPM_ENCAUTH; + +/// +/// Part 2, section 5.7: TPM_KEY_HANDLE_LIST +/// Size of handle is loaded * sizeof(TPM_KEY_HANDLE) +/// +typedef struct tdTPM_KEY_HANDLE_LIST { + UINT16 loaded; + TPM_KEY_HANDLE handle[1]; +} TPM_KEY_HANDLE_LIST; + +// +// Part 2, section 5.8: TPM_KEY_USAGE values +// +/// +/// TPM_KEY_SIGNING SHALL indicate a signing key. The [private] key SHALL be +/// used for signing operations, only. This means that it MUST be a leaf of the +/// Protected Storage key hierarchy. +/// +#define TPM_KEY_SIGNING ((UINT16) 0x0010) +/// +/// TPM_KEY_STORAGE SHALL indicate a storage key. The key SHALL be used to wrap +/// and unwrap other keys in the Protected Storage hierarchy +/// +#define TPM_KEY_STORAGE ((UINT16) 0x0011) +/// +/// TPM_KEY_IDENTITY SHALL indicate an identity key. The key SHALL be used for +/// operations that require a TPM identity, only. +/// +#define TPM_KEY_IDENTITY ((UINT16) 0x0012) +/// +/// TPM_KEY_AUTHCHANGE SHALL indicate an ephemeral key that is in use during +/// the ChangeAuthAsym process, only. +/// +#define TPM_KEY_AUTHCHANGE ((UINT16) 0x0013) +/// +/// TPM_KEY_BIND SHALL indicate a key that can be used for TPM_Bind and +/// TPM_Unbind operations only. +/// +#define TPM_KEY_BIND ((UINT16) 0x0014) +/// +/// TPM_KEY_LEGACY SHALL indicate a key that can perform signing and binding +/// operations. The key MAY be used for both signing and binding operations. +/// The TPM_KEY_LEGACY key type is to allow for use by applications where both +/// signing and encryption operations occur with the same key. The use of this +/// key type is not recommended TPM_KEY_MIGRATE 0x0016 This SHALL indicate a +/// key in use for TPM_MigrateKey +/// +#define TPM_KEY_LEGACY ((UINT16) 0x0015) +/// +/// TPM_KEY_MIGRAGE SHALL indicate a key in use for TPM_MigrateKey +/// +#define TPM_KEY_MIGRATE ((UINT16) 0x0016) + +// +// Part 2, section 5.8.1: Mandatory Key Usage Schemes +// + +#define TPM_ES_NONE ((TPM_ENC_SCHEME) 0x0001) +#define TPM_ES_RSAESPKCSv15 ((TPM_ENC_SCHEME) 0x0002) +#define TPM_ES_RSAESOAEP_SHA1_MGF1 ((TPM_ENC_SCHEME) 0x0003) +#define TPM_ES_SYM_CNT ((TPM_ENC_SCHEME) 0x0004) ///< rev94 defined +#define TPM_ES_SYM_CTR ((TPM_ENC_SCHEME) 0x0004) +#define TPM_ES_SYM_OFB ((TPM_ENC_SCHEME) 0x0005) + +#define TPM_SS_NONE ((TPM_SIG_SCHEME) 0x0001) +#define TPM_SS_RSASSAPKCS1v15_SHA1 ((TPM_SIG_SCHEME) 0x0002) +#define TPM_SS_RSASSAPKCS1v15_DER ((TPM_SIG_SCHEME) 0x0003) +#define TPM_SS_RSASSAPKCS1v15_INFO ((TPM_SIG_SCHEME) 0x0004) + +// +// Part 2, section 5.9: TPM_AUTH_DATA_USAGE values +// +#define TPM_AUTH_NEVER ((TPM_AUTH_DATA_USAGE) 0x00) +#define TPM_AUTH_ALWAYS ((TPM_AUTH_DATA_USAGE) 0x01) +#define TPM_AUTH_PRIV_USE_ONLY ((TPM_AUTH_DATA_USAGE) 0x03) + +/// +/// Part 2, section 5.10: TPM_KEY_FLAGS +/// +typedef enum tdTPM_KEY_FLAGS { + redirection = 0x00000001, + migratable = 0x00000002, + isVolatile = 0x00000004, + pcrIgnoredOnRead = 0x00000008, + migrateAuthority = 0x00000010 +} TPM_KEY_FLAGS_BITS; + +/// +/// Part 2, section 5.11: TPM_CHANGEAUTH_VALIDATE +/// +typedef struct tdTPM_CHANGEAUTH_VALIDATE { + TPM_SECRET newAuthSecret; + TPM_NONCE n1; +} TPM_CHANGEAUTH_VALIDATE; + +/// +/// Part 2, section 5.12: TPM_MIGRATIONKEYAUTH +/// decalared after section 10 to catch declaration of TPM_PUBKEY +/// +/// Part 2 section 10.1: TPM_KEY_PARMS +/// [size_is(parmSize)] BYTE* parms; +/// +typedef struct tdTPM_KEY_PARMS { + TPM_ALGORITHM_ID algorithmID; + TPM_ENC_SCHEME encScheme; + TPM_SIG_SCHEME sigScheme; + UINT32 parmSize; + UINT8 *parms; +} TPM_KEY_PARMS; + +/// +/// Part 2, section 10.4: TPM_STORE_PUBKEY +/// +typedef struct tdTPM_STORE_PUBKEY { + UINT32 keyLength; + UINT8 key[1]; +} TPM_STORE_PUBKEY; + +/// +/// Part 2, section 10.5: TPM_PUBKEY +/// +typedef struct tdTPM_PUBKEY{ + TPM_KEY_PARMS algorithmParms; + TPM_STORE_PUBKEY pubKey; +} TPM_PUBKEY; + +/// +/// Part 2, section 5.12: TPM_MIGRATIONKEYAUTH +/// +typedef struct tdTPM_MIGRATIONKEYAUTH{ + TPM_PUBKEY migrationKey; + TPM_MIGRATE_SCHEME migrationScheme; + TPM_DIGEST digest; +} TPM_MIGRATIONKEYAUTH; + +/// +/// Part 2, section 5.13: TPM_COUNTER_VALUE +/// +typedef struct tdTPM_COUNTER_VALUE{ + TPM_STRUCTURE_TAG tag; + UINT8 label[4]; + TPM_ACTUAL_COUNT counter; +} TPM_COUNTER_VALUE; + +/// +/// Part 2, section 5.14: TPM_SIGN_INFO +/// Size of data indicated by dataLen +/// +typedef struct tdTPM_SIGN_INFO { + TPM_STRUCTURE_TAG tag; + UINT8 fixed[4]; + TPM_NONCE replay; + UINT32 dataLen; + UINT8 *data; +} TPM_SIGN_INFO; + +/// +/// Part 2, section 5.15: TPM_MSA_COMPOSITE +/// Number of migAuthDigest indicated by MSAlist +/// +typedef struct tdTPM_MSA_COMPOSITE { + UINT32 MSAlist; + TPM_DIGEST migAuthDigest[1]; +} TPM_MSA_COMPOSITE; + +/// +/// Part 2, section 5.16: TPM_CMK_AUTH +/// +typedef struct tdTPM_CMK_AUTH{ + TPM_DIGEST migrationAuthorityDigest; + TPM_DIGEST destinationKeyDigest; + TPM_DIGEST sourceKeyDigest; +} TPM_CMK_AUTH; + +// +// Part 2, section 5.17: TPM_CMK_DELEGATE +// +#define TPM_CMK_DELEGATE_SIGNING ((TPM_CMK_DELEGATE) BIT31) +#define TPM_CMK_DELEGATE_STORAGE ((TPM_CMK_DELEGATE) BIT30) +#define TPM_CMK_DELEGATE_BIND ((TPM_CMK_DELEGATE) BIT29) +#define TPM_CMK_DELEGATE_LEGACY ((TPM_CMK_DELEGATE) BIT28) +#define TPM_CMK_DELEGATE_MIGRATE ((TPM_CMK_DELEGATE) BIT27) + +/// +/// Part 2, section 5.18: TPM_SELECT_SIZE +/// +typedef struct tdTPM_SELECT_SIZE { + UINT8 major; + UINT8 minor; + UINT16 reqSize; +} TPM_SELECT_SIZE; + +/// +/// Part 2, section 5,19: TPM_CMK_MIGAUTH +/// +typedef struct tdTPM_CMK_MIGAUTH{ + TPM_STRUCTURE_TAG tag; + TPM_DIGEST msaDigest; + TPM_DIGEST pubKeyDigest; +} TPM_CMK_MIGAUTH; + +/// +/// Part 2, section 5.20: TPM_CMK_SIGTICKET +/// +typedef struct tdTPM_CMK_SIGTICKET{ + TPM_STRUCTURE_TAG tag; + TPM_DIGEST verKeyDigest; + TPM_DIGEST signedData; +} TPM_CMK_SIGTICKET; + +/// +/// Part 2, section 5.21: TPM_CMK_MA_APPROVAL +/// +typedef struct tdTPM_CMK_MA_APPROVAL{ + TPM_STRUCTURE_TAG tag; + TPM_DIGEST migrationAuthorityDigest; +} TPM_CMK_MA_APPROVAL; + +// +// Part 2, section 6: Command Tags +// +#define TPM_TAG_RQU_COMMAND ((TPM_STRUCTURE_TAG) 0x00C1) +#define TPM_TAG_RQU_AUTH1_COMMAND ((TPM_STRUCTURE_TAG) 0x00C2) +#define TPM_TAG_RQU_AUTH2_COMMAND ((TPM_STRUCTURE_TAG) 0x00C3) +#define TPM_TAG_RSP_COMMAND ((TPM_STRUCTURE_TAG) 0x00C4) +#define TPM_TAG_RSP_AUTH1_COMMAND ((TPM_STRUCTURE_TAG) 0x00C5) +#define TPM_TAG_RSP_AUTH2_COMMAND ((TPM_STRUCTURE_TAG) 0x00C6) + +/// +/// Part 2, section 7.1: TPM_PERMANENT_FLAGS +/// +typedef struct tdTPM_PERMANENT_FLAGS{ + TPM_STRUCTURE_TAG tag; + BOOLEAN disable; + BOOLEAN ownership; + BOOLEAN deactivated; + BOOLEAN readPubek; + BOOLEAN disableOwnerClear; + BOOLEAN allowMaintenance; + BOOLEAN physicalPresenceLifetimeLock; + BOOLEAN physicalPresenceHWEnable; + BOOLEAN physicalPresenceCMDEnable; + BOOLEAN CEKPUsed; + BOOLEAN TPMpost; + BOOLEAN TPMpostLock; + BOOLEAN FIPS; + BOOLEAN operator; + BOOLEAN enableRevokeEK; + BOOLEAN nvLocked; + BOOLEAN readSRKPub; + BOOLEAN tpmEstablished; + BOOLEAN maintenanceDone; + BOOLEAN disableFullDALogicInfo; +} TPM_PERMANENT_FLAGS; + +// +// Part 2, section 7.1.1: Flag Restrictions (of TPM_PERMANENT_FLAGS) +// +#define TPM_PF_DISABLE ((TPM_CAPABILITY_AREA) 1) +#define TPM_PF_OWNERSHIP ((TPM_CAPABILITY_AREA) 2) +#define TPM_PF_DEACTIVATED ((TPM_CAPABILITY_AREA) 3) +#define TPM_PF_READPUBEK ((TPM_CAPABILITY_AREA) 4) +#define TPM_PF_DISABLEOWNERCLEAR ((TPM_CAPABILITY_AREA) 5) +#define TPM_PF_ALLOWMAINTENANCE ((TPM_CAPABILITY_AREA) 6) +#define TPM_PF_PHYSICALPRESENCELIFETIMELOCK ((TPM_CAPABILITY_AREA) 7) +#define TPM_PF_PHYSICALPRESENCEHWENABLE ((TPM_CAPABILITY_AREA) 8) +#define TPM_PF_PHYSICALPRESENCECMDENABLE ((TPM_CAPABILITY_AREA) 9) +#define TPM_PF_CEKPUSED ((TPM_CAPABILITY_AREA) 10) +#define TPM_PF_TPMPOST ((TPM_CAPABILITY_AREA) 11) +#define TPM_PF_TPMPOSTLOCK ((TPM_CAPABILITY_AREA) 12) +#define TPM_PF_FIPS ((TPM_CAPABILITY_AREA) 13) +#define TPM_PF_OPERATOR ((TPM_CAPABILITY_AREA) 14) +#define TPM_PF_ENABLEREVOKEEK ((TPM_CAPABILITY_AREA) 15) +#define TPM_PF_NV_LOCKED ((TPM_CAPABILITY_AREA) 16) +#define TPM_PF_READSRKPUB ((TPM_CAPABILITY_AREA) 17) +#define TPM_PF_TPMESTABLISHED ((TPM_CAPABILITY_AREA) 18) +#define TPM_PF_MAINTENANCEDONE ((TPM_CAPABILITY_AREA) 19) +#define TPM_PF_DISABLEFULLDALOGICINFO ((TPM_CAPABILITY_AREA) 20) + +/// +/// Part 2, section 7.2: TPM_STCLEAR_FLAGS +/// +typedef struct tdTPM_STCLEAR_FLAGS{ + TPM_STRUCTURE_TAG tag; + BOOLEAN deactivated; + BOOLEAN disableForceClear; + BOOLEAN physicalPresence; + BOOLEAN physicalPresenceLock; + BOOLEAN bGlobalLock; +} TPM_STCLEAR_FLAGS; + +// +// Part 2, section 7.2.1: Flag Restrictions (of TPM_STCLEAR_FLAGS) +// +#define TPM_SF_DEACTIVATED ((TPM_CAPABILITY_AREA) 1) +#define TPM_SF_DISABLEFORCECLEAR ((TPM_CAPABILITY_AREA) 2) +#define TPM_SF_PHYSICALPRESENCE ((TPM_CAPABILITY_AREA) 3) +#define TPM_SF_PHYSICALPRESENCELOCK ((TPM_CAPABILITY_AREA) 4) +#define TPM_SF_BGLOBALLOCK ((TPM_CAPABILITY_AREA) 5) + +/// +/// Part 2, section 7.3: TPM_STANY_FLAGS +/// +typedef struct tdTPM_STANY_FLAGS{ + TPM_STRUCTURE_TAG tag; + BOOLEAN postInitialise; + TPM_MODIFIER_INDICATOR localityModifier; + BOOLEAN transportExclusive; + BOOLEAN TOSPresent; +} TPM_STANY_FLAGS; + +// +// Part 2, section 7.3.1: Flag Restrictions (of TPM_STANY_FLAGS) +// +#define TPM_AF_POSTINITIALISE ((TPM_CAPABILITY_AREA) 1) +#define TPM_AF_LOCALITYMODIFIER ((TPM_CAPABILITY_AREA) 2) +#define TPM_AF_TRANSPORTEXCLUSIVE ((TPM_CAPABILITY_AREA) 3) +#define TPM_AF_TOSPRESENT ((TPM_CAPABILITY_AREA) 4) + +// +// All those structures defined in section 7.4, 7.5, 7.6 are not normative and +// thus no definitions here +// +// Part 2, section 7.4: TPM_PERMANENT_DATA +// +#define TPM_MIN_COUNTERS 4 ///< the minimum number of counters is 4 +#define TPM_DELEGATE_KEY TPM_KEY +#define TPM_NUM_PCR 16 +#define TPM_MAX_NV_WRITE_NOOWNER 64 + +// +// Part 2, section 7.4.1: PERMANENT_DATA Subcap for SetCapability +// +#define TPM_PD_REVMAJOR ((TPM_CAPABILITY_AREA) 1) +#define TPM_PD_REVMINOR ((TPM_CAPABILITY_AREA) 2) +#define TPM_PD_TPMPROOF ((TPM_CAPABILITY_AREA) 3) +#define TPM_PD_OWNERAUTH ((TPM_CAPABILITY_AREA) 4) +#define TPM_PD_OPERATORAUTH ((TPM_CAPABILITY_AREA) 5) +#define TPM_PD_MANUMAINTPUB ((TPM_CAPABILITY_AREA) 6) +#define TPM_PD_ENDORSEMENTKEY ((TPM_CAPABILITY_AREA) 7) +#define TPM_PD_SRK ((TPM_CAPABILITY_AREA) 8) +#define TPM_PD_DELEGATEKEY ((TPM_CAPABILITY_AREA) 9) +#define TPM_PD_CONTEXTKEY ((TPM_CAPABILITY_AREA) 10) +#define TPM_PD_AUDITMONOTONICCOUNTER ((TPM_CAPABILITY_AREA) 11) +#define TPM_PD_MONOTONICCOUNTER ((TPM_CAPABILITY_AREA) 12) +#define TPM_PD_PCRATTRIB ((TPM_CAPABILITY_AREA) 13) +#define TPM_PD_ORDINALAUDITSTATUS ((TPM_CAPABILITY_AREA) 14) +#define TPM_PD_AUTHDIR ((TPM_CAPABILITY_AREA) 15) +#define TPM_PD_RNGSTATE ((TPM_CAPABILITY_AREA) 16) +#define TPM_PD_FAMILYTABLE ((TPM_CAPABILITY_AREA) 17) +#define TPM_DELEGATETABLE ((TPM_CAPABILITY_AREA) 18) +#define TPM_PD_EKRESET ((TPM_CAPABILITY_AREA) 19) +#define TPM_PD_MAXNVBUFSIZE ((TPM_CAPABILITY_AREA) 20) +#define TPM_PD_LASTFAMILYID ((TPM_CAPABILITY_AREA) 21) +#define TPM_PD_NOOWNERNVWRITE ((TPM_CAPABILITY_AREA) 22) +#define TPM_PD_RESTRICTDELEGATE ((TPM_CAPABILITY_AREA) 23) +#define TPM_PD_TPMDAASEED ((TPM_CAPABILITY_AREA) 24) +#define TPM_PD_DAAPROOF ((TPM_CAPABILITY_AREA) 25) + +/// +/// Part 2, section 7.5: TPM_STCLEAR_DATA +/// available inside TPM only +/// + typedef struct tdTPM_STCLEAR_DATA{ + TPM_STRUCTURE_TAG tag; + TPM_NONCE contextNonceKey; + TPM_COUNT_ID countID; + UINT32 ownerReference; + BOOLEAN disableResetLock; + TPM_PCRVALUE PCR[TPM_NUM_PCR]; + UINT32 deferredPhysicalPresence; + }TPM_STCLEAR_DATA; + +// +// Part 2, section 7.5.1: STCLEAR_DATA Subcap for SetCapability +// +#define TPM_SD_CONTEXTNONCEKEY ((TPM_CAPABILITY_AREA)0x00000001) +#define TPM_SD_COUNTID ((TPM_CAPABILITY_AREA)0x00000002) +#define TPM_SD_OWNERREFERENCE ((TPM_CAPABILITY_AREA)0x00000003) +#define TPM_SD_DISABLERESETLOCK ((TPM_CAPABILITY_AREA)0x00000004) +#define TPM_SD_PCR ((TPM_CAPABILITY_AREA)0x00000005) +#define TPM_SD_DEFERREDPHYSICALPRESENCE ((TPM_CAPABILITY_AREA)0x00000006) + +// +// Part 2, section 7.6.1: STANY_DATA Subcap for SetCapability +// +#define TPM_AD_CONTEXTNONCESESSION ((TPM_CAPABILITY_AREA) 1) +#define TPM_AD_AUDITDIGEST ((TPM_CAPABILITY_AREA) 2) +#define TPM_AD_CURRENTTICKS ((TPM_CAPABILITY_AREA) 3) +#define TPM_AD_CONTEXTCOUNT ((TPM_CAPABILITY_AREA) 4) +#define TPM_AD_CONTEXTLIST ((TPM_CAPABILITY_AREA) 5) +#define TPM_AD_SESSIONS ((TPM_CAPABILITY_AREA) 6) + +// +// Part 2, section 8: PCR Structures +// + +/// +/// Part 2, section 8.1: TPM_PCR_SELECTION +/// Size of pcrSelect[] indicated by sizeOfSelect +/// +typedef struct tdTPM_PCR_SELECTION { + UINT16 sizeOfSelect; + UINT8 pcrSelect[1]; +} TPM_PCR_SELECTION; + +/// +/// Part 2, section 8.2: TPM_PCR_COMPOSITE +/// Size of pcrValue[] indicated by valueSize +/// +typedef struct tdTPM_PCR_COMPOSITE { + TPM_PCR_SELECTION select; + UINT32 valueSize; + TPM_PCRVALUE pcrValue[1]; +} TPM_PCR_COMPOSITE; + +/// +/// Part 2, section 8.3: TPM_PCR_INFO +/// +typedef struct tdTPM_PCR_INFO { + TPM_PCR_SELECTION pcrSelection; + TPM_COMPOSITE_HASH digestAtRelease; + TPM_COMPOSITE_HASH digestAtCreation; +} TPM_PCR_INFO; + +/// +/// Part 2, section 8.6: TPM_LOCALITY_SELECTION +/// +typedef UINT8 TPM_LOCALITY_SELECTION; + +#define TPM_LOC_FOUR ((UINT8) 0x10) +#define TPM_LOC_THREE ((UINT8) 0x08) +#define TPM_LOC_TWO ((UINT8) 0x04) +#define TPM_LOC_ONE ((UINT8) 0x02) +#define TPM_LOC_ZERO ((UINT8) 0x01) + +/// +/// Part 2, section 8.4: TPM_PCR_INFO_LONG +/// +typedef struct tdTPM_PCR_INFO_LONG { + TPM_STRUCTURE_TAG tag; + TPM_LOCALITY_SELECTION localityAtCreation; + TPM_LOCALITY_SELECTION localityAtRelease; + TPM_PCR_SELECTION creationPCRSelection; + TPM_PCR_SELECTION releasePCRSelection; + TPM_COMPOSITE_HASH digestAtCreation; + TPM_COMPOSITE_HASH digestAtRelease; +} TPM_PCR_INFO_LONG; + +/// +/// Part 2, section 8.5: TPM_PCR_INFO_SHORT +/// +typedef struct tdTPM_PCR_INFO_SHORT{ + TPM_PCR_SELECTION pcrSelection; + TPM_LOCALITY_SELECTION localityAtRelease; + TPM_COMPOSITE_HASH digestAtRelease; +} TPM_PCR_INFO_SHORT; + +/// +/// Part 2, section 8.8: TPM_PCR_ATTRIBUTES +/// +typedef struct tdTPM_PCR_ATTRIBUTES{ + BOOLEAN pcrReset; + TPM_LOCALITY_SELECTION pcrExtendLocal; + TPM_LOCALITY_SELECTION pcrResetLocal; +} TPM_PCR_ATTRIBUTES; + +// +// Part 2, section 9: Storage Structures +// + +/// +/// Part 2, section 9.1: TPM_STORED_DATA +/// [size_is(sealInfoSize)] BYTE* sealInfo; +/// [size_is(encDataSize)] BYTE* encData; +/// +typedef struct tdTPM_STORED_DATA { + TPM_STRUCT_VER ver; + UINT32 sealInfoSize; + UINT8 *sealInfo; + UINT32 encDataSize; + UINT8 *encData; +} TPM_STORED_DATA; + +/// +/// Part 2, section 9.2: TPM_STORED_DATA12 +/// [size_is(sealInfoSize)] BYTE* sealInfo; +/// [size_is(encDataSize)] BYTE* encData; +/// +typedef struct tdTPM_STORED_DATA12 { + TPM_STRUCTURE_TAG tag; + TPM_ENTITY_TYPE et; + UINT32 sealInfoSize; + UINT8 *sealInfo; + UINT32 encDataSize; + UINT8 *encData; +} TPM_STORED_DATA12; + +/// +/// Part 2, section 9.3: TPM_SEALED_DATA +/// [size_is(dataSize)] BYTE* data; +/// +typedef struct tdTPM_SEALED_DATA { + TPM_PAYLOAD_TYPE payload; + TPM_SECRET authData; + TPM_NONCE tpmProof; + TPM_DIGEST storedDigest; + UINT32 dataSize; + UINT8 *data; +} TPM_SEALED_DATA; + +/// +/// Part 2, section 9.4: TPM_SYMMETRIC_KEY +/// [size_is(size)] BYTE* data; +/// +typedef struct tdTPM_SYMMETRIC_KEY { + TPM_ALGORITHM_ID algId; + TPM_ENC_SCHEME encScheme; + UINT16 dataSize; + UINT8 *data; +} TPM_SYMMETRIC_KEY; + +/// +/// Part 2, section 9.5: TPM_BOUND_DATA +/// +typedef struct tdTPM_BOUND_DATA { + TPM_STRUCT_VER ver; + TPM_PAYLOAD_TYPE payload; + UINT8 payloadData[1]; +} TPM_BOUND_DATA; + +// +// Part 2 section 10: TPM_KEY complex +// + +// +// Section 10.1, 10.4, and 10.5 have been defined previously +// + +/// +/// Part 2, section 10.2: TPM_KEY +/// [size_is(encDataSize)] BYTE* encData; +/// +typedef struct tdTPM_KEY{ + TPM_STRUCT_VER ver; + TPM_KEY_USAGE keyUsage; + TPM_KEY_FLAGS keyFlags; + TPM_AUTH_DATA_USAGE authDataUsage; + TPM_KEY_PARMS algorithmParms; + UINT32 PCRInfoSize; + UINT8 *PCRInfo; + TPM_STORE_PUBKEY pubKey; + UINT32 encDataSize; + UINT8 *encData; +} TPM_KEY; + +/// +/// Part 2, section 10.3: TPM_KEY12 +/// [size_is(encDataSize)] BYTE* encData; +/// +typedef struct tdTPM_KEY12{ + TPM_STRUCTURE_TAG tag; + UINT16 fill; + TPM_KEY_USAGE keyUsage; + TPM_KEY_FLAGS keyFlags; + TPM_AUTH_DATA_USAGE authDataUsage; + TPM_KEY_PARMS algorithmParms; + UINT32 PCRInfoSize; + UINT8 *PCRInfo; + TPM_STORE_PUBKEY pubKey; + UINT32 encDataSize; + UINT8 *encData; +} TPM_KEY12; + +/// +/// Part 2, section 10.7: TPM_STORE_PRIVKEY +/// [size_is(keyLength)] BYTE* key; +/// +typedef struct tdTPM_STORE_PRIVKEY { + UINT32 keyLength; + UINT8 *key; +} TPM_STORE_PRIVKEY; + +/// +/// Part 2, section 10.6: TPM_STORE_ASYMKEY +/// +typedef struct tdTPM_STORE_ASYMKEY { // pos len total + TPM_PAYLOAD_TYPE payload; // 0 1 1 + TPM_SECRET usageAuth; // 1 20 21 + TPM_SECRET migrationAuth; // 21 20 41 + TPM_DIGEST pubDataDigest; // 41 20 61 + TPM_STORE_PRIVKEY privKey; // 61 132-151 193-214 +} TPM_STORE_ASYMKEY; + +/// +/// Part 2, section 10.8: TPM_MIGRATE_ASYMKEY +/// [size_is(partPrivKeyLen)] BYTE* partPrivKey; +/// +typedef struct tdTPM_MIGRATE_ASYMKEY { // pos len total + TPM_PAYLOAD_TYPE payload; // 0 1 1 + TPM_SECRET usageAuth; // 1 20 21 + TPM_DIGEST pubDataDigest; // 21 20 41 + UINT32 partPrivKeyLen; // 41 4 45 + UINT8 *partPrivKey; // 45 112-127 157-172 +} TPM_MIGRATE_ASYMKEY; + +/// +/// Part 2, section 10.9: TPM_KEY_CONTROL +/// +#define TPM_KEY_CONTROL_OWNER_EVICT ((UINT32) 0x00000001) + +// +// Part 2, section 11: Signed Structures +// + +/// +/// Part 2, section 11.1: TPM_CERTIFY_INFO Structure +/// +typedef struct tdTPM_CERTIFY_INFO { + TPM_STRUCT_VER version; + TPM_KEY_USAGE keyUsage; + TPM_KEY_FLAGS keyFlags; + TPM_AUTH_DATA_USAGE authDataUsage; + TPM_KEY_PARMS algorithmParms; + TPM_DIGEST pubkeyDigest; + TPM_NONCE data; + BOOLEAN parentPCRStatus; + UINT32 PCRInfoSize; + UINT8 *PCRInfo; +} TPM_CERTIFY_INFO; + +/// +/// Part 2, section 11.2: TPM_CERTIFY_INFO2 Structure +/// +typedef struct tdTPM_CERTIFY_INFO2 { + TPM_STRUCTURE_TAG tag; + UINT8 fill; + TPM_PAYLOAD_TYPE payloadType; + TPM_KEY_USAGE keyUsage; + TPM_KEY_FLAGS keyFlags; + TPM_AUTH_DATA_USAGE authDataUsage; + TPM_KEY_PARMS algorithmParms; + TPM_DIGEST pubkeyDigest; + TPM_NONCE data; + BOOLEAN parentPCRStatus; + UINT32 PCRInfoSize; + UINT8 *PCRInfo; + UINT32 migrationAuthoritySize; + UINT8 *migrationAuthority; +} TPM_CERTIFY_INFO2; + +/// +/// Part 2, section 11.3 TPM_QUOTE_INFO Structure +/// +typedef struct tdTPM_QUOTE_INFO { + TPM_STRUCT_VER version; + UINT8 fixed[4]; + TPM_COMPOSITE_HASH digestValue; + TPM_NONCE externalData; +} TPM_QUOTE_INFO; + +/// +/// Part 2, section 11.4 TPM_QUOTE_INFO2 Structure +/// +typedef struct tdTPM_QUOTE_INFO2 { + TPM_STRUCTURE_TAG tag; + UINT8 fixed[4]; + TPM_NONCE externalData; + TPM_PCR_INFO_SHORT infoShort; +} TPM_QUOTE_INFO2; + +// +// Part 2, section 12: Identity Structures +// + +/// +/// Part 2, section 12.1 TPM_EK_BLOB +/// +typedef struct tdTPM_EK_BLOB { + TPM_STRUCTURE_TAG tag; + TPM_EK_TYPE ekType; + UINT32 blobSize; + UINT8 *blob; +} TPM_EK_BLOB; + +/// +/// Part 2, section 12.2 TPM_EK_BLOB_ACTIVATE +/// +typedef struct tdTPM_EK_BLOB_ACTIVATE { + TPM_STRUCTURE_TAG tag; + TPM_SYMMETRIC_KEY sessionKey; + TPM_DIGEST idDigest; + TPM_PCR_INFO_SHORT pcrInfo; +} TPM_EK_BLOB_ACTIVATE; + +/// +/// Part 2, section 12.3 TPM_EK_BLOB_AUTH +/// +typedef struct tdTPM_EK_BLOB_AUTH { + TPM_STRUCTURE_TAG tag; + TPM_SECRET authValue; +} TPM_EK_BLOB_AUTH; + + +/// +/// Part 2, section 12.5 TPM_IDENTITY_CONTENTS +/// +typedef struct tdTPM_IDENTITY_CONTENTS { + TPM_STRUCT_VER ver; + UINT32 ordinal; + TPM_CHOSENID_HASH labelPrivCADigest; + TPM_PUBKEY identityPubKey; +} TPM_IDENTITY_CONTENTS; + +/// +/// Part 2, section 12.6 TPM_IDENTITY_REQ +/// +typedef struct tdTPM_IDENTITY_REQ { + UINT32 asymSize; + UINT32 symSize; + TPM_KEY_PARMS asymAlgorithm; + TPM_KEY_PARMS symAlgorithm; + UINT8 *asymBlob; + UINT8 *symBlob; +} TPM_IDENTITY_REQ; + +/// +/// Part 2, section 12.7 TPM_IDENTITY_PROOF +/// +typedef struct tdTPM_IDENTITY_PROOF { + TPM_STRUCT_VER ver; + UINT32 labelSize; + UINT32 identityBindingSize; + UINT32 endorsementSize; + UINT32 platformSize; + UINT32 conformanceSize; + TPM_PUBKEY identityKey; + UINT8 *labelArea; + UINT8 *identityBinding; + UINT8 *endorsementCredential; + UINT8 *platformCredential; + UINT8 *conformanceCredential; +} TPM_IDENTITY_PROOF; + +/// +/// Part 2, section 12.8 TPM_ASYM_CA_CONTENTS +/// +typedef struct tdTPM_ASYM_CA_CONTENTS { + TPM_SYMMETRIC_KEY sessionKey; + TPM_DIGEST idDigest; +} TPM_ASYM_CA_CONTENTS; + +/// +/// Part 2, section 12.9 TPM_SYM_CA_ATTESTATION +/// +typedef struct tdTPM_SYM_CA_ATTESTATION { + UINT32 credSize; + TPM_KEY_PARMS algorithm; + UINT8 *credential; +} TPM_SYM_CA_ATTESTATION; + +/// +/// Part 2, section 15: Tick Structures +/// Placed here out of order because definitions are used in section 13. +/// +typedef struct tdTPM_CURRENT_TICKS { + TPM_STRUCTURE_TAG tag; + UINT64 currentTicks; + UINT16 tickRate; + TPM_NONCE tickNonce; +} TPM_CURRENT_TICKS; + +/// +/// Part 2, section 13: Transport structures +/// + +/// +/// Part 2, section 13.1: TPM _TRANSPORT_PUBLIC +/// +typedef struct tdTPM_TRANSPORT_PUBLIC { + TPM_STRUCTURE_TAG tag; + TPM_TRANSPORT_ATTRIBUTES transAttributes; + TPM_ALGORITHM_ID algId; + TPM_ENC_SCHEME encScheme; +} TPM_TRANSPORT_PUBLIC; + +// +// Part 2, section 13.1.1 TPM_TRANSPORT_ATTRIBUTES Definitions +// +#define TPM_TRANSPORT_ENCRYPT ((UINT32)BIT0) +#define TPM_TRANSPORT_LOG ((UINT32)BIT1) +#define TPM_TRANSPORT_EXCLUSIVE ((UINT32)BIT2) + +/// +/// Part 2, section 13.2 TPM_TRANSPORT_INTERNAL +/// +typedef struct tdTPM_TRANSPORT_INTERNAL { + TPM_STRUCTURE_TAG tag; + TPM_AUTHDATA authData; + TPM_TRANSPORT_PUBLIC transPublic; + TPM_TRANSHANDLE transHandle; + TPM_NONCE transNonceEven; + TPM_DIGEST transDigest; +} TPM_TRANSPORT_INTERNAL; + +/// +/// Part 2, section 13.3 TPM_TRANSPORT_LOG_IN structure +/// +typedef struct tdTPM_TRANSPORT_LOG_IN { + TPM_STRUCTURE_TAG tag; + TPM_DIGEST parameters; + TPM_DIGEST pubKeyHash; +} TPM_TRANSPORT_LOG_IN; + +/// +/// Part 2, section 13.4 TPM_TRANSPORT_LOG_OUT structure +/// +typedef struct tdTPM_TRANSPORT_LOG_OUT { + TPM_STRUCTURE_TAG tag; + TPM_CURRENT_TICKS currentTicks; + TPM_DIGEST parameters; + TPM_MODIFIER_INDICATOR locality; +} TPM_TRANSPORT_LOG_OUT; + +/// +/// Part 2, section 13.5 TPM_TRANSPORT_AUTH structure +/// +typedef struct tdTPM_TRANSPORT_AUTH { + TPM_STRUCTURE_TAG tag; + TPM_AUTHDATA authData; +} TPM_TRANSPORT_AUTH; + +// +// Part 2, section 14: Audit Structures +// + +/// +/// Part 2, section 14.1 TPM_AUDIT_EVENT_IN structure +/// +typedef struct tdTPM_AUDIT_EVENT_IN { + TPM_STRUCTURE_TAG tag; + TPM_DIGEST inputParms; + TPM_COUNTER_VALUE auditCount; +} TPM_AUDIT_EVENT_IN; + +/// +/// Part 2, section 14.2 TPM_AUDIT_EVENT_OUT structure +/// +typedef struct tdTPM_AUDIT_EVENT_OUT { + TPM_STRUCTURE_TAG tag; + TPM_COMMAND_CODE ordinal; + TPM_DIGEST outputParms; + TPM_COUNTER_VALUE auditCount; + TPM_RESULT returnCode; +} TPM_AUDIT_EVENT_OUT; + +// +// Part 2, section 16: Return Codes +// + +#define TPM_VENDOR_ERROR TPM_Vendor_Specific32 +#define TPM_NON_FATAL 0x00000800 + +#define TPM_SUCCESS ((TPM_RESULT) TPM_BASE) +#define TPM_AUTHFAIL ((TPM_RESULT) (TPM_BASE + 1)) +#define TPM_BADINDEX ((TPM_RESULT) (TPM_BASE + 2)) +#define TPM_BAD_PARAMETER ((TPM_RESULT) (TPM_BASE + 3)) +#define TPM_AUDITFAILURE ((TPM_RESULT) (TPM_BASE + 4)) +#define TPM_CLEAR_DISABLED ((TPM_RESULT) (TPM_BASE + 5)) +#define TPM_DEACTIVATED ((TPM_RESULT) (TPM_BASE + 6)) +#define TPM_DISABLED ((TPM_RESULT) (TPM_BASE + 7)) +#define TPM_DISABLED_CMD ((TPM_RESULT) (TPM_BASE + 8)) +#define TPM_FAIL ((TPM_RESULT) (TPM_BASE + 9)) +#define TPM_BAD_ORDINAL ((TPM_RESULT) (TPM_BASE + 10)) +#define TPM_INSTALL_DISABLED ((TPM_RESULT) (TPM_BASE + 11)) +#define TPM_INVALID_KEYHANDLE ((TPM_RESULT) (TPM_BASE + 12)) +#define TPM_KEYNOTFOUND ((TPM_RESULT) (TPM_BASE + 13)) +#define TPM_INAPPROPRIATE_ENC ((TPM_RESULT) (TPM_BASE + 14)) +#define TPM_MIGRATEFAIL ((TPM_RESULT) (TPM_BASE + 15)) +#define TPM_INVALID_PCR_INFO ((TPM_RESULT) (TPM_BASE + 16)) +#define TPM_NOSPACE ((TPM_RESULT) (TPM_BASE + 17)) +#define TPM_NOSRK ((TPM_RESULT) (TPM_BASE + 18)) +#define TPM_NOTSEALED_BLOB ((TPM_RESULT) (TPM_BASE + 19)) +#define TPM_OWNER_SET ((TPM_RESULT) (TPM_BASE + 20)) +#define TPM_RESOURCES ((TPM_RESULT) (TPM_BASE + 21)) +#define TPM_SHORTRANDOM ((TPM_RESULT) (TPM_BASE + 22)) +#define TPM_SIZE ((TPM_RESULT) (TPM_BASE + 23)) +#define TPM_WRONGPCRVAL ((TPM_RESULT) (TPM_BASE + 24)) +#define TPM_BAD_PARAM_SIZE ((TPM_RESULT) (TPM_BASE + 25)) +#define TPM_SHA_THREAD ((TPM_RESULT) (TPM_BASE + 26)) +#define TPM_SHA_ERROR ((TPM_RESULT) (TPM_BASE + 27)) +#define TPM_FAILEDSELFTEST ((TPM_RESULT) (TPM_BASE + 28)) +#define TPM_AUTH2FAIL ((TPM_RESULT) (TPM_BASE + 29)) +#define TPM_BADTAG ((TPM_RESULT) (TPM_BASE + 30)) +#define TPM_IOERROR ((TPM_RESULT) (TPM_BASE + 31)) +#define TPM_ENCRYPT_ERROR ((TPM_RESULT) (TPM_BASE + 32)) +#define TPM_DECRYPT_ERROR ((TPM_RESULT) (TPM_BASE + 33)) +#define TPM_INVALID_AUTHHANDLE ((TPM_RESULT) (TPM_BASE + 34)) +#define TPM_NO_ENDORSEMENT ((TPM_RESULT) (TPM_BASE + 35)) +#define TPM_INVALID_KEYUSAGE ((TPM_RESULT) (TPM_BASE + 36)) +#define TPM_WRONG_ENTITYTYPE ((TPM_RESULT) (TPM_BASE + 37)) +#define TPM_INVALID_POSTINIT ((TPM_RESULT) (TPM_BASE + 38)) +#define TPM_INAPPROPRIATE_SIG ((TPM_RESULT) (TPM_BASE + 39)) +#define TPM_BAD_KEY_PROPERTY ((TPM_RESULT) (TPM_BASE + 40)) +#define TPM_BAD_MIGRATION ((TPM_RESULT) (TPM_BASE + 41)) +#define TPM_BAD_SCHEME ((TPM_RESULT) (TPM_BASE + 42)) +#define TPM_BAD_DATASIZE ((TPM_RESULT) (TPM_BASE + 43)) +#define TPM_BAD_MODE ((TPM_RESULT) (TPM_BASE + 44)) +#define TPM_BAD_PRESENCE ((TPM_RESULT) (TPM_BASE + 45)) +#define TPM_BAD_VERSION ((TPM_RESULT) (TPM_BASE + 46)) +#define TPM_NO_WRAP_TRANSPORT ((TPM_RESULT) (TPM_BASE + 47)) +#define TPM_AUDITFAIL_UNSUCCESSFUL ((TPM_RESULT) (TPM_BASE + 48)) +#define TPM_AUDITFAIL_SUCCESSFUL ((TPM_RESULT) (TPM_BASE + 49)) +#define TPM_NOTRESETABLE ((TPM_RESULT) (TPM_BASE + 50)) +#define TPM_NOTLOCAL ((TPM_RESULT) (TPM_BASE + 51)) +#define TPM_BAD_TYPE ((TPM_RESULT) (TPM_BASE + 52)) +#define TPM_INVALID_RESOURCE ((TPM_RESULT) (TPM_BASE + 53)) +#define TPM_NOTFIPS ((TPM_RESULT) (TPM_BASE + 54)) +#define TPM_INVALID_FAMILY ((TPM_RESULT) (TPM_BASE + 55)) +#define TPM_NO_NV_PERMISSION ((TPM_RESULT) (TPM_BASE + 56)) +#define TPM_REQUIRES_SIGN ((TPM_RESULT) (TPM_BASE + 57)) +#define TPM_KEY_NOTSUPPORTED ((TPM_RESULT) (TPM_BASE + 58)) +#define TPM_AUTH_CONFLICT ((TPM_RESULT) (TPM_BASE + 59)) +#define TPM_AREA_LOCKED ((TPM_RESULT) (TPM_BASE + 60)) +#define TPM_BAD_LOCALITY ((TPM_RESULT) (TPM_BASE + 61)) +#define TPM_READ_ONLY ((TPM_RESULT) (TPM_BASE + 62)) +#define TPM_PER_NOWRITE ((TPM_RESULT) (TPM_BASE + 63)) +#define TPM_FAMILYCOUNT ((TPM_RESULT) (TPM_BASE + 64)) +#define TPM_WRITE_LOCKED ((TPM_RESULT) (TPM_BASE + 65)) +#define TPM_BAD_ATTRIBUTES ((TPM_RESULT) (TPM_BASE + 66)) +#define TPM_INVALID_STRUCTURE ((TPM_RESULT) (TPM_BASE + 67)) +#define TPM_KEY_OWNER_CONTROL ((TPM_RESULT) (TPM_BASE + 68)) +#define TPM_BAD_COUNTER ((TPM_RESULT) (TPM_BASE + 69)) +#define TPM_NOT_FULLWRITE ((TPM_RESULT) (TPM_BASE + 70)) +#define TPM_CONTEXT_GAP ((TPM_RESULT) (TPM_BASE + 71)) +#define TPM_MAXNVWRITES ((TPM_RESULT) (TPM_BASE + 72)) +#define TPM_NOOPERATOR ((TPM_RESULT) (TPM_BASE + 73)) +#define TPM_RESOURCEMISSING ((TPM_RESULT) (TPM_BASE + 74)) +#define TPM_DELEGATE_LOCK ((TPM_RESULT) (TPM_BASE + 75)) +#define TPM_DELEGATE_FAMILY ((TPM_RESULT) (TPM_BASE + 76)) +#define TPM_DELEGATE_ADMIN ((TPM_RESULT) (TPM_BASE + 77)) +#define TPM_TRANSPORT_NOTEXCLUSIVE ((TPM_RESULT) (TPM_BASE + 78)) +#define TPM_OWNER_CONTROL ((TPM_RESULT) (TPM_BASE + 79)) +#define TPM_DAA_RESOURCES ((TPM_RESULT) (TPM_BASE + 80)) +#define TPM_DAA_INPUT_DATA0 ((TPM_RESULT) (TPM_BASE + 81)) +#define TPM_DAA_INPUT_DATA1 ((TPM_RESULT) (TPM_BASE + 82)) +#define TPM_DAA_ISSUER_SETTINGS ((TPM_RESULT) (TPM_BASE + 83)) +#define TPM_DAA_TPM_SETTINGS ((TPM_RESULT) (TPM_BASE + 84)) +#define TPM_DAA_STAGE ((TPM_RESULT) (TPM_BASE + 85)) +#define TPM_DAA_ISSUER_VALIDITY ((TPM_RESULT) (TPM_BASE + 86)) +#define TPM_DAA_WRONG_W ((TPM_RESULT) (TPM_BASE + 87)) +#define TPM_BAD_HANDLE ((TPM_RESULT) (TPM_BASE + 88)) +#define TPM_BAD_DELEGATE ((TPM_RESULT) (TPM_BASE + 89)) +#define TPM_BADCONTEXT ((TPM_RESULT) (TPM_BASE + 90)) +#define TPM_TOOMANYCONTEXTS ((TPM_RESULT) (TPM_BASE + 91)) +#define TPM_MA_TICKET_SIGNATURE ((TPM_RESULT) (TPM_BASE + 92)) +#define TPM_MA_DESTINATION ((TPM_RESULT) (TPM_BASE + 93)) +#define TPM_MA_SOURCE ((TPM_RESULT) (TPM_BASE + 94)) +#define TPM_MA_AUTHORITY ((TPM_RESULT) (TPM_BASE + 95)) +#define TPM_PERMANENTEK ((TPM_RESULT) (TPM_BASE + 97)) +#define TPM_BAD_SIGNATURE ((TPM_RESULT) (TPM_BASE + 98)) +#define TPM_NOCONTEXTSPACE ((TPM_RESULT) (TPM_BASE + 99)) + +#define TPM_RETRY ((TPM_RESULT) (TPM_BASE + TPM_NON_FATAL)) +#define TPM_NEEDS_SELFTEST ((TPM_RESULT) (TPM_BASE + TPM_NON_FATAL + 1)) +#define TPM_DOING_SELFTEST ((TPM_RESULT) (TPM_BASE + TPM_NON_FATAL + 2)) +#define TPM_DEFEND_LOCK_RUNNING ((TPM_RESULT) (TPM_BASE + TPM_NON_FATAL + 3)) + +// +// Part 2, section 17: Ordinals +// +// Ordinals are 32 bit values. The upper byte contains values that serve as +// flag indicators, the next byte contains values indicating what committee +// designated the ordinal, and the final two bytes contain the Command +// Ordinal Index. +// 3 2 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |P|C|V| Reserved| Purview | Command Ordinal Index | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Where: +// +// * P is Protected/Unprotected command. When 0 the command is a Protected +// command, when 1 the command is an Unprotected command. +// +// * C is Non-Connection/Connection related command. When 0 this command +// passes through to either the protected (TPM) or unprotected (TSS) +// components. +// +// * V is TPM/Vendor command. When 0 the command is TPM defined, when 1 the +// command is vendor defined. +// +// * All reserved area bits are set to 0. +// + +#define TPM_ORD_ActivateIdentity ((TPM_COMMAND_CODE) 0x0000007A) +#define TPM_ORD_AuthorizeMigrationKey ((TPM_COMMAND_CODE) 0x0000002B) +#define TPM_ORD_CertifyKey ((TPM_COMMAND_CODE) 0x00000032) +#define TPM_ORD_CertifyKey2 ((TPM_COMMAND_CODE) 0x00000033) +#define TPM_ORD_CertifySelfTest ((TPM_COMMAND_CODE) 0x00000052) +#define TPM_ORD_ChangeAuth ((TPM_COMMAND_CODE) 0x0000000C) +#define TPM_ORD_ChangeAuthAsymFinish ((TPM_COMMAND_CODE) 0x0000000F) +#define TPM_ORD_ChangeAuthAsymStart ((TPM_COMMAND_CODE) 0x0000000E) +#define TPM_ORD_ChangeAuthOwner ((TPM_COMMAND_CODE) 0x00000010) +#define TPM_ORD_CMK_ApproveMA ((TPM_COMMAND_CODE) 0x0000001D) +#define TPM_ORD_CMK_ConvertMigration ((TPM_COMMAND_CODE) 0x00000024) +#define TPM_ORD_CMK_CreateBlob ((TPM_COMMAND_CODE) 0x0000001B) +#define TPM_ORD_CMK_CreateKey ((TPM_COMMAND_CODE) 0x00000013) +#define TPM_ORD_CMK_CreateTicket ((TPM_COMMAND_CODE) 0x00000012) +#define TPM_ORD_CMK_SetRestrictions ((TPM_COMMAND_CODE) 0x0000001C) +#define TPM_ORD_ContinueSelfTest ((TPM_COMMAND_CODE) 0x00000053) +#define TPM_ORD_ConvertMigrationBlob ((TPM_COMMAND_CODE) 0x0000002A) +#define TPM_ORD_CreateCounter ((TPM_COMMAND_CODE) 0x000000DC) +#define TPM_ORD_CreateEndorsementKeyPair ((TPM_COMMAND_CODE) 0x00000078) +#define TPM_ORD_CreateMaintenanceArchive ((TPM_COMMAND_CODE) 0x0000002C) +#define TPM_ORD_CreateMigrationBlob ((TPM_COMMAND_CODE) 0x00000028) +#define TPM_ORD_CreateRevocableEK ((TPM_COMMAND_CODE) 0x0000007F) +#define TPM_ORD_CreateWrapKey ((TPM_COMMAND_CODE) 0x0000001F) +#define TPM_ORD_DAA_JOIN ((TPM_COMMAND_CODE) 0x00000029) +#define TPM_ORD_DAA_SIGN ((TPM_COMMAND_CODE) 0x00000031) +#define TPM_ORD_Delegate_CreateKeyDelegation ((TPM_COMMAND_CODE) 0x000000D4) +#define TPM_ORD_Delegate_CreateOwnerDelegation ((TPM_COMMAND_CODE) 0x000000D5) +#define TPM_ORD_Delegate_LoadOwnerDelegation ((TPM_COMMAND_CODE) 0x000000D8) +#define TPM_ORD_Delegate_Manage ((TPM_COMMAND_CODE) 0x000000D2) +#define TPM_ORD_Delegate_ReadTable ((TPM_COMMAND_CODE) 0x000000DB) +#define TPM_ORD_Delegate_UpdateVerification ((TPM_COMMAND_CODE) 0x000000D1) +#define TPM_ORD_Delegate_VerifyDelegation ((TPM_COMMAND_CODE) 0x000000D6) +#define TPM_ORD_DirRead ((TPM_COMMAND_CODE) 0x0000001A) +#define TPM_ORD_DirWriteAuth ((TPM_COMMAND_CODE) 0x00000019) +#define TPM_ORD_DisableForceClear ((TPM_COMMAND_CODE) 0x0000005E) +#define TPM_ORD_DisableOwnerClear ((TPM_COMMAND_CODE) 0x0000005C) +#define TPM_ORD_DisablePubekRead ((TPM_COMMAND_CODE) 0x0000007E) +#define TPM_ORD_DSAP ((TPM_COMMAND_CODE) 0x00000011) +#define TPM_ORD_EstablishTransport ((TPM_COMMAND_CODE) 0x000000E6) +#define TPM_ORD_EvictKey ((TPM_COMMAND_CODE) 0x00000022) +#define TPM_ORD_ExecuteTransport ((TPM_COMMAND_CODE) 0x000000E7) +#define TPM_ORD_Extend ((TPM_COMMAND_CODE) 0x00000014) +#define TPM_ORD_FieldUpgrade ((TPM_COMMAND_CODE) 0x000000AA) +#define TPM_ORD_FlushSpecific ((TPM_COMMAND_CODE) 0x000000BA) +#define TPM_ORD_ForceClear ((TPM_COMMAND_CODE) 0x0000005D) +#define TPM_ORD_GetAuditDigest ((TPM_COMMAND_CODE) 0x00000085) +#define TPM_ORD_GetAuditDigestSigned ((TPM_COMMAND_CODE) 0x00000086) +#define TPM_ORD_GetAuditEvent ((TPM_COMMAND_CODE) 0x00000082) +#define TPM_ORD_GetAuditEventSigned ((TPM_COMMAND_CODE) 0x00000083) +#define TPM_ORD_GetCapability ((TPM_COMMAND_CODE) 0x00000065) +#define TPM_ORD_GetCapabilityOwner ((TPM_COMMAND_CODE) 0x00000066) +#define TPM_ORD_GetCapabilitySigned ((TPM_COMMAND_CODE) 0x00000064) +#define TPM_ORD_GetOrdinalAuditStatus ((TPM_COMMAND_CODE) 0x0000008C) +#define TPM_ORD_GetPubKey ((TPM_COMMAND_CODE) 0x00000021) +#define TPM_ORD_GetRandom ((TPM_COMMAND_CODE) 0x00000046) +#define TPM_ORD_GetTestResult ((TPM_COMMAND_CODE) 0x00000054) +#define TPM_ORD_GetTicks ((TPM_COMMAND_CODE) 0x000000F1) +#define TPM_ORD_IncrementCounter ((TPM_COMMAND_CODE) 0x000000DD) +#define TPM_ORD_Init ((TPM_COMMAND_CODE) 0x00000097) +#define TPM_ORD_KeyControlOwner ((TPM_COMMAND_CODE) 0x00000023) +#define TPM_ORD_KillMaintenanceFeature ((TPM_COMMAND_CODE) 0x0000002E) +#define TPM_ORD_LoadAuthContext ((TPM_COMMAND_CODE) 0x000000B7) +#define TPM_ORD_LoadContext ((TPM_COMMAND_CODE) 0x000000B9) +#define TPM_ORD_LoadKey ((TPM_COMMAND_CODE) 0x00000020) +#define TPM_ORD_LoadKey2 ((TPM_COMMAND_CODE) 0x00000041) +#define TPM_ORD_LoadKeyContext ((TPM_COMMAND_CODE) 0x000000B5) +#define TPM_ORD_LoadMaintenanceArchive ((TPM_COMMAND_CODE) 0x0000002D) +#define TPM_ORD_LoadManuMaintPub ((TPM_COMMAND_CODE) 0x0000002F) +#define TPM_ORD_MakeIdentity ((TPM_COMMAND_CODE) 0x00000079) +#define TPM_ORD_MigrateKey ((TPM_COMMAND_CODE) 0x00000025) +#define TPM_ORD_NV_DefineSpace ((TPM_COMMAND_CODE) 0x000000CC) +#define TPM_ORD_NV_ReadValue ((TPM_COMMAND_CODE) 0x000000CF) +#define TPM_ORD_NV_ReadValueAuth ((TPM_COMMAND_CODE) 0x000000D0) +#define TPM_ORD_NV_WriteValue ((TPM_COMMAND_CODE) 0x000000CD) +#define TPM_ORD_NV_WriteValueAuth ((TPM_COMMAND_CODE) 0x000000CE) +#define TPM_ORD_OIAP ((TPM_COMMAND_CODE) 0x0000000A) +#define TPM_ORD_OSAP ((TPM_COMMAND_CODE) 0x0000000B) +#define TPM_ORD_OwnerClear ((TPM_COMMAND_CODE) 0x0000005B) +#define TPM_ORD_OwnerReadInternalPub ((TPM_COMMAND_CODE) 0x00000081) +#define TPM_ORD_OwnerReadPubek ((TPM_COMMAND_CODE) 0x0000007D) +#define TPM_ORD_OwnerSetDisable ((TPM_COMMAND_CODE) 0x0000006E) +#define TPM_ORD_PCR_Reset ((TPM_COMMAND_CODE) 0x000000C8) +#define TPM_ORD_PcrRead ((TPM_COMMAND_CODE) 0x00000015) +#define TPM_ORD_PhysicalDisable ((TPM_COMMAND_CODE) 0x00000070) +#define TPM_ORD_PhysicalEnable ((TPM_COMMAND_CODE) 0x0000006F) +#define TPM_ORD_PhysicalSetDeactivated ((TPM_COMMAND_CODE) 0x00000072) +#define TPM_ORD_Quote ((TPM_COMMAND_CODE) 0x00000016) +#define TPM_ORD_Quote2 ((TPM_COMMAND_CODE) 0x0000003E) +#define TPM_ORD_ReadCounter ((TPM_COMMAND_CODE) 0x000000DE) +#define TPM_ORD_ReadManuMaintPub ((TPM_COMMAND_CODE) 0x00000030) +#define TPM_ORD_ReadPubek ((TPM_COMMAND_CODE) 0x0000007C) +#define TPM_ORD_ReleaseCounter ((TPM_COMMAND_CODE) 0x000000DF) +#define TPM_ORD_ReleaseCounterOwner ((TPM_COMMAND_CODE) 0x000000E0) +#define TPM_ORD_ReleaseTransportSigned ((TPM_COMMAND_CODE) 0x000000E8) +#define TPM_ORD_Reset ((TPM_COMMAND_CODE) 0x0000005A) +#define TPM_ORD_ResetLockValue ((TPM_COMMAND_CODE) 0x00000040) +#define TPM_ORD_RevokeTrust ((TPM_COMMAND_CODE) 0x00000080) +#define TPM_ORD_SaveAuthContext ((TPM_COMMAND_CODE) 0x000000B6) +#define TPM_ORD_SaveContext ((TPM_COMMAND_CODE) 0x000000B8) +#define TPM_ORD_SaveKeyContext ((TPM_COMMAND_CODE) 0x000000B4) +#define TPM_ORD_SaveState ((TPM_COMMAND_CODE) 0x00000098) +#define TPM_ORD_Seal ((TPM_COMMAND_CODE) 0x00000017) +#define TPM_ORD_Sealx ((TPM_COMMAND_CODE) 0x0000003D) +#define TPM_ORD_SelfTestFull ((TPM_COMMAND_CODE) 0x00000050) +#define TPM_ORD_SetCapability ((TPM_COMMAND_CODE) 0x0000003F) +#define TPM_ORD_SetOperatorAuth ((TPM_COMMAND_CODE) 0x00000074) +#define TPM_ORD_SetOrdinalAuditStatus ((TPM_COMMAND_CODE) 0x0000008D) +#define TPM_ORD_SetOwnerInstall ((TPM_COMMAND_CODE) 0x00000071) +#define TPM_ORD_SetOwnerPointer ((TPM_COMMAND_CODE) 0x00000075) +#define TPM_ORD_SetRedirection ((TPM_COMMAND_CODE) 0x0000009A) +#define TPM_ORD_SetTempDeactivated ((TPM_COMMAND_CODE) 0x00000073) +#define TPM_ORD_SHA1Complete ((TPM_COMMAND_CODE) 0x000000A2) +#define TPM_ORD_SHA1CompleteExtend ((TPM_COMMAND_CODE) 0x000000A3) +#define TPM_ORD_SHA1Start ((TPM_COMMAND_CODE) 0x000000A0) +#define TPM_ORD_SHA1Update ((TPM_COMMAND_CODE) 0x000000A1) +#define TPM_ORD_Sign ((TPM_COMMAND_CODE) 0x0000003C) +#define TPM_ORD_Startup ((TPM_COMMAND_CODE) 0x00000099) +#define TPM_ORD_StirRandom ((TPM_COMMAND_CODE) 0x00000047) +#define TPM_ORD_TakeOwnership ((TPM_COMMAND_CODE) 0x0000000D) +#define TPM_ORD_Terminate_Handle ((TPM_COMMAND_CODE) 0x00000096) +#define TPM_ORD_TickStampBlob ((TPM_COMMAND_CODE) 0x000000F2) +#define TPM_ORD_UnBind ((TPM_COMMAND_CODE) 0x0000001E) +#define TPM_ORD_Unseal ((TPM_COMMAND_CODE) 0x00000018) +#define TSC_ORD_PhysicalPresence ((TPM_COMMAND_CODE) 0x4000000A) +#define TSC_ORD_ResetEstablishmentBit ((TPM_COMMAND_CODE) 0x4000000B) + +// +// Part 2, section 18: Context structures +// + +/// +/// Part 2, section 18.1: TPM_CONTEXT_BLOB +/// +typedef struct tdTPM_CONTEXT_BLOB { + TPM_STRUCTURE_TAG tag; + TPM_RESOURCE_TYPE resourceType; + TPM_HANDLE handle; + UINT8 label[16]; + UINT32 contextCount; + TPM_DIGEST integrityDigest; + UINT32 additionalSize; + UINT8 *additionalData; + UINT32 sensitiveSize; + UINT8 *sensitiveData; +} TPM_CONTEXT_BLOB; + +/// +/// Part 2, section 18.2 TPM_CONTEXT_SENSITIVE +/// +typedef struct tdTPM_CONTEXT_SENSITIVE { + TPM_STRUCTURE_TAG tag; + TPM_NONCE contextNonce; + UINT32 internalSize; + UINT8 *internalData; +} TPM_CONTEXT_SENSITIVE; + +// +// Part 2, section 19: NV Structures +// + +// +// Part 2, section 19.1.1: Required TPM_NV_INDEX values +// +#define TPM_NV_INDEX_LOCK ((UINT32)0xffffffff) +#define TPM_NV_INDEX0 ((UINT32)0x00000000) +#define TPM_NV_INDEX_DIR ((UINT32)0x10000001) +#define TPM_NV_INDEX_EKCert ((UINT32)0x0000f000) +#define TPM_NV_INDEX_TPM_CC ((UINT32)0x0000f001) +#define TPM_NV_INDEX_PlatformCert ((UINT32)0x0000f002) +#define TPM_NV_INDEX_Platform_CC ((UINT32)0x0000f003) +// +// Part 2, section 19.1.2: Reserved Index values +// +#define TPM_NV_INDEX_TSS_BASE ((UINT32)0x00011100) +#define TPM_NV_INDEX_PC_BASE ((UINT32)0x00011200) +#define TPM_NV_INDEX_SERVER_BASE ((UINT32)0x00011300) +#define TPM_NV_INDEX_MOBILE_BASE ((UINT32)0x00011400) +#define TPM_NV_INDEX_PERIPHERAL_BASE ((UINT32)0x00011500) +#define TPM_NV_INDEX_GROUP_RESV_BASE ((UINT32)0x00010000) + +/// +/// Part 2, section 19.2: TPM_NV_ATTRIBUTES +/// +typedef struct tdTPM_NV_ATTRIBUTES { + TPM_STRUCTURE_TAG tag; + UINT32 attributes; +} TPM_NV_ATTRIBUTES; + +#define TPM_NV_PER_READ_STCLEAR (BIT31) +#define TPM_NV_PER_AUTHREAD (BIT18) +#define TPM_NV_PER_OWNERREAD (BIT17) +#define TPM_NV_PER_PPREAD (BIT16) +#define TPM_NV_PER_GLOBALLOCK (BIT15) +#define TPM_NV_PER_WRITE_STCLEAR (BIT14) +#define TPM_NV_PER_WRITEDEFINE (BIT13) +#define TPM_NV_PER_WRITEALL (BIT12) +#define TPM_NV_PER_AUTHWRITE (BIT2) +#define TPM_NV_PER_OWNERWRITE (BIT1) +#define TPM_NV_PER_PPWRITE (BIT0) + +/// +/// Part 2, section 19.3: TPM_NV_DATA_PUBLIC +/// +typedef struct tdTPM_NV_DATA_PUBLIC { + TPM_STRUCTURE_TAG tag; + TPM_NV_INDEX nvIndex; + TPM_PCR_INFO_SHORT pcrInfoRead; + TPM_PCR_INFO_SHORT pcrInfoWrite; + TPM_NV_ATTRIBUTES permission; + BOOLEAN bReadSTClear; + BOOLEAN bWriteSTClear; + BOOLEAN bWriteDefine; + UINT32 dataSize; +} TPM_NV_DATA_PUBLIC; + +// +// Part 2, section 20: Delegate Structures +// + +#define TPM_DEL_OWNER_BITS ((UINT32)0x00000001) +#define TPM_DEL_KEY_BITS ((UINT32)0x00000002) +/// +/// Part 2, section 20.2: Delegate Definitions +/// +typedef struct tdTPM_DELEGATIONS { + TPM_STRUCTURE_TAG tag; + UINT32 delegateType; + UINT32 per1; + UINT32 per2; +} TPM_DELEGATIONS; + +// +// Part 2, section 20.2.1: Owner Permission Settings +// +#define TPM_DELEGATE_SetOrdinalAuditStatus (BIT30) +#define TPM_DELEGATE_DirWriteAuth (BIT29) +#define TPM_DELEGATE_CMK_ApproveMA (BIT28) +#define TPM_DELEGATE_NV_WriteValue (BIT27) +#define TPM_DELEGATE_CMK_CreateTicket (BIT26) +#define TPM_DELEGATE_NV_ReadValue (BIT25) +#define TPM_DELEGATE_Delegate_LoadOwnerDelegation (BIT24) +#define TPM_DELEGATE_DAA_Join (BIT23) +#define TPM_DELEGATE_AuthorizeMigrationKey (BIT22) +#define TPM_DELEGATE_CreateMaintenanceArchive (BIT21) +#define TPM_DELEGATE_LoadMaintenanceArchive (BIT20) +#define TPM_DELEGATE_KillMaintenanceFeature (BIT19) +#define TPM_DELEGATE_OwnerReadInteralPub (BIT18) +#define TPM_DELEGATE_ResetLockValue (BIT17) +#define TPM_DELEGATE_OwnerClear (BIT16) +#define TPM_DELEGATE_DisableOwnerClear (BIT15) +#define TPM_DELEGATE_NV_DefineSpace (BIT14) +#define TPM_DELEGATE_OwnerSetDisable (BIT13) +#define TPM_DELEGATE_SetCapability (BIT12) +#define TPM_DELEGATE_MakeIdentity (BIT11) +#define TPM_DELEGATE_ActivateIdentity (BIT10) +#define TPM_DELEGATE_OwnerReadPubek (BIT9) +#define TPM_DELEGATE_DisablePubekRead (BIT8) +#define TPM_DELEGATE_SetRedirection (BIT7) +#define TPM_DELEGATE_FieldUpgrade (BIT6) +#define TPM_DELEGATE_Delegate_UpdateVerification (BIT5) +#define TPM_DELEGATE_CreateCounter (BIT4) +#define TPM_DELEGATE_ReleaseCounterOwner (BIT3) +#define TPM_DELEGATE_DelegateManage (BIT2) +#define TPM_DELEGATE_Delegate_CreateOwnerDelegation (BIT1) +#define TPM_DELEGATE_DAA_Sign (BIT0) + +// +// Part 2, section 20.2.3: Key Permission settings +// +#define TPM_KEY_DELEGATE_CMK_ConvertMigration (BIT28) +#define TPM_KEY_DELEGATE_TickStampBlob (BIT27) +#define TPM_KEY_DELEGATE_ChangeAuthAsymStart (BIT26) +#define TPM_KEY_DELEGATE_ChangeAuthAsymFinish (BIT25) +#define TPM_KEY_DELEGATE_CMK_CreateKey (BIT24) +#define TPM_KEY_DELEGATE_MigrateKey (BIT23) +#define TPM_KEY_DELEGATE_LoadKey2 (BIT22) +#define TPM_KEY_DELEGATE_EstablishTransport (BIT21) +#define TPM_KEY_DELEGATE_ReleaseTransportSigned (BIT20) +#define TPM_KEY_DELEGATE_Quote2 (BIT19) +#define TPM_KEY_DELEGATE_Sealx (BIT18) +#define TPM_KEY_DELEGATE_MakeIdentity (BIT17) +#define TPM_KEY_DELEGATE_ActivateIdentity (BIT16) +#define TPM_KEY_DELEGATE_GetAuditDigestSigned (BIT15) +#define TPM_KEY_DELEGATE_Sign (BIT14) +#define TPM_KEY_DELEGATE_CertifyKey2 (BIT13) +#define TPM_KEY_DELEGATE_CertifyKey (BIT12) +#define TPM_KEY_DELEGATE_CreateWrapKey (BIT11) +#define TPM_KEY_DELEGATE_CMK_CreateBlob (BIT10) +#define TPM_KEY_DELEGATE_CreateMigrationBlob (BIT9) +#define TPM_KEY_DELEGATE_ConvertMigrationBlob (BIT8) +#define TPM_KEY_DELEGATE_CreateKeyDelegation (BIT7) +#define TPM_KEY_DELEGATE_ChangeAuth (BIT6) +#define TPM_KEY_DELEGATE_GetPubKey (BIT5) +#define TPM_KEY_DELEGATE_UnBind (BIT4) +#define TPM_KEY_DELEGATE_Quote (BIT3) +#define TPM_KEY_DELEGATE_Unseal (BIT2) +#define TPM_KEY_DELEGATE_Seal (BIT1) +#define TPM_KEY_DELEGATE_LoadKey (BIT0) + +// +// Part 2, section 20.3: TPM_FAMILY_FLAGS +// +#define TPM_DELEGATE_ADMIN_LOCK (BIT1) +#define TPM_FAMFLAG_ENABLE (BIT0) + +/// +/// Part 2, section 20.4: TPM_FAMILY_LABEL +/// +typedef struct tdTPM_FAMILY_LABEL { + UINT8 label; +} TPM_FAMILY_LABEL; + +/// +/// Part 2, section 20.5: TPM_FAMILY_TABLE_ENTRY +/// +typedef struct tdTPM_FAMILY_TABLE_ENTRY { + TPM_STRUCTURE_TAG tag; + TPM_FAMILY_LABEL label; + TPM_FAMILY_ID familyID; + TPM_FAMILY_VERIFICATION verificationCount; + TPM_FAMILY_FLAGS flags; +} TPM_FAMILY_TABLE_ENTRY; + +// +// Part 2, section 20.6: TPM_FAMILY_TABLE +// +#define TPM_NUM_FAMILY_TABLE_ENTRY_MIN 8 + +typedef struct tdTPM_FAMILY_TABLE{ + TPM_FAMILY_TABLE_ENTRY famTableRow[TPM_NUM_FAMILY_TABLE_ENTRY_MIN]; +} TPM_FAMILY_TABLE; + +/// +/// Part 2, section 20.7: TPM_DELEGATE_LABEL +/// +typedef struct tdTPM_DELEGATE_LABEL { + UINT8 label; +} TPM_DELEGATE_LABEL; + +/// +/// Part 2, section 20.8: TPM_DELEGATE_PUBLIC +/// +typedef struct tdTPM_DELEGATE_PUBLIC { + TPM_STRUCTURE_TAG tag; + TPM_DELEGATE_LABEL label; + TPM_PCR_INFO_SHORT pcrInfo; + TPM_DELEGATIONS permissions; + TPM_FAMILY_ID familyID; + TPM_FAMILY_VERIFICATION verificationCount; +} TPM_DELEGATE_PUBLIC; + +/// +/// Part 2, section 20.9: TPM_DELEGATE_TABLE_ROW +/// +typedef struct tdTPM_DELEGATE_TABLE_ROW { + TPM_STRUCTURE_TAG tag; + TPM_DELEGATE_PUBLIC pub; + TPM_SECRET authValue; +} TPM_DELEGATE_TABLE_ROW; + +// +// Part 2, section 20.10: TPM_DELEGATE_TABLE +// +#define TPM_NUM_DELEGATE_TABLE_ENTRY_MIN 2 + +typedef struct tdTPM_DELEGATE_TABLE{ + TPM_DELEGATE_TABLE_ROW delRow[TPM_NUM_DELEGATE_TABLE_ENTRY_MIN]; +} TPM_DELEGATE_TABLE; + +/// +/// Part 2, section 20.11: TPM_DELEGATE_SENSITIVE +/// +typedef struct tdTPM_DELEGATE_SENSITIVE { + TPM_STRUCTURE_TAG tag; + TPM_SECRET authValue; +} TPM_DELEGATE_SENSITIVE; + +/// +/// Part 2, section 20.12: TPM_DELEGATE_OWNER_BLOB +/// +typedef struct tdTPM_DELEGATE_OWNER_BLOB { + TPM_STRUCTURE_TAG tag; + TPM_DELEGATE_PUBLIC pub; + TPM_DIGEST integrityDigest; + UINT32 additionalSize; + UINT8 *additionalArea; + UINT32 sensitiveSize; + UINT8 *sensitiveArea; +} TPM_DELEGATE_OWNER_BLOB; + +/// +/// Part 2, section 20.13: TTPM_DELEGATE_KEY_BLOB +/// +typedef struct tdTPM_DELEGATE_KEY_BLOB { + TPM_STRUCTURE_TAG tag; + TPM_DELEGATE_PUBLIC pub; + TPM_DIGEST integrityDigest; + TPM_DIGEST pubKeyDigest; + UINT32 additionalSize; + UINT8 *additionalArea; + UINT32 sensitiveSize; + UINT8 *sensitiveArea; +} TPM_DELEGATE_KEY_BLOB; + +// +// Part 2, section 20.14: TPM_FAMILY_OPERATION Values +// +#define TPM_FAMILY_CREATE ((UINT32)0x00000001) +#define TPM_FAMILY_ENABLE ((UINT32)0x00000002) +#define TPM_FAMILY_ADMIN ((UINT32)0x00000003) +#define TPM_FAMILY_INVALIDATE ((UINT32)0x00000004) + +// +// Part 2, section 21.1: TPM_CAPABILITY_AREA for GetCapability +// +#define TPM_CAP_ORD ((TPM_CAPABILITY_AREA) 0x00000001) +#define TPM_CAP_ALG ((TPM_CAPABILITY_AREA) 0x00000002) +#define TPM_CAP_PID ((TPM_CAPABILITY_AREA) 0x00000003) +#define TPM_CAP_FLAG ((TPM_CAPABILITY_AREA) 0x00000004) +#define TPM_CAP_PROPERTY ((TPM_CAPABILITY_AREA) 0x00000005) +#define TPM_CAP_VERSION ((TPM_CAPABILITY_AREA) 0x00000006) +#define TPM_CAP_KEY_HANDLE ((TPM_CAPABILITY_AREA) 0x00000007) +#define TPM_CAP_CHECK_LOADED ((TPM_CAPABILITY_AREA) 0x00000008) +#define TPM_CAP_SYM_MODE ((TPM_CAPABILITY_AREA) 0x00000009) +#define TPM_CAP_KEY_STATUS ((TPM_CAPABILITY_AREA) 0x0000000C) +#define TPM_CAP_NV_LIST ((TPM_CAPABILITY_AREA) 0x0000000D) +#define TPM_CAP_MFR ((TPM_CAPABILITY_AREA) 0x00000010) +#define TPM_CAP_NV_INDEX ((TPM_CAPABILITY_AREA) 0x00000011) +#define TPM_CAP_TRANS_ALG ((TPM_CAPABILITY_AREA) 0x00000012) +#define TPM_CAP_HANDLE ((TPM_CAPABILITY_AREA) 0x00000014) +#define TPM_CAP_TRANS_ES ((TPM_CAPABILITY_AREA) 0x00000015) +#define TPM_CAP_AUTH_ENCRYPT ((TPM_CAPABILITY_AREA) 0x00000017) +#define TPM_CAP_SELECT_SIZE ((TPM_CAPABILITY_AREA) 0x00000018) +#define TPM_CAP_VERSION_VAL ((TPM_CAPABILITY_AREA) 0x0000001A) + +#define TPM_CAP_FLAG_PERMANENT ((TPM_CAPABILITY_AREA) 0x00000108) +#define TPM_CAP_FLAG_VOLATILE ((TPM_CAPABILITY_AREA) 0x00000109) + +// +// Part 2, section 21.2: CAP_PROPERTY Subcap values for GetCapability +// +#define TPM_CAP_PROP_PCR ((TPM_CAPABILITY_AREA) 0x00000101) +#define TPM_CAP_PROP_DIR ((TPM_CAPABILITY_AREA) 0x00000102) +#define TPM_CAP_PROP_MANUFACTURER ((TPM_CAPABILITY_AREA) 0x00000103) +#define TPM_CAP_PROP_KEYS ((TPM_CAPABILITY_AREA) 0x00000104) +#define TPM_CAP_PROP_MIN_COUNTER ((TPM_CAPABILITY_AREA) 0x00000107) +#define TPM_CAP_PROP_AUTHSESS ((TPM_CAPABILITY_AREA) 0x0000010A) +#define TPM_CAP_PROP_TRANSESS ((TPM_CAPABILITY_AREA) 0x0000010B) +#define TPM_CAP_PROP_COUNTERS ((TPM_CAPABILITY_AREA) 0x0000010C) +#define TPM_CAP_PROP_MAX_AUTHSESS ((TPM_CAPABILITY_AREA) 0x0000010D) +#define TPM_CAP_PROP_MAX_TRANSESS ((TPM_CAPABILITY_AREA) 0x0000010E) +#define TPM_CAP_PROP_MAX_COUNTERS ((TPM_CAPABILITY_AREA) 0x0000010F) +#define TPM_CAP_PROP_MAX_KEYS ((TPM_CAPABILITY_AREA) 0x00000110) +#define TPM_CAP_PROP_OWNER ((TPM_CAPABILITY_AREA) 0x00000111) +#define TPM_CAP_PROP_CONTEXT ((TPM_CAPABILITY_AREA) 0x00000112) +#define TPM_CAP_PROP_MAX_CONTEXT ((TPM_CAPABILITY_AREA) 0x00000113) +#define TPM_CAP_PROP_FAMILYROWS ((TPM_CAPABILITY_AREA) 0x00000114) +#define TPM_CAP_PROP_TIS_TIMEOUT ((TPM_CAPABILITY_AREA) 0x00000115) +#define TPM_CAP_PROP_STARTUP_EFFECT ((TPM_CAPABILITY_AREA) 0x00000116) +#define TPM_CAP_PROP_DELEGATE_ROW ((TPM_CAPABILITY_AREA) 0x00000117) +#define TPM_CAP_PROP_DAA_MAX ((TPM_CAPABILITY_AREA) 0x00000119) +#define CAP_PROP_SESSION_DAA ((TPM_CAPABILITY_AREA) 0x0000011A) +#define TPM_CAP_PROP_CONTEXT_DIST ((TPM_CAPABILITY_AREA) 0x0000011B) +#define TPM_CAP_PROP_DAA_INTERRUPT ((TPM_CAPABILITY_AREA) 0x0000011C) +#define TPM_CAP_PROP_SESSIONS ((TPM_CAPABILITY_AREA) 0x0000011D) +#define TPM_CAP_PROP_MAX_SESSIONS ((TPM_CAPABILITY_AREA) 0x0000011E) +#define TPM_CAP_PROP_CMK_RESTRICTION ((TPM_CAPABILITY_AREA) 0x0000011F) +#define TPM_CAP_PROP_DURATION ((TPM_CAPABILITY_AREA) 0x00000120) +#define TPM_CAP_PROP_ACTIVE_COUNTER ((TPM_CAPABILITY_AREA) 0x00000122) +#define TPM_CAP_PROP_MAX_NV_AVAILABLE ((TPM_CAPABILITY_AREA) 0x00000123) +#define TPM_CAP_PROP_INPUT_BUFFER ((TPM_CAPABILITY_AREA) 0x00000124) + +// +// Part 2, section 21.4: TPM_CAPABILITY_AREA for SetCapability +// +#define TPM_SET_PERM_FLAGS ((TPM_CAPABILITY_AREA) 0x00000001) +#define TPM_SET_PERM_DATA ((TPM_CAPABILITY_AREA) 0x00000002) +#define TPM_SET_STCLEAR_FLAGS ((TPM_CAPABILITY_AREA) 0x00000003) +#define TPM_SET_STCLEAR_DATA ((TPM_CAPABILITY_AREA) 0x00000004) +#define TPM_SET_STANY_FLAGS ((TPM_CAPABILITY_AREA) 0x00000005) +#define TPM_SET_STANY_DATA ((TPM_CAPABILITY_AREA) 0x00000006) + +/// +/// Part 2, section 21.6: TPM_CAP_VERSION_INFO +/// [size_is(vendorSpecificSize)] BYTE* vendorSpecific; +/// +typedef struct tdTPM_CAP_VERSION_INFO { + TPM_STRUCTURE_TAG tag; + TPM_VERSION version; + UINT16 specLevel; + UINT8 errataRev; + UINT8 tpmVendorID[4]; + UINT16 vendorSpecificSize; + UINT8 *vendorSpecific; +} TPM_CAP_VERSION_INFO; + +/// +/// Part 2, section 21.10: TPM_DA_ACTION_TYPE +/// +typedef struct tdTPM_DA_ACTION_TYPE { + TPM_STRUCTURE_TAG tag; + UINT32 actions; +} TPM_DA_ACTION_TYPE; + +#define TPM_DA_ACTION_FAILURE_MODE (((UINT32)1)<<3) +#define TPM_DA_ACTION_DEACTIVATE (((UINT32)1)<<2) +#define TPM_DA_ACTION_DISABLE (((UINT32)1)<<1) +#define TPM_DA_ACTION_TIMEOUT (((UINT32)1)<<0) + +/// +/// Part 2, section 21.7: TPM_DA_INFO +/// +typedef struct tdTPM_DA_INFO { + TPM_STRUCTURE_TAG tag; + TPM_DA_STATE state; + UINT16 currentCount; + UINT16 thresholdCount; + TPM_DA_ACTION_TYPE actionAtThreshold; + UINT32 actionDependValue; + UINT32 vendorDataSize; + UINT8 *vendorData; +} TPM_DA_INFO; + +/// +/// Part 2, section 21.8: TPM_DA_INFO_LIMITED +/// +typedef struct tdTPM_DA_INFO_LIMITED { + TPM_STRUCTURE_TAG tag; + TPM_DA_STATE state; + TPM_DA_ACTION_TYPE actionAtThreshold; + UINT32 vendorDataSize; + UINT8 *vendorData; +} TPM_DA_INFO_LIMITED; + +// +// Part 2, section 21.9: CAP_PROPERTY Subcap values for GetCapability +// +#define TPM_DA_STATE_INACTIVE ((UINT8)0x00) +#define TPM_DA_STATE_ACTIVE ((UINT8)0x01) + +// +// Part 2, section 22: DAA Structures +// + +// +// Part 2, section 22.1: Size definitions +// +#define TPM_DAA_SIZE_r0 (43) +#define TPM_DAA_SIZE_r1 (43) +#define TPM_DAA_SIZE_r2 (128) +#define TPM_DAA_SIZE_r3 (168) +#define TPM_DAA_SIZE_r4 (219) +#define TPM_DAA_SIZE_NT (20) +#define TPM_DAA_SIZE_v0 (128) +#define TPM_DAA_SIZE_v1 (192) +#define TPM_DAA_SIZE_NE (256) +#define TPM_DAA_SIZE_w (256) +#define TPM_DAA_SIZE_issuerModulus (256) +// +// Part 2, section 22.2: Constant definitions +// +#define TPM_DAA_power0 (104) +#define TPM_DAA_power1 (1024) + +/// +/// Part 2, section 22.3: TPM_DAA_ISSUER +/// +typedef struct tdTPM_DAA_ISSUER { + TPM_STRUCTURE_TAG tag; + TPM_DIGEST DAA_digest_R0; + TPM_DIGEST DAA_digest_R1; + TPM_DIGEST DAA_digest_S0; + TPM_DIGEST DAA_digest_S1; + TPM_DIGEST DAA_digest_n; + TPM_DIGEST DAA_digest_gamma; + UINT8 DAA_generic_q[26]; +} TPM_DAA_ISSUER; + +/// +/// Part 2, section 22.4: TPM_DAA_TPM +/// +typedef struct tdTPM_DAA_TPM { + TPM_STRUCTURE_TAG tag; + TPM_DIGEST DAA_digestIssuer; + TPM_DIGEST DAA_digest_v0; + TPM_DIGEST DAA_digest_v1; + TPM_DIGEST DAA_rekey; + UINT32 DAA_count; +} TPM_DAA_TPM; + +/// +/// Part 2, section 22.5: TPM_DAA_CONTEXT +/// +typedef struct tdTPM_DAA_CONTEXT { + TPM_STRUCTURE_TAG tag; + TPM_DIGEST DAA_digestContext; + TPM_DIGEST DAA_digest; + TPM_DAA_CONTEXT_SEED DAA_contextSeed; + UINT8 DAA_scratch[256]; + UINT8 DAA_stage; +} TPM_DAA_CONTEXT; + +/// +/// Part 2, section 22.6: TPM_DAA_JOINDATA +/// +typedef struct tdTPM_DAA_JOINDATA { + UINT8 DAA_join_u0[128]; + UINT8 DAA_join_u1[138]; + TPM_DIGEST DAA_digest_n0; +} TPM_DAA_JOINDATA; + +/// +/// Part 2, section 22.8: TPM_DAA_BLOB +/// +typedef struct tdTPM_DAA_BLOB { + TPM_STRUCTURE_TAG tag; + TPM_RESOURCE_TYPE resourceType; + UINT8 label[16]; + TPM_DIGEST blobIntegrity; + UINT32 additionalSize; + UINT8 *additionalData; + UINT32 sensitiveSize; + UINT8 *sensitiveData; +} TPM_DAA_BLOB; + +/// +/// Part 2, section 22.9: TPM_DAA_SENSITIVE +/// +typedef struct tdTPM_DAA_SENSITIVE { + TPM_STRUCTURE_TAG tag; + UINT32 internalSize; + UINT8 *internalData; +} TPM_DAA_SENSITIVE; + + +// +// Part 2, section 23: Redirection +// + +/// +/// Part 2 section 23.1: TPM_REDIR_COMMAND +/// This section defines exactly one value but does not +/// give it a name. The definition of TPM_SetRedirection in Part3 +/// refers to exactly one name but does not give its value. We join +/// them here. +/// +#define TPM_REDIR_GPIO (0x00000001) + +/// +/// TPM Command Headers defined in Part 3 +/// +typedef struct tdTPM_RQU_COMMAND_HDR { + TPM_STRUCTURE_TAG tag; + UINT32 paramSize; + TPM_COMMAND_CODE ordinal; +} TPM_RQU_COMMAND_HDR; + +/// +/// TPM Response Headers defined in Part 3 +/// +typedef struct tdTPM_RSP_COMMAND_HDR { + TPM_STRUCTURE_TAG tag; + UINT32 paramSize; + TPM_RESULT returnCode; +} TPM_RSP_COMMAND_HDR; + +#pragma pack () + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/UefiTcgPlatform.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/UefiTcgPlatform.h new file mode 100644 index 000000000..8bb7ea389 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/UefiTcgPlatform.h @@ -0,0 +1,172 @@ +/** @file + TCG EFI Platform Definition in TCG_EFI_Platform_1_20_Final + + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __UEFI_TCG_PLATFORM_H__ +#define __UEFI_TCG_PLATFORM_H__ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/IndustryStandard/Tpm12.h> +#include <ipxe/efi/Uefi.h> + +// +// Standard event types +// +#define EV_POST_CODE ((TCG_EVENTTYPE) 0x00000001) +#define EV_SEPARATOR ((TCG_EVENTTYPE) 0x00000004) +#define EV_S_CRTM_CONTENTS ((TCG_EVENTTYPE) 0x00000007) +#define EV_S_CRTM_VERSION ((TCG_EVENTTYPE) 0x00000008) +#define EV_CPU_MICROCODE ((TCG_EVENTTYPE) 0x00000009) +#define EV_TABLE_OF_DEVICES ((TCG_EVENTTYPE) 0x0000000B) + +// +// EFI specific event types +// +#define EV_EFI_EVENT_BASE ((TCG_EVENTTYPE) 0x80000000) +#define EV_EFI_VARIABLE_DRIVER_CONFIG (EV_EFI_EVENT_BASE + 1) +#define EV_EFI_VARIABLE_BOOT (EV_EFI_EVENT_BASE + 2) +#define EV_EFI_BOOT_SERVICES_APPLICATION (EV_EFI_EVENT_BASE + 3) +#define EV_EFI_BOOT_SERVICES_DRIVER (EV_EFI_EVENT_BASE + 4) +#define EV_EFI_RUNTIME_SERVICES_DRIVER (EV_EFI_EVENT_BASE + 5) +#define EV_EFI_GPT_EVENT (EV_EFI_EVENT_BASE + 6) +#define EV_EFI_ACTION (EV_EFI_EVENT_BASE + 7) +#define EV_EFI_PLATFORM_FIRMWARE_BLOB (EV_EFI_EVENT_BASE + 8) +#define EV_EFI_HANDOFF_TABLES (EV_EFI_EVENT_BASE + 9) + +#define EFI_CALLING_EFI_APPLICATION \ + "Calling EFI Application from Boot Option" +#define EFI_RETURNING_FROM_EFI_APPLICATOIN \ + "Returning from EFI Application from Boot Option" +#define EFI_EXIT_BOOT_SERVICES_INVOCATION \ + "Exit Boot Services Invocation" +#define EFI_EXIT_BOOT_SERVICES_FAILED \ + "Exit Boot Services Returned with Failure" +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED \ + "Exit Boot Services Returned with Success" + + +#define EV_POSTCODE_INFO_POST_CODE "POST CODE" +#define POST_CODE_STR_LEN (sizeof(EV_POSTCODE_INFO_POST_CODE) - 1) + +#define EV_POSTCODE_INFO_SMM_CODE "SMM CODE" +#define SMM_CODE_STR_LEN (sizeof(EV_POSTCODE_INFO_SMM_CODE) - 1) + +#define EV_POSTCODE_INFO_ACPI_DATA "ACPI DATA" +#define ACPI_DATA_LEN (sizeof(EV_POSTCODE_INFO_ACPI_DATA) - 1) + +#define EV_POSTCODE_INFO_BIS_CODE "BIS CODE" +#define BIS_CODE_LEN (sizeof(EV_POSTCODE_INFO_BIS_CODE) - 1) + +#define EV_POSTCODE_INFO_UEFI_PI "UEFI PI" +#define UEFI_PI_LEN (sizeof(EV_POSTCODE_INFO_UEFI_PI) - 1) + +#define EV_POSTCODE_INFO_OPROM "Embedded Option ROM" +#define OPROM_LEN (sizeof(EV_POSTCODE_INFO_OPROM) - 1) + +// +// Set structure alignment to 1-byte +// +#pragma pack (1) + +typedef UINT32 TCG_EVENTTYPE; +typedef TPM_PCRINDEX TCG_PCRINDEX; +typedef TPM_DIGEST TCG_DIGEST; +/// +/// Event Log Entry Structure Definition +/// +typedef struct tdTCG_PCR_EVENT { + TCG_PCRINDEX PCRIndex; ///< PCRIndex event extended to + TCG_EVENTTYPE EventType; ///< TCG EFI event type + TCG_DIGEST Digest; ///< Value extended into PCRIndex + UINT32 EventSize; ///< Size of the event data + UINT8 Event[1]; ///< The event data +} TCG_PCR_EVENT; + +#define TSS_EVENT_DATA_MAX_SIZE 256 + +/// +/// TCG_PCR_EVENT_HDR +/// +typedef struct tdTCG_PCR_EVENT_HDR { + TCG_PCRINDEX PCRIndex; + TCG_EVENTTYPE EventType; + TCG_DIGEST Digest; + UINT32 EventSize; +} TCG_PCR_EVENT_HDR; + +/// +/// EFI_PLATFORM_FIRMWARE_BLOB +/// +/// BlobLength should be of type UINTN but we use UINT64 here +/// because PEI is 32-bit while DXE is 64-bit on x64 platforms +/// +typedef struct tdEFI_PLATFORM_FIRMWARE_BLOB { + EFI_PHYSICAL_ADDRESS BlobBase; + UINT64 BlobLength; +} EFI_PLATFORM_FIRMWARE_BLOB; + +/// +/// EFI_IMAGE_LOAD_EVENT +/// +/// This structure is used in EV_EFI_BOOT_SERVICES_APPLICATION, +/// EV_EFI_BOOT_SERVICES_DRIVER and EV_EFI_RUNTIME_SERVICES_DRIVER +/// +typedef struct tdEFI_IMAGE_LOAD_EVENT { + EFI_PHYSICAL_ADDRESS ImageLocationInMemory; + UINTN ImageLengthInMemory; + UINTN ImageLinkTimeAddress; + UINTN LengthOfDevicePath; + EFI_DEVICE_PATH_PROTOCOL DevicePath[1]; +} EFI_IMAGE_LOAD_EVENT; + +/// +/// EFI_HANDOFF_TABLE_POINTERS +/// +/// This structure is used in EV_EFI_HANDOFF_TABLES event to facilitate +/// the measurement of given configuration tables. +/// +typedef struct tdEFI_HANDOFF_TABLE_POINTERS { + UINTN NumberOfTables; + EFI_CONFIGURATION_TABLE TableEntry[1]; +} EFI_HANDOFF_TABLE_POINTERS; + +/// +/// EFI_VARIABLE_DATA +/// +/// This structure serves as the header for measuring variables. The name of the +/// variable (in Unicode format) should immediately follow, then the variable +/// data. +/// +typedef struct tdEFI_VARIABLE_DATA { + EFI_GUID VariableName; + UINTN UnicodeNameLength; + UINTN VariableDataLength; + CHAR16 UnicodeName[1]; + INT8 VariableData[1]; ///< Driver or platform-specific data +} EFI_VARIABLE_DATA; + +typedef struct tdEFI_GPT_DATA { + EFI_PARTITION_TABLE_HEADER EfiPartitionHeader; + UINTN NumberOfPartitions; + EFI_PARTITION_ENTRY Partitions[1]; +} EFI_GPT_DATA; + +// +// Restore original structure alignment +// +#pragma pack () + +#endif + + diff --git a/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h b/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h index be521f969..e9c31d130 100644 --- a/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h +++ b/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h @@ -2,7 +2,7 @@ Provides string functions, linked list functions, math functions, synchronization functions, and CPU architecture-specific functions. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -148,6 +148,39 @@ typedef struct { #endif // defined (MDE_CPU_ARM) +#if defined (MDE_CPU_AARCH64) +typedef struct { + // GP regs + UINT64 X19; + UINT64 X20; + UINT64 X21; + UINT64 X22; + UINT64 X23; + UINT64 X24; + UINT64 X25; + UINT64 X26; + UINT64 X27; + UINT64 X28; + UINT64 FP; + UINT64 LR; + UINT64 IP0; + + // FP regs + UINT64 D8; + UINT64 D9; + UINT64 D10; + UINT64 D11; + UINT64 D12; + UINT64 D13; + UINT64 D14; + UINT64 D15; +} BASE_LIBRARY_JUMP_BUFFER; + +#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 + +#endif // defined (MDE_CPU_AARCH64) + + // // String Services // @@ -1359,7 +1392,7 @@ InsertTailList ( @param List A pointer to the head node of a doubly linked list. @return The first node of a doubly linked list. - @retval NULL The list is empty. + @retval List The list is empty. **/ LIST_ENTRY * diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h index e007cab83..50d25f23f 100644 --- a/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h +++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h @@ -1,7 +1,7 @@ /** @file Include file matches things in PI. -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -659,7 +659,7 @@ EFI_STATUS // #define DXE_SERVICES_SIGNATURE 0x565245535f455844ULL #define DXE_SPECIFICATION_MAJOR_REVISION 1 -#define DXE_SPECIFICATION_MINOR_REVISION 20 +#define DXE_SPECIFICATION_MINOR_REVISION 30 #define DXE_SERVICES_REVISION ((DXE_SPECIFICATION_MAJOR_REVISION<<16) | (DXE_SPECIFICATION_MINOR_REVISION)) typedef struct { diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h index 4863e146d..e818861b7 100644 --- a/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h +++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h @@ -1,7 +1,7 @@ /** @file The firmware volume related definitions in PI. - Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -11,7 +11,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. @par Revision Reference: - PI Version 1.2C + PI Version 1.3 **/ @@ -88,7 +88,7 @@ typedef UINT32 EFI_FVB_ATTRIBUTES_2; #define EFI_FVB2_ALIGNMENT_512M 0x001D0000 #define EFI_FVB2_ALIGNMENT_1G 0x001E0000 #define EFI_FVB2_ALIGNMENT_2G 0x001F0000 - +#define EFI_FVB2_WEAK_ALIGNMENT 0x80000000 typedef struct { /// diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h index d5d7aaa42..daf6591f5 100644 --- a/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h +++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiMultiPhase.h @@ -1,7 +1,7 @@ /** @file Include file matches things in PI for multiple module types. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -135,4 +135,33 @@ typedef struct { UINT64 RegionState; } EFI_SMRAM_DESCRIPTOR; +typedef enum { + EFI_PCD_TYPE_8, + EFI_PCD_TYPE_16, + EFI_PCD_TYPE_32, + EFI_PCD_TYPE_64, + EFI_PCD_TYPE_BOOL, + EFI_PCD_TYPE_PTR +} EFI_PCD_TYPE; + +typedef struct { + /// + /// The returned information associated with the requested TokenNumber. If + /// TokenNumber is 0, then PcdType is set to EFI_PCD_TYPE_8. + /// + EFI_PCD_TYPE PcdType; + /// + /// The size of the data in bytes associated with the TokenNumber specified. If + /// TokenNumber is 0, then PcdSize is set 0. + /// + UINTN PcdSize; + /// + /// The null-terminated ASCII string associated with a given token. If the + /// TokenNumber specified was 0, then this field corresponds to the null-terminated + /// ASCII string associated with the token's namespace Guid. If NULL, there is no + /// name associated with this request. + /// + CHAR8 *PcdName; +} EFI_PCD_INFO; + #endif diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h index 4c720529f..5bef98f64 100644 --- a/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h +++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h @@ -1,7 +1,7 @@ /** @file StatusCode related definitions in PI. -Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -598,7 +598,10 @@ typedef struct { // // IO Bus Class ATA/ATAPI Subclass Progress Code definitions. // - +#define EFI_IOB_ATA_BUS_SMART_ENABLE (EFI_SUBCLASS_SPECIFIC | 0x00000000) +#define EFI_IOB_ATA_BUS_SMART_DISABLE (EFI_SUBCLASS_SPECIFIC | 0x00000001) +#define EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD (EFI_SUBCLASS_SPECIFIC | 0x00000002) +#define EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD (EFI_SUBCLASS_SPECIFIC | 0x00000003) // // IO Bus Class FC Subclass Progress Code definitions. // @@ -671,6 +674,8 @@ typedef struct { // // IO Bus Class ATA/ATAPI Subclass Error Code definitions. // +#define EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED (EFI_SUBCLASS_SPECIFIC | 0x00000000) +#define EFI_IOB_ATA_BUS_SMART_DISABLED (EFI_SUBCLASS_SPECIFIC | 0x00000001) // // IO Bus Class FC Subclass Error Code definitions. diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Arp.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Arp.h new file mode 100644 index 000000000..80921f9a0 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Arp.h @@ -0,0 +1,387 @@ +/** @file + EFI ARP Protocol Definition + + The EFI ARP Service Binding Protocol is used to locate EFI + ARP Protocol drivers to create and destroy child of the + driver to communicate with other host using ARP protocol. + The EFI ARP Protocol provides services to map IP network + address to hardware address used by a data link protocol. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol was introduced in UEFI Specification 2.0. + +**/ + +#ifndef __EFI_ARP_PROTOCOL_H__ +#define __EFI_ARP_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xf44c00ee, 0x1f2c, 0x4a00, {0xaa, 0x9, 0x1c, 0x9f, 0x3e, 0x8, 0x0, 0xa3 } \ + } + +#define EFI_ARP_PROTOCOL_GUID \ + { \ + 0xf4b427bb, 0xba21, 0x4f16, {0xbc, 0x4e, 0x43, 0xe4, 0x16, 0xab, 0x61, 0x9c } \ + } + +typedef struct _EFI_ARP_PROTOCOL EFI_ARP_PROTOCOL; + +typedef struct { + /// + /// Length in bytes of this entry. + /// + UINT32 Size; + + /// + /// Set to TRUE if this entry is a "deny" entry. + /// Set to FALSE if this entry is a "normal" entry. + /// + BOOLEAN DenyFlag; + + /// + /// Set to TRUE if this entry will not time out. + /// Set to FALSE if this entry will time out. + /// + BOOLEAN StaticFlag; + + /// + /// 16-bit ARP hardware identifier number. + /// + UINT16 HwAddressType; + + /// + /// 16-bit protocol type number. + /// + UINT16 SwAddressType; + + /// + /// The length of the hardware address. + /// + UINT8 HwAddressLength; + + /// + /// The length of the protocol address. + /// + UINT8 SwAddressLength; +} EFI_ARP_FIND_DATA; + +typedef struct { + /// + /// 16-bit protocol type number in host byte order. + /// + UINT16 SwAddressType; + + /// + /// The length in bytes of the station's protocol address to register. + /// + UINT8 SwAddressLength; + + /// + /// The pointer to the first byte of the protocol address to register. For + /// example, if SwAddressType is 0x0800 (IP), then + /// StationAddress points to the first byte of this station's IP + /// address stored in network byte order. + /// + VOID *StationAddress; + + /// + /// The timeout value in 100-ns units that is associated with each + /// new dynamic ARP cache entry. If it is set to zero, the value is + /// implementation-specific. + /// + UINT32 EntryTimeOut; + + /// + /// The number of retries before a MAC address is resolved. If it is + /// set to zero, the value is implementation-specific. + /// + UINT32 RetryCount; + + /// + /// The timeout value in 100-ns units that is used to wait for the ARP + /// reply packet or the timeout value between two retries. Set to zero + /// to use implementation-specific value. + /// + UINT32 RetryTimeOut; +} EFI_ARP_CONFIG_DATA; + + +/** + This function is used to assign a station address to the ARP cache for this instance + of the ARP driver. + + Each ARP instance has one station address. The EFI_ARP_PROTOCOL driver will + respond to ARP requests that match this registered station address. A call to + this function with the ConfigData field set to NULL will reset this ARP instance. + + Once a protocol type and station address have been assigned to this ARP instance, + all the following ARP functions will use this information. Attempting to change + the protocol type or station address to a configured ARP instance will result in errors. + + @param This The pointer to the EFI_ARP_PROTOCOL instance. + @param ConfigData The pointer to the EFI_ARP_CONFIG_DATA structure. + + @retval EFI_SUCCESS The new station address was successfully + registered. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + * This is NULL. + * SwAddressLength is zero when ConfigData is not NULL. + * StationAddress is NULL when ConfigData is not NULL. + @retval EFI_ACCESS_DENIED The SwAddressType, SwAddressLength, or + StationAddress is different from the one that is + already registered. + @retval EFI_OUT_OF_RESOURCES Storage for the new StationAddress could not be + allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_CONFIGURE)( + IN EFI_ARP_PROTOCOL *This, + IN EFI_ARP_CONFIG_DATA *ConfigData OPTIONAL + ); + +/** + This function is used to insert entries into the ARP cache. + + ARP cache entries are typically inserted and updated by network protocol drivers + as network traffic is processed. Most ARP cache entries will time out and be + deleted if the network traffic stops. ARP cache entries that were inserted + by the Add() function may be static (will not time out) or dynamic (will time out). + Default ARP cache timeout values are not covered in most network protocol + specifications (although RFC 1122 comes pretty close) and will only be + discussed in general terms in this specification. The timeout values that are + used in the EFI Sample Implementation should be used only as a guideline. + Final product implementations of the EFI network stack should be tuned for + their expected network environments. + + @param This Pointer to the EFI_ARP_PROTOCOL instance. + @param DenyFlag Set to TRUE if this entry is a deny entry. Set to + FALSE if this entry is a normal entry. + @param TargetSwAddress Pointer to a protocol address to add (or deny). + May be set to NULL if DenyFlag is TRUE. + @param TargetHwAddress Pointer to a hardware address to add (or deny). + May be set to NULL if DenyFlag is TRUE. + @param TimeoutValue Time in 100-ns units that this entry will remain + in the ARP cache. A value of zero means that the + entry is permanent. A nonzero value will override + the one given by Configure() if the entry to be + added is a dynamic entry. + @param Overwrite If TRUE, the matching cache entry will be + overwritten with the supplied parameters. If + FALSE, EFI_ACCESS_DENIED is returned if the + corresponding cache entry already exists. + + @retval EFI_SUCCESS The entry has been added or updated. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + * This is NULL. + * DenyFlag is FALSE and TargetHwAddress is NULL. + * DenyFlag is FALSE and TargetSwAddress is NULL. + * TargetHwAddress is NULL and TargetSwAddress is NULL. + * Neither TargetSwAddress nor TargetHwAddress are NULL when DenyFlag is + TRUE. + @retval EFI_OUT_OF_RESOURCES The new ARP cache entry could not be allocated. + @retval EFI_ACCESS_DENIED The ARP cache entry already exists and Overwrite + is not true. + @retval EFI_NOT_STARTED The ARP driver instance has not been configured. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_ADD)( + IN EFI_ARP_PROTOCOL *This, + IN BOOLEAN DenyFlag, + IN VOID *TargetSwAddress OPTIONAL, + IN VOID *TargetHwAddress OPTIONAL, + IN UINT32 TimeoutValue, + IN BOOLEAN Overwrite + ); + +/** + This function searches the ARP cache for matching entries and allocates a buffer into + which those entries are copied. + + The first part of the allocated buffer is EFI_ARP_FIND_DATA, following which + are protocol address pairs and hardware address pairs. + When finding a specific protocol address (BySwAddress is TRUE and AddressBuffer + is not NULL), the ARP cache timeout for the found entry is reset if Refresh is + set to TRUE. If the found ARP cache entry is a permanent entry, it is not + affected by Refresh. + + @param This The pointer to the EFI_ARP_PROTOCOL instance. + @param BySwAddress Set to TRUE to look for matching software protocol + addresses. Set to FALSE to look for matching + hardware protocol addresses. + @param AddressBuffer The pointer to the address buffer. Set to NULL + to match all addresses. + @param EntryLength The size of an entry in the entries buffer. + @param EntryCount The number of ARP cache entries that are found by + the specified criteria. + @param Entries The pointer to the buffer that will receive the ARP + cache entries. + @param Refresh Set to TRUE to refresh the timeout value of the + matching ARP cache entry. + + @retval EFI_SUCCESS The requested ARP cache entries were copied into + the buffer. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. Both EntryCount and EntryLength are + NULL, when Refresh is FALSE. + @retval EFI_NOT_FOUND No matching entries were found. + @retval EFI_NOT_STARTED The ARP driver instance has not been configured. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_FIND)( + IN EFI_ARP_PROTOCOL *This, + IN BOOLEAN BySwAddress, + IN VOID *AddressBuffer OPTIONAL, + OUT UINT32 *EntryLength OPTIONAL, + OUT UINT32 *EntryCount OPTIONAL, + OUT EFI_ARP_FIND_DATA **Entries OPTIONAL, + IN BOOLEAN Refresh + ); + + +/** + This function removes specified ARP cache entries. + + @param This The pointer to the EFI_ARP_PROTOCOL instance. + @param BySwAddress Set to TRUE to delete matching protocol addresses. + Set to FALSE to delete matching hardware + addresses. + @param AddressBuffer The pointer to the address buffer that is used as a + key to look for the cache entry. Set to NULL to + delete all entries. + + @retval EFI_SUCCESS The entry was removed from the ARP cache. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_FOUND The specified deletion key was not found. + @retval EFI_NOT_STARTED The ARP driver instance has not been configured. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_DELETE)( + IN EFI_ARP_PROTOCOL *This, + IN BOOLEAN BySwAddress, + IN VOID *AddressBuffer OPTIONAL + ); + +/** + This function delete all dynamic entries from the ARP cache that match the specified + software protocol type. + + @param This The pointer to the EFI_ARP_PROTOCOL instance. + + @retval EFI_SUCCESS The cache has been flushed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_FOUND There are no matching dynamic cache entries. + @retval EFI_NOT_STARTED The ARP driver instance has not been configured. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_FLUSH)( + IN EFI_ARP_PROTOCOL *This + ); + +/** + This function tries to resolve the TargetSwAddress and optionally returns a + TargetHwAddress if it already exists in the ARP cache. + + @param This The pointer to the EFI_ARP_PROTOCOL instance. + @param TargetSwAddress The pointer to the protocol address to resolve. + @param ResolvedEvent The pointer to the event that will be signaled when + the address is resolved or some error occurs. + @param TargetHwAddress The pointer to the buffer for the resolved hardware + address in network byte order. + + @retval EFI_SUCCESS The data is copied from the ARP cache into the + TargetHwAddress buffer. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. TargetHwAddress is NULL. + @retval EFI_ACCESS_DENIED The requested address is not present in the normal + ARP cache but is present in the deny address list. + Outgoing traffic to that address is forbidden. + @retval EFI_NOT_STARTED The ARP driver instance has not been configured. + @retval EFI_NOT_READY The request has been started and is not finished. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_REQUEST)( + IN EFI_ARP_PROTOCOL *This, + IN VOID *TargetSwAddress OPTIONAL, + IN EFI_EVENT ResolvedEvent OPTIONAL, + OUT VOID *TargetHwAddress + ); + +/** + This function aborts the previous ARP request (identified by This, TargetSwAddress + and ResolvedEvent) that is issued by EFI_ARP_PROTOCOL.Request(). + + If the request is in the internal ARP request queue, the request is aborted + immediately and its ResolvedEvent is signaled. Only an asynchronous address + request needs to be canceled. If TargeSwAddress and ResolveEvent are both + NULL, all the pending asynchronous requests that have been issued by This + instance will be cancelled and their corresponding events will be signaled. + + @param This The pointer to the EFI_ARP_PROTOCOL instance. + @param TargetSwAddress The pointer to the protocol address in previous + request session. + @param ResolvedEvent Pointer to the event that is used as the + notification event in previous request session. + + @retval EFI_SUCCESS The pending request session(s) is/are aborted and + corresponding event(s) is/are signaled. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. TargetSwAddress is not NULL and + ResolvedEvent is NULL. TargetSwAddress is NULL and + ResolvedEvent is not NULL. + @retval EFI_NOT_STARTED The ARP driver instance has not been configured. + @retval EFI_NOT_FOUND The request is not issued by + EFI_ARP_PROTOCOL.Request(). + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ARP_CANCEL)( + IN EFI_ARP_PROTOCOL *This, + IN VOID *TargetSwAddress OPTIONAL, + IN EFI_EVENT ResolvedEvent OPTIONAL + ); + +/// +/// ARP is used to resolve local network protocol addresses into +/// network hardware addresses. +/// +struct _EFI_ARP_PROTOCOL { + EFI_ARP_CONFIGURE Configure; + EFI_ARP_ADD Add; + EFI_ARP_FIND Find; + EFI_ARP_DELETE Delete; + EFI_ARP_FLUSH Flush; + EFI_ARP_REQUEST Request; + EFI_ARP_CANCEL Cancel; +}; + + +extern EFI_GUID gEfiArpServiceBindingProtocolGuid; +extern EFI_GUID gEfiArpProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/BusSpecificDriverOverride.h b/roms/ipxe/src/include/ipxe/efi/Protocol/BusSpecificDriverOverride.h new file mode 100644 index 000000000..be92323fc --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/BusSpecificDriverOverride.h @@ -0,0 +1,74 @@ +/** @file + Bus Specific Driver Override protocol as defined in the UEFI 2.0 specification. + + Bus drivers that have a bus specific algorithm for matching drivers to controllers are + required to produce this protocol for each controller. For example, a PCI Bus Driver will produce an + instance of this protocol for every PCI controller that has a PCI option ROM that contains one or + more UEFI drivers. The protocol instance is attached to the handle of the PCI controller. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_H_ +#define _EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_H_ + +FILE_LICENCE ( BSD3 ); + +/// +/// Global ID for the Bus Specific Driver Override Protocol +/// +#define EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID \ + { \ + 0x3bc1b285, 0x8a15, 0x4a82, {0xaa, 0xbf, 0x4d, 0x7d, 0x13, 0xfb, 0x32, 0x65 } \ + } + +typedef struct _EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL; + +// +// Prototypes for the Bus Specific Driver Override Protocol +// + +/** + Uses a bus specific algorithm to retrieve a driver image handle for a controller. + + @param This A pointer to the EFI_BUS_SPECIFIC_DRIVER_ + OVERRIDE_PROTOCOL instance. + @param DriverImageHandle On input, a pointer to the previous driver image handle returned + by GetDriver(). On output, a pointer to the next driver + image handle. Passing in a NULL, will return the first driver + image handle. + + @retval EFI_SUCCESS A bus specific override driver is returned in DriverImageHandle. + @retval EFI_NOT_FOUND The end of the list of override drivers was reached. + A bus specific override driver is not returned in DriverImageHandle. + @retval EFI_INVALID_PARAMETER DriverImageHandle is not a handle that was returned on a + previous call to GetDriver(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_GET_DRIVER)( + IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle + ); + +/// +/// This protocol matches one or more drivers to a controller. This protocol is produced by a bus driver, +/// and it is installed on the child handles of buses that require a bus specific algorithm for matching +/// drivers to controllers. +/// +struct _EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL { + EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_GET_DRIVER GetDriver; +}; + +extern EFI_GUID gEfiBusSpecificDriverOverrideProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName.h b/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName.h new file mode 100644 index 000000000..87b6d61a0 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName.h @@ -0,0 +1,131 @@ +/** @file + EFI Component Name Protocol as defined in the EFI 1.1 specification. + This protocol is used to retrieve user readable names of EFI Drivers + and controllers managed by EFI Drivers. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_COMPONENT_NAME_H__ +#define __EFI_COMPONENT_NAME_H__ + +FILE_LICENCE ( BSD3 ); + +/// +/// The global ID for the Component Name Protocol. +/// +#define EFI_COMPONENT_NAME_PROTOCOL_GUID \ + { \ + 0x107a772c, 0xd5e1, 0x11d4, {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +typedef struct _EFI_COMPONENT_NAME_PROTOCOL EFI_COMPONENT_NAME_PROTOCOL; + + +/** + Retrieves a Unicode string that is the user-readable name of the EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three-character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_DRIVER_NAME)( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language, from the point of view of the driver specified + by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/// +/// This protocol is used to retrieve user readable names of drivers +/// and controllers managed by UEFI Drivers. +/// +struct _EFI_COMPONENT_NAME_PROTOCOL { + EFI_COMPONENT_NAME_GET_DRIVER_NAME GetDriverName; + EFI_COMPONENT_NAME_GET_CONTROLLER_NAME GetControllerName; + /// + /// A Null-terminated ASCII string that contains one or more + /// ISO 639-2 language codes. This is the list of language codes + /// that this protocol supports. + /// + CHAR8 *SupportedLanguages; +}; + +extern EFI_GUID gEfiComponentNameProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/ConsoleControl/ConsoleControl.h b/roms/ipxe/src/include/ipxe/efi/Protocol/ConsoleControl/ConsoleControl.h new file mode 100644 index 000000000..0bf5799e6 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/ConsoleControl/ConsoleControl.h @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + ConsoleControl.h + +Abstract: + + Abstraction of a Text mode or GOP/UGA screen + +--*/ + +#ifndef __CONSOLE_CONTROL_H__ +#define __CONSOLE_CONTROL_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ + { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} } + +typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL; + + +typedef enum { + EfiConsoleControlScreenText, + EfiConsoleControlScreenGraphics, + EfiConsoleControlScreenMaxValue +} EFI_CONSOLE_CONTROL_SCREEN_MODE; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, + OUT BOOLEAN *GopUgaExists, OPTIONAL + OUT BOOLEAN *StdInLocked OPTIONAL + ) +/*++ + + Routine Description: + Return the current video mode information. Also returns info about existence + of Graphics Output devices or UGA Draw devices in system, and if the Std In + device is locked. All the arguments are optional and only returned if a non + NULL pointer is passed in. + + Arguments: + This - Protocol instance pointer. + Mode - Are we in text of grahics mode. + GopUgaExists - TRUE if Console Spliter has found a GOP or UGA device + StdInLocked - TRUE if StdIn device is keyboard locked + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode + ) +/*++ + + Routine Description: + Set the current mode to either text or graphics. Graphics is + for Quiet Boot. + + Arguments: + This - Protocol instance pointer. + Mode - Mode to set the + + Returns: + EFI_SUCCESS - Mode information returned. + +--*/ +; + + +typedef +EFI_STATUS +(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) ( + IN EFI_CONSOLE_CONTROL_PROTOCOL *This, + IN CHAR16 *Password + ) +/*++ + + Routine Description: + Lock Std In devices until Password is typed. + + Arguments: + This - Protocol instance pointer. + Password - Password needed to unlock screen. NULL means unlock keyboard + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_DEVICE_ERROR - Std In not locked + +--*/ +; + + + +struct _EFI_CONSOLE_CONTROL_PROTOCOL { + EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; + EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; +}; + +extern EFI_GUID gEfiConsoleControlProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h b/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h index ea5cec578..e2b4b203a 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/DebugSupport.h @@ -1,11 +1,13 @@ /** @file - DebugSupport protocol and supporting definitions as defined in the UEFI2.0 + DebugSupport protocol and supporting definitions as defined in the UEFI2.4 specification. The DebugSupport protocol is used by source level debuggers to abstract the processor and handle context save and restore operations. Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR> + This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -519,6 +521,97 @@ typedef struct { UINT32 IFAR; } EFI_SYSTEM_CONTEXT_ARM; + +/// +/// AARCH64 processor exception types. +/// +#define EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS 0 +#define EXCEPT_AARCH64_IRQ 1 +#define EXCEPT_AARCH64_FIQ 2 +#define EXCEPT_AARCH64_SERROR 3 + +/// +/// For coding convenience, define the maximum valid ARM exception. +/// +#define MAX_AARCH64_EXCEPTION EXCEPT_AARCH64_SERROR + +typedef struct { + // General Purpose Registers + UINT64 X0; + UINT64 X1; + UINT64 X2; + UINT64 X3; + UINT64 X4; + UINT64 X5; + UINT64 X6; + UINT64 X7; + UINT64 X8; + UINT64 X9; + UINT64 X10; + UINT64 X11; + UINT64 X12; + UINT64 X13; + UINT64 X14; + UINT64 X15; + UINT64 X16; + UINT64 X17; + UINT64 X18; + UINT64 X19; + UINT64 X20; + UINT64 X21; + UINT64 X22; + UINT64 X23; + UINT64 X24; + UINT64 X25; + UINT64 X26; + UINT64 X27; + UINT64 X28; + UINT64 FP; // x29 - Frame pointer + UINT64 LR; // x30 - Link Register + UINT64 SP; // x31 - Stack pointer + + // FP/SIMD Registers + UINT64 V0[2]; + UINT64 V1[2]; + UINT64 V2[2]; + UINT64 V3[2]; + UINT64 V4[2]; + UINT64 V5[2]; + UINT64 V6[2]; + UINT64 V7[2]; + UINT64 V8[2]; + UINT64 V9[2]; + UINT64 V10[2]; + UINT64 V11[2]; + UINT64 V12[2]; + UINT64 V13[2]; + UINT64 V14[2]; + UINT64 V15[2]; + UINT64 V16[2]; + UINT64 V17[2]; + UINT64 V18[2]; + UINT64 V19[2]; + UINT64 V20[2]; + UINT64 V21[2]; + UINT64 V22[2]; + UINT64 V23[2]; + UINT64 V24[2]; + UINT64 V25[2]; + UINT64 V26[2]; + UINT64 V27[2]; + UINT64 V28[2]; + UINT64 V29[2]; + UINT64 V30[2]; + UINT64 V31[2]; + + UINT64 ELR; // Exception Link Register + UINT64 SPSR; // Saved Processor Status Register + UINT64 FPSR; // Floating Point Status Register + UINT64 ESR; // Exception syndrome register + UINT64 FAR; // Fault Address Register +} EFI_SYSTEM_CONTEXT_AARCH64; + + /// /// Universal EFI_SYSTEM_CONTEXT definition. /// @@ -528,6 +621,7 @@ typedef union { EFI_SYSTEM_CONTEXT_X64 *SystemContextX64; EFI_SYSTEM_CONTEXT_IPF *SystemContextIpf; EFI_SYSTEM_CONTEXT_ARM *SystemContextArm; + EFI_SYSTEM_CONTEXT_AARCH64 *SystemContextAArch64; } EFI_SYSTEM_CONTEXT; // @@ -568,7 +662,8 @@ typedef enum { IsaX64 = IMAGE_FILE_MACHINE_X64, ///< 0x8664 IsaIpf = IMAGE_FILE_MACHINE_IA64, ///< 0x0200 IsaEbc = IMAGE_FILE_MACHINE_EBC, ///< 0x0EBC - IsaArm = IMAGE_FILE_MACHINE_ARMTHUMB_MIXED ///< 0x01c2 + IsaArm = IMAGE_FILE_MACHINE_ARMTHUMB_MIXED, ///< 0x01c2 + IsaAArch64 = IMAGE_FILE_MACHINE_ARM64 ///< 0xAA64 } EFI_INSTRUCTION_SET_ARCHITECTURE; diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h index cc4c927df..a305df575 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h @@ -5,7 +5,7 @@ from a software point of view. The path must persist from boot to boot, so it can not contain things like PCI bus numbers that change from boot to boot. -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -788,6 +788,16 @@ typedef struct { } SASEX_DEVICE_PATH; /// +/// NvmExpress Namespace Device Path SubType. +/// +#define MSG_NVME_NAMESPACE_DP 0x17 +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 NamespaceId; + UINT64 NamespaceUuid; +} NVME_NAMESPACE_DEVICE_PATH; + +/// /// iSCSI Device Path SubType /// #define MSG_ISCSI_DP 0x13 @@ -1085,6 +1095,7 @@ typedef union { UART_FLOW_CONTROL_DEVICE_PATH UartFlowControl; SAS_DEVICE_PATH Sas; SASEX_DEVICE_PATH SasEx; + NVME_NAMESPACE_DEVICE_PATH NvmeNamespace; HARDDRIVE_DEVICE_PATH HardDrive; CDROM_DEVICE_PATH CD; @@ -1134,6 +1145,7 @@ typedef union { UART_FLOW_CONTROL_DEVICE_PATH *UartFlowControl; SAS_DEVICE_PATH *Sas; SASEX_DEVICE_PATH *SasEx; + NVME_NAMESPACE_DEVICE_PATH *NvmeNamespace; HARDDRIVE_DEVICE_PATH *HardDrive; CDROM_DEVICE_PATH *CD; diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Dhcp4.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Dhcp4.h new file mode 100644 index 000000000..560ee3224 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Dhcp4.h @@ -0,0 +1,782 @@ +/** @file + EFI_DHCP4_PROTOCOL as defined in UEFI 2.0. + EFI_DHCP4_SERVICE_BINDING_PROTOCOL as defined in UEFI 2.0. + These protocols are used to collect configuration information for the EFI IPv4 Protocol + drivers and to provide DHCPv4 server and PXE boot server discovery services. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol was introduced in UEFI Specification 2.0. + +**/ + +#ifndef __EFI_DHCP4_PROTOCOL_H__ +#define __EFI_DHCP4_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_DHCP4_PROTOCOL_GUID \ + { \ + 0x8a219718, 0x4ef5, 0x4761, {0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ + } + +#define EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x9d9a39d8, 0xbd42, 0x4a73, {0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ + } + +typedef struct _EFI_DHCP4_PROTOCOL EFI_DHCP4_PROTOCOL; + + +#pragma pack(1) +typedef struct { + /// + /// DHCP option code. + /// + UINT8 OpCode; + /// + /// Length of the DHCP option data. Not present if OpCode is 0 or 255. + /// + UINT8 Length; + /// + /// Start of the DHCP option data. Not present if OpCode is 0 or 255 or if Length is zero. + /// + UINT8 Data[1]; +} EFI_DHCP4_PACKET_OPTION; +#pragma pack() + + +#pragma pack(1) +/// +/// EFI_DHCP4_PACKET defines the format of DHCPv4 packets. See RFC 2131 for more information. +/// +typedef struct { + UINT8 OpCode; + UINT8 HwType; + UINT8 HwAddrLen; + UINT8 Hops; + UINT32 Xid; + UINT16 Seconds; + UINT16 Reserved; + EFI_IPv4_ADDRESS ClientAddr; ///< Client IP address from client. + EFI_IPv4_ADDRESS YourAddr; ///< Client IP address from server. + EFI_IPv4_ADDRESS ServerAddr; ///< IP address of next server in bootstrap. + EFI_IPv4_ADDRESS GatewayAddr; ///< Relay agent IP address. + UINT8 ClientHwAddr[16]; ///< Client hardware address. + CHAR8 ServerName[64]; + CHAR8 BootFileName[128]; +}EFI_DHCP4_HEADER; +#pragma pack() + + +#pragma pack(1) +typedef struct { + /// + /// Size of the EFI_DHCP4_PACKET buffer. + /// + UINT32 Size; + /// + /// Length of the EFI_DHCP4_PACKET from the first byte of the Header field + /// to the last byte of the Option[] field. + /// + UINT32 Length; + + struct { + /// + /// DHCP packet header. + /// + EFI_DHCP4_HEADER Header; + /// + /// DHCP magik cookie in network byte order. + /// + UINT32 Magik; + /// + /// Start of the DHCP packed option data. + /// + UINT8 Option[1]; + } Dhcp4; +} EFI_DHCP4_PACKET; +#pragma pack() + + +typedef enum { + /// + /// The EFI DHCPv4 Protocol driver is stopped. + /// + Dhcp4Stopped = 0x0, + /// + /// The EFI DHCPv4 Protocol driver is inactive. + /// + Dhcp4Init = 0x1, + /// + /// The EFI DHCPv4 Protocol driver is collecting DHCP offer packets from DHCP servers. + /// + Dhcp4Selecting = 0x2, + /// + /// The EFI DHCPv4 Protocol driver has sent the request to the DHCP server and is waiting for a response. + /// + Dhcp4Requesting = 0x3, + /// + /// The DHCP configuration has completed. + /// + Dhcp4Bound = 0x4, + /// + /// The DHCP configuration is being renewed and another request has + /// been sent out, but it has not received a response from the server yet. + /// + Dhcp4Renewing = 0x5, + /// + /// The DHCP configuration has timed out and the EFI DHCPv4 + /// Protocol driver is trying to extend the lease time. + /// + Dhcp4Rebinding = 0x6, + /// + /// The EFI DHCPv4 Protocol driver was initialized with a previously + /// allocated or known IP address. + /// + Dhcp4InitReboot = 0x7, + /// + /// The EFI DHCPv4 Protocol driver is seeking to reuse the previously + /// allocated IP address by sending a request to the DHCP server. + /// + Dhcp4Rebooting = 0x8 +} EFI_DHCP4_STATE; + + +typedef enum{ + /// + /// The packet to start the configuration sequence is about to be sent. + /// + Dhcp4SendDiscover = 0x01, + /// + /// A reply packet was just received. + /// + Dhcp4RcvdOffer = 0x02, + /// + /// It is time for Dhcp4Callback to select an offer. + /// + Dhcp4SelectOffer = 0x03, + /// + /// A request packet is about to be sent. + /// + Dhcp4SendRequest = 0x04, + /// + /// A DHCPACK packet was received and will be passed to Dhcp4Callback. + /// + Dhcp4RcvdAck = 0x05, + /// + /// A DHCPNAK packet was received and will be passed to Dhcp4Callback. + /// + Dhcp4RcvdNak = 0x06, + /// + /// A decline packet is about to be sent. + /// + Dhcp4SendDecline = 0x07, + /// + /// The DHCP configuration process has completed. No packet is associated with this event. + /// + Dhcp4BoundCompleted = 0x08, + /// + /// It is time to enter the Dhcp4Renewing state and to contact the server + /// that originally issued the network address. No packet is associated with this event. + /// + Dhcp4EnterRenewing = 0x09, + /// + /// It is time to enter the Dhcp4Rebinding state and to contact any server. + /// No packet is associated with this event. + /// + Dhcp4EnterRebinding = 0x0a, + /// + /// The configured IP address was lost either because the lease has expired, + /// the user released the configuration, or a DHCPNAK packet was received in + /// the Dhcp4Renewing or Dhcp4Rebinding state. No packet is associated with this event. + /// + Dhcp4AddressLost = 0x0b, + /// + /// The DHCP process failed because a DHCPNAK packet was received or the user + /// aborted the DHCP process at a time when the configuration was not available yet. + /// No packet is associated with this event. + /// + Dhcp4Fail = 0x0c +} EFI_DHCP4_EVENT; + +/** + Callback routine. + + EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver + to intercept events that occurred in the configuration process. This structure + provides advanced control of each state transition of the DHCP process. The + returned status code determines the behavior of the EFI DHCPv4 Protocol driver. + There are three possible returned values, which are described in the following + table. + + @param This The pointer to the EFI DHCPv4 Protocol instance that is used to + configure this callback function. + @param Context The pointer to the context that is initialized by + EFI_DHCP4_PROTOCOL.Configure(). + @param CurrentState The current operational state of the EFI DHCPv4 Protocol + driver. + @param Dhcp4Event The event that occurs in the current state, which usually means a + state transition. + @param Packet The DHCP packet that is going to be sent or already received. + @param NewPacket The packet that is used to replace the above Packet. + + @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to continue the DHCP process. + When it is in the Dhcp4Selecting state, it tells the EFI DHCPv4 Protocol + driver to stop collecting additional packets. The driver will exit + the Dhcp4Selecting state and enter the Dhcp4Requesting state. + @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol + driver will continue to wait for more packets until the retry + timeout expires. + @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to abort the current process and + return to the Dhcp4Init or Dhcp4InitReboot state. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_CALLBACK)( + IN EFI_DHCP4_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP4_STATE CurrentState, + IN EFI_DHCP4_EVENT Dhcp4Event, + IN EFI_DHCP4_PACKET *Packet OPTIONAL, + OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL + ); + +typedef struct { + /// + /// The number of times to try sending a packet during the Dhcp4SendDiscover + /// event and waiting for a response during the Dhcp4RcvdOffer event. + /// Set to zero to use the default try counts and timeout values. + /// + UINT32 DiscoverTryCount; + /// + /// The maximum amount of time (in seconds) to wait for returned packets in each + /// of the retries. Timeout values of zero will default to a timeout value + /// of one second. Set to NULL to use default timeout values. + /// + UINT32 *DiscoverTimeout; + /// + /// The number of times to try sending a packet during the Dhcp4SendRequest event + /// and waiting for a response during the Dhcp4RcvdAck event before accepting + /// failure. Set to zero to use the default try counts and timeout values. + /// + UINT32 RequestTryCount; + /// + /// The maximum amount of time (in seconds) to wait for return packets in each of the retries. + /// Timeout values of zero will default to a timeout value of one second. + /// Set to NULL to use default timeout values. + /// + UINT32 *RequestTimeout; + /// + /// For a DHCPDISCOVER, setting this parameter to the previously allocated IP + /// address will cause the EFI DHCPv4 Protocol driver to enter the Dhcp4InitReboot state. + /// And set this field to 0.0.0.0 to enter the Dhcp4Init state. + /// For a DHCPINFORM this parameter should be set to the client network address + /// which was assigned to the client during a DHCPDISCOVER. + /// + EFI_IPv4_ADDRESS ClientAddress; + /// + /// The callback function to intercept various events that occurred in + /// the DHCP configuration process. Set to NULL to ignore all those events. + /// + EFI_DHCP4_CALLBACK Dhcp4Callback; + /// + /// The pointer to the context that will be passed to Dhcp4Callback when it is called. + /// + VOID *CallbackContext; + /// + /// Number of DHCP options in the OptionList. + /// + UINT32 OptionCount; + /// + /// List of DHCP options to be included in every packet that is sent during the + /// Dhcp4SendDiscover event. Pad options are appended automatically by DHCP driver + /// in outgoing DHCP packets. If OptionList itself contains pad option, they are + /// ignored by the driver. OptionList can be freed after EFI_DHCP4_PROTOCOL.Configure() + /// returns. Ignored if OptionCount is zero. + /// + EFI_DHCP4_PACKET_OPTION **OptionList; +} EFI_DHCP4_CONFIG_DATA; + + +typedef struct { + /// + /// The EFI DHCPv4 Protocol driver operating state. + /// + EFI_DHCP4_STATE State; + /// + /// The configuration data of the current EFI DHCPv4 Protocol driver instance. + /// + EFI_DHCP4_CONFIG_DATA ConfigData; + /// + /// The client IP address that was acquired from the DHCP server. If it is zero, + /// the DHCP acquisition has not completed yet and the following fields in this structure are undefined. + /// + EFI_IPv4_ADDRESS ClientAddress; + /// + /// The local hardware address. + /// + EFI_MAC_ADDRESS ClientMacAddress; + /// + /// The server IP address that is providing the DHCP service to this client. + /// + EFI_IPv4_ADDRESS ServerAddress; + /// + /// The router IP address that was acquired from the DHCP server. + /// May be zero if the server does not offer this address. + /// + EFI_IPv4_ADDRESS RouterAddress; + /// + /// The subnet mask of the connected network that was acquired from the DHCP server. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// The lease time (in 1-second units) of the configured IP address. + /// The value 0xFFFFFFFF means that the lease time is infinite. + /// A default lease of 7 days is used if the DHCP server does not provide a value. + /// + UINT32 LeaseTime; + /// + /// The cached latest DHCPACK or DHCPNAK or BOOTP REPLY packet. May be NULL if no packet is cached. + /// + EFI_DHCP4_PACKET *ReplyPacket; +} EFI_DHCP4_MODE_DATA; + + +typedef struct { + /// + /// Alternate listening address. It can be a unicast, multicast, or broadcast address. + /// + EFI_IPv4_ADDRESS ListenAddress; + /// + /// The subnet mask of above listening unicast/broadcast IP address. + /// Ignored if ListenAddress is a multicast address. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Alternate station source (or listening) port number. + /// If zero, then the default station port number (68) will be used. + /// + UINT16 ListenPort; +} EFI_DHCP4_LISTEN_POINT; + + +typedef struct { + /// + /// The completion status of transmitting and receiving. + /// + EFI_STATUS Status; + /// + /// If not NULL, the event that will be signaled when the collection process + /// completes. If NULL, this function will busy-wait until the collection process competes. + /// + EFI_EVENT CompletionEvent; + /// + /// The pointer to the server IP address. This address may be a unicast, multicast, or broadcast address. + /// + EFI_IPv4_ADDRESS RemoteAddress; + /// + /// The server listening port number. If zero, the default server listening port number (67) will be used. + /// + UINT16 RemotePort; + /// + /// The pointer to the gateway address to override the existing setting. + /// + EFI_IPv4_ADDRESS GatewayAddress; + /// + /// The number of entries in ListenPoints. If zero, the default station address and port number 68 are used. + /// + UINT32 ListenPointCount; + /// + /// An array of station address and port number pairs that are used as receiving filters. + /// The first entry is also used as the source address and source port of the outgoing packet. + /// + EFI_DHCP4_LISTEN_POINT *ListenPoints; + /// + /// The number of seconds to collect responses. Zero is invalid. + /// + UINT32 TimeoutValue; + /// + /// The pointer to the packet to be transmitted. + /// + EFI_DHCP4_PACKET *Packet; + /// + /// Number of received packets. + /// + UINT32 ResponseCount; + /// + /// The pointer to the allocated list of received packets. + /// + EFI_DHCP4_PACKET *ResponseList; +} EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN; + + +/** + Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver. + + The GetModeData() function returns the current operating mode and cached data + packet for the EFI DHCPv4 Protocol driver. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param Dhcp4ModeData The pointer to storage for the EFI_DHCP4_MODE_DATA structure. + + @retval EFI_SUCCESS The mode data was returned. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_GET_MODE_DATA)( + IN EFI_DHCP4_PROTOCOL *This, + OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData + ); + +/** + Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver. + + The Configure() function is used to initialize, change, or reset the operational + settings of the EFI DHCPv4 Protocol driver for the communication device on which + the EFI DHCPv4 Service Binding Protocol is installed. This function can be + successfully called only if both of the following are true: + * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init, + Dhcp4InitReboot, or Dhcp4Bound states. + * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI + DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4 + Protocol driver. + When this driver is in the Dhcp4Stopped state, it can transfer into one of the + following two possible initial states: + * Dhcp4Init + * Dhcp4InitReboot. + The driver can transfer into these states by calling Configure() with a non-NULL + Dhcp4CfgData. The driver will transfer into the appropriate state based on the + supplied client network address in the ClientAddress parameter and DHCP options + in the OptionList parameter as described in RFC 2131. + When Configure() is called successfully while Dhcp4CfgData is set to NULL, the + default configuring data will be reset in the EFI DHCPv4 Protocol driver and + the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance + wants to make it possible for another instance to configure the EFI DHCPv4 Protocol + driver, it must call this function with Dhcp4CfgData set to NULL. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param Dhcp4CfgData The pointer to the EFI_DHCP4_CONFIG_DATA. + + @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or + Dhcp4InitReboot state, if the original state of this driver + was Dhcp4Stopped, Dhcp4Init,Dhcp4InitReboot, or Dhcp4Bound + and the value of Dhcp4CfgData was not NULL. + Otherwise, the state was left unchanged. + @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the + Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state; + Or onother instance of this EFI DHCPv4 Protocol driver is already + in a valid configured state. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + This is NULL. + DiscoverTryCount > 0 and DiscoverTimeout is NULL + RequestTryCount > 0 and RequestTimeout is NULL. + OptionCount >0 and OptionList is NULL. + ClientAddress is not a valid unicast address. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_CONFIGURE)( + IN EFI_DHCP4_PROTOCOL *This, + IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL + ); + + +/** + Starts the DHCP configuration process. + + The Start() function starts the DHCP configuration process. This function can + be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or + Dhcp4InitReboot state. + If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol + driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the + Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL. + If the process aborts, either by the user or by some unexpected network error, + the state is restored to the Dhcp4Init state. The Start() function can be called + again to restart the process. + Refer to RFC 2131 for precise state transitions during this process. At the + time when each event occurs in this process, the callback function that was set + by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this + opportunity to control the process. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param CompletionEvent If not NULL, it indicates the event that will be signaled when the + EFI DHCPv4 Protocol driver is transferred into the + Dhcp4Bound state or when the DHCP process is aborted. + EFI_DHCP4_PROTOCOL.GetModeData() can be called to + check the completion status. If NULL, + EFI_DHCP4_PROTOCOL.Start() will wait until the driver + is transferred into the Dhcp4Bound state or the process fails. + + @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed + when CompletionEvent is NULL. + @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped + state. EFI_DHCP4_PROTOCOL. Configure() needs to be called. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_TIMEOUT The DHCP configuration process failed because no response was + received from the server within the specified timeout value. + @retval EFI_ABORTED The user aborted the DHCP process. + @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the + DHCP process. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NO_MEDIA There was a media error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_START)( + IN EFI_DHCP4_PROTOCOL *This, + IN EFI_EVENT CompletionEvent OPTIONAL + ); + +/** + Extends the lease time by sending a request packet. + + The RenewRebind() function is used to manually extend the lease time when the + EFI DHCPv4 Protocol driver is in the Dhcp4Bound state, and the lease time has + not expired yet. This function will send a request packet to the previously + found server (or to any server when RebindRequest is TRUE) and transfer the + state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is + TRUE). When a response is received, the state is returned to Dhcp4Bound. + If no response is received before the try count is exceeded (the RequestTryCount + field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that + was issued by the previous server expires, the driver will return to the Dhcp4Bound + state, and the previous configuration is restored. The outgoing and incoming packets + can be captured by the EFI_DHCP4_CALLBACK function. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param RebindRequest If TRUE, this function broadcasts the request packets and enters + the Dhcp4Rebinding state. Otherwise, it sends a unicast + request packet and enters the Dhcp4Renewing state. + @param CompletionEvent If not NULL, this event is signaled when the renew/rebind phase + completes or some error occurs. + EFI_DHCP4_PROTOCOL.GetModeData() can be called to + check the completion status. If NULL, + EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait + until the DHCP process finishes. + + @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the + Dhcp4Renewing state or is back to the Dhcp4Bound state. + @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped + state. EFI_DHCP4_PROTOCOL.Configure() needs to + be called. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_TIMEOUT There was no response from the server when the try count was + exceeded. + @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_RENEW_REBIND)( + IN EFI_DHCP4_PROTOCOL *This, + IN BOOLEAN RebindRequest, + IN EFI_EVENT CompletionEvent OPTIONAL + ); + +/** + Releases the current address configuration. + + The Release() function releases the current configured IP address by doing either + of the following: + * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the + Dhcp4Bound state + * Setting the previously assigned IP address that was provided with the + EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in + Dhcp4InitReboot state + After a successful call to this function, the EFI DHCPv4 Protocol driver returns + to the Dhcp4Init state, and any subsequent incoming packets will be discarded silently. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + + @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_RELEASE)( + IN EFI_DHCP4_PROTOCOL *This + ); + +/** + Stops the current address configuration. + + The Stop() function is used to stop the DHCP configuration process. After this + function is called successfully, the EFI DHCPv4 Protocol driver is transferred + into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called + before DHCP configuration process can be started again. This function can be + called when the EFI DHCPv4 Protocol driver is in any state. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + + @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_STOP)( + IN EFI_DHCP4_PROTOCOL *This + ); + +/** + Builds a DHCP packet, given the options to be appended or deleted or replaced. + + The Build() function is used to assemble a new packet from the original packet + by replacing or deleting existing options or appending new options. This function + does not change any state of the EFI DHCPv4 Protocol driver and can be used at + any time. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param SeedPacket Initial packet to be used as a base for building new packet. + @param DeleteCount Number of opcodes in the DeleteList. + @param DeleteList List of opcodes to be deleted from the seed packet. + Ignored if DeleteCount is zero. + @param AppendCount Number of entries in the OptionList. + @param AppendList The pointer to a DHCP option list to be appended to SeedPacket. + If SeedPacket also contains options in this list, they are + replaced by new options (except pad option). Ignored if + AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION + @param NewPacket The pointer to storage for the pointer to the new allocated packet. + Use the EFI Boot Service FreePool() on the resulting pointer + when done with the packet. + + @retval EFI_SUCCESS The new packet was built. + @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + SeedPacket is NULL. + SeedPacket is not a well-formed DHCP packet. + AppendCount is not zero and AppendList is NULL. + DeleteCount is not zero and DeleteList is NULL. + NewPacket is NULL + Both DeleteCount and AppendCount are zero and + NewPacket is not NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_BUILD)( + IN EFI_DHCP4_PROTOCOL *This, + IN EFI_DHCP4_PACKET *SeedPacket, + IN UINT32 DeleteCount, + IN UINT8 *DeleteList OPTIONAL, + IN UINT32 AppendCount, + IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL, + OUT EFI_DHCP4_PACKET **NewPacket + ); + + +/** + Transmits a DHCP formatted packet and optionally waits for responses. + + The TransmitReceive() function is used to transmit a DHCP packet and optionally + wait for the response from servers. This function does not change the state of + the EFI DHCPv4 Protocol driver. It can be used at any time because of this. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param Token The pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure. + + @retval EFI_SUCCESS The packet was successfully queued for transmission. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token.RemoteAddress is zero. + Token.Packet is NULL. + Token.Packet is not a well-formed DHCP packet. + The transaction ID in Token.Packet is in use by another DHCP process. + @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call + this function after collection process completes. + @retval EFI_NO_MAPPING The default station address is not available yet. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_UNSUPPORTED The implementation doesn't support this function + @retval Others Some other unexpected error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_TRANSMIT_RECEIVE)( + IN EFI_DHCP4_PROTOCOL *This, + IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token + ); + + +/** + Parses the packed DHCP option data. + + The Parse() function is used to retrieve the option list from a DHCP packet. + If *OptionCount isn't zero, and there is enough space for all the DHCP options + in the Packet, each element of PacketOptionList is set to point to somewhere in + the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported, + the caller should reassemble the parsed DHCP options to get the final result. + If *OptionCount is zero or there isn't enough space for all of them, the number + of DHCP options in the Packet is returned in OptionCount. + + @param This The pointer to the EFI_DHCP4_PROTOCOL instance. + @param Packet The pointer to packet to be parsed. + @param OptionCount On input, the number of entries in the PacketOptionList. + On output, the number of entries that were written into the + PacketOptionList. + @param PacketOptionList A list of packet option entries to be filled in. End option or pad + options are not included. + + @retval EFI_SUCCESS The packet was successfully parsed. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + The packet is NULL. + The packet is not a well-formed DHCP packet. + OptionCount is NULL. + @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE: + 1) *OptionCount is smaller than the number of options that + were found in the Packet. + 2) PacketOptionList is NULL. + @retval EFI_OUT_OF_RESOURCE The packet failed to parse because of a resource shortage. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP4_PARSE)( + IN EFI_DHCP4_PROTOCOL *This, + IN EFI_DHCP4_PACKET *Packet, + IN OUT UINT32 *OptionCount, + OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL + ); + +/// +/// This protocol is used to collect configuration information for the EFI IPv4 Protocol drivers +/// and to provide DHCPv4 server and PXE boot server discovery services. +/// +struct _EFI_DHCP4_PROTOCOL { + EFI_DHCP4_GET_MODE_DATA GetModeData; + EFI_DHCP4_CONFIGURE Configure; + EFI_DHCP4_START Start; + EFI_DHCP4_RENEW_REBIND RenewRebind; + EFI_DHCP4_RELEASE Release; + EFI_DHCP4_STOP Stop; + EFI_DHCP4_BUILD Build; + EFI_DHCP4_TRANSMIT_RECEIVE TransmitReceive; + EFI_DHCP4_PARSE Parse; +}; + +extern EFI_GUID gEfiDhcp4ProtocolGuid; +extern EFI_GUID gEfiDhcp4ServiceBindingProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/DiskIo.h b/roms/ipxe/src/include/ipxe/efi/Protocol/DiskIo.h new file mode 100644 index 000000000..1b47ce520 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/DiskIo.h @@ -0,0 +1,119 @@ +/** @file + Disk IO protocol as defined in the UEFI 2.0 specification. + + The Disk IO protocol is used to convert block oriented devices into byte + oriented devices. The Disk IO protocol is intended to layer on top of the + Block IO protocol. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DISK_IO_H__ +#define __DISK_IO_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_DISK_IO_PROTOCOL_GUID \ + { \ + 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +/// +/// Protocol GUID name defined in EFI1.1. +/// +#define DISK_IO_PROTOCOL EFI_DISK_IO_PROTOCOL_GUID + +typedef struct _EFI_DISK_IO_PROTOCOL EFI_DISK_IO_PROTOCOL; + +/// +/// Protocol defined in EFI1.1. +/// +typedef EFI_DISK_IO_PROTOCOL EFI_DISK_IO; + +/** + Read BufferSize bytes from Offset into Buffer. + + @param This Protocol instance pointer. + @param MediaId Id of the media, changes every time the media is replaced. + @param Offset The starting byte offset to read from + @param BufferSize Size of Buffer + @param Buffer Buffer containing read data + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while performing the read. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not + valid for the device. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_READ)( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Writes a specified number of bytes to a device. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to be written. + @param Offset The starting byte offset on the logical block I/O device to write. + @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device. + @param Buffer A pointer to the buffer containing the data to be written. + + @retval EFI_SUCCESS The data was written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing the write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not + valid for the device. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DISK_WRITE)( + IN EFI_DISK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +#define EFI_DISK_IO_PROTOCOL_REVISION 0x00010000 + +/// +/// Revision defined in EFI1.1 +/// +#define EFI_DISK_IO_INTERFACE_REVISION EFI_DISK_IO_PROTOCOL_REVISION + +/// +/// This protocol is used to abstract Block I/O interfaces. +/// +struct _EFI_DISK_IO_PROTOCOL { + /// + /// The revision to which the disk I/O interface adheres. All future + /// revisions must be backwards compatible. If a future version is not + /// backwards compatible, it is not the same GUID. + /// + UINT64 Revision; + EFI_DISK_READ ReadDisk; + EFI_DISK_WRITE WriteDisk; +}; + +extern EFI_GUID gEfiDiskIoProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h b/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h index 12873c31f..0c0f56d73 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h @@ -4,7 +4,7 @@ The EFI_FORM_BROWSER2_PROTOCOL is the interface to call for drivers to leverage the EFI configuration driver interface. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -84,7 +84,7 @@ typedef UINTN EFI_BROWSER_ACTION_REQUEST; @param FormSetGuid This field points to the EFI_GUID which must match the Guid field or one of the elements of the ClassId field in the EFI_IFR_FORM_SET op-code. If - FormsetGuid is NULL, then this function will display the the form set class + FormsetGuid is NULL, then this function will display the form set class EFI_HII_PLATFORM_SETUP_FORMSET_GUID. @param FormId This field specifies the identifier of the form within the form set to render as the first diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/GraphicsOutput.h b/roms/ipxe/src/include/ipxe/efi/Protocol/GraphicsOutput.h new file mode 100644 index 000000000..98ca8c9c0 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/GraphicsOutput.h @@ -0,0 +1,278 @@ +/** @file + Graphics Output Protocol from the UEFI 2.0 specification. + + Abstraction of a very simple graphics device. + + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __GRAPHICS_OUTPUT_H__ +#define __GRAPHICS_OUTPUT_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + { \ + 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \ + } + +typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL; + +typedef struct { + UINT32 RedMask; + UINT32 GreenMask; + UINT32 BlueMask; + UINT32 ReservedMask; +} EFI_PIXEL_BITMASK; + +typedef enum { + /// + /// A pixel is 32-bits and byte zero represents red, byte one represents green, + /// byte two represents blue, and byte three is reserved. This is the definition + /// for the physical frame buffer. The byte values for the red, green, and blue + /// components represent the color intensity. This color intensity value range + /// from a minimum intensity of 0 to maximum intensity of 255. + /// + PixelRedGreenBlueReserved8BitPerColor, + /// + /// A pixel is 32-bits and byte zero represents blue, byte one represents green, + /// byte two represents red, and byte three is reserved. This is the definition + /// for the physical frame buffer. The byte values for the red, green, and blue + /// components represent the color intensity. This color intensity value range + /// from a minimum intensity of 0 to maximum intensity of 255. + /// + PixelBlueGreenRedReserved8BitPerColor, + /// + /// The Pixel definition of the physical frame buffer. + /// + PixelBitMask, + /// + /// This mode does not support a physical frame buffer. + /// + PixelBltOnly, + /// + /// Valid EFI_GRAPHICS_PIXEL_FORMAT enum values are less than this value. + /// + PixelFormatMax +} EFI_GRAPHICS_PIXEL_FORMAT; + +typedef struct { + /// + /// The version of this data structure. A value of zero represents the + /// EFI_GRAPHICS_OUTPUT_MODE_INFORMATION structure as defined in this specification. + /// + UINT32 Version; + /// + /// The size of video screen in pixels in the X dimension. + /// + UINT32 HorizontalResolution; + /// + /// The size of video screen in pixels in the Y dimension. + /// + UINT32 VerticalResolution; + /// + /// Enumeration that defines the physical format of the pixel. A value of PixelBltOnly + /// implies that a linear frame buffer is not available for this mode. + /// + EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; + /// + /// This bit-mask is only valid if PixelFormat is set to PixelPixelBitMask. + /// A bit being set defines what bits are used for what purpose such as Red, Green, Blue, or Reserved. + /// + EFI_PIXEL_BITMASK PixelInformation; + /// + /// Defines the number of pixel elements per video memory line. + /// + UINT32 PixelsPerScanLine; +} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; + +/** + Returns information for an available graphics mode that the graphics device + and the set of active video output devices supports. + + @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance. + @param ModeNumber The mode number to return information on. + @param SizeOfInfo A pointer to the size, in bytes, of the Info buffer. + @param Info A pointer to callee allocated buffer that returns information about ModeNumber. + + @retval EFI_SUCCESS Valid mode information was returned. + @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the video mode. + @retval EFI_INVALID_PARAMETER ModeNumber is not valid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE)( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ); + +/** + Set the video device into the specified mode and clears the visible portions of + the output display to black. + + @param This The EFI_GRAPHICS_OUTPUT_PROTOCOL instance. + @param ModeNumber Abstraction that defines the current video mode. + + @retval EFI_SUCCESS The graphics mode specified by ModeNumber was selected. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + @retval EFI_UNSUPPORTED ModeNumber is not supported by this device. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE)( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber + ); + +typedef struct { + UINT8 Blue; + UINT8 Green; + UINT8 Red; + UINT8 Reserved; +} EFI_GRAPHICS_OUTPUT_BLT_PIXEL; + +typedef union { + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Pixel; + UINT32 Raw; +} EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION; + +/// +/// actions for BltOperations +/// +typedef enum { + /// + /// Write data from the BltBuffer pixel (0, 0) + /// directly to every pixel of the video display rectangle + /// (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + /// Only one pixel will be used from the BltBuffer. Delta is NOT used. + /// + EfiBltVideoFill, + + /// + /// Read data from the video display rectangle + /// (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in + /// the BltBuffer rectangle (DestinationX, DestinationY ) + /// (DestinationX + Width, DestinationY + Height). If DestinationX or + /// DestinationY is not zero then Delta must be set to the length in bytes + /// of a row in the BltBuffer. + /// + EfiBltVideoToBltBuffer, + + /// + /// Write data from the BltBuffer rectangle + /// (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the + /// video display rectangle (DestinationX, DestinationY) + /// (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is + /// not zero then Delta must be set to the length in bytes of a row in the + /// BltBuffer. + /// + EfiBltBufferToVideo, + + /// + /// Copy from the video display rectangle (SourceX, SourceY) + /// (SourceX + Width, SourceY + Height) to the video display rectangle + /// (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height). + /// The BltBuffer and Delta are not used in this mode. + /// + EfiBltVideoToVideo, + + EfiGraphicsOutputBltOperationMax +} EFI_GRAPHICS_OUTPUT_BLT_OPERATION; + +/** + Blt a rectangle of pixels on the graphics screen. Blt stands for BLock Transfer. + + @param This Protocol instance pointer. + @param BltBuffer The data to transfer to the graphics screen. + Size is at least Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL). + @param BltOperation The operation to perform when copying BltBuffer on to the graphics screen. + @param SourceX The X coordinate of source for the BltOperation. + @param SourceY The Y coordinate of source for the BltOperation. + @param DestinationX The X coordinate of destination for the BltOperation. + @param DestinationY The Y coordinate of destination for the BltOperation. + @param Width The width of a rectangle in the blt rectangle in pixels. + @param Height The height of a rectangle in the blt rectangle in pixels. + @param Delta Not used for EfiBltVideoFill or the EfiBltVideoToVideo operation. + If a Delta of zero is used, the entire BltBuffer is being operated on. + If a subrectangle of the BltBuffer is being used then Delta + represents the number of bytes in a row of the BltBuffer. + + @retval EFI_SUCCESS BltBuffer was drawn to the graphics screen. + @retval EFI_INVALID_PARAMETER BltOperation is not valid. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the request. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT)( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta OPTIONAL + ); + +typedef struct { + /// + /// The number of modes supported by QueryMode() and SetMode(). + /// + UINT32 MaxMode; + /// + /// Current Mode of the graphics device. Valid mode numbers are 0 to MaxMode -1. + /// + UINT32 Mode; + /// + /// Pointer to read-only EFI_GRAPHICS_OUTPUT_MODE_INFORMATION data. + /// + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + /// + /// Size of Info structure in bytes. + /// + UINTN SizeOfInfo; + /// + /// Base address of graphics linear frame buffer. + /// Offset zero in FrameBufferBase represents the upper left pixel of the display. + /// + EFI_PHYSICAL_ADDRESS FrameBufferBase; + /// + /// Amount of frame buffer needed to support the active mode as defined by + /// PixelsPerScanLine xVerticalResolution x PixelElementSize. + /// + UINTN FrameBufferSize; +} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; + +/// +/// Provides a basic abstraction to set video modes and copy pixels to and from +/// the graphics controller's frame buffer. The linear address of the hardware +/// frame buffer is also exposed so software can write directly to the video hardware. +/// +struct _EFI_GRAPHICS_OUTPUT_PROTOCOL { + EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; + /// + /// Pointer to EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE data. + /// + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; +}; + +extern EFI_GUID gEfiGraphicsOutputProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h b/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h index 929d9cd28..17ce3fdcc 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h @@ -5,7 +5,7 @@ This protocol is published by drivers providing and requesting configuration data from HII. It may only be invoked by HII. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -96,13 +96,10 @@ typedef UINTN EFI_BROWSER_ACTION; stored awaiting possible future protocols. - @retval EFI_NOT_FOUND Routing data doesn't match any - known driver. Progress set to the - first character in the routing header. - Note: There is no requirement that the - driver validate the routing data. It - must skip the <ConfigHdr> in order to - process the names. + @retval EFI_NOT_FOUND A configuration element matching + the routing data is not found. + Progress set to the first character + in the routing header. @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent "&" before the diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h b/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h index 411ca2c03..cbc0108b0 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/HiiDatabase.h @@ -225,7 +225,9 @@ EFI_STATUS updated with a value that will enable the data to fit. @retval EFI_NOT_FOUND No matching handle could be found in database. - @retval EFI_INVALID_PARAMETER Handle or HandleBufferLength was NULL. + @retval EFI_INVALID_PARAMETER HandleBufferLength was NULL. + @retval EFI_INVALID_PARAMETER The value referenced by HandleBufferLength was not + zero and Handle was NULL. @retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but PackageGuid is not NULL, PackageType is a EFI_HII_ PACKAGE_TYPE_GUID but PackageGuid is NULL. @@ -273,6 +275,13 @@ EFI_STATUS @retval EFI_OUT_OF_RESOURCES BufferSize is too small to hold the package. + @retval EFI_NOT_FOUND The specifiecd Handle could not be found in the + current database. + + @retval EFI_INVALID_PARAMETER BufferSize was NULL. + + @retval EFI_INVALID_PARAMETER The value referenced by BufferSize was not zero + and Buffer was NULL. **/ typedef EFI_STATUS @@ -395,6 +404,11 @@ EFI_STATUS KeyGuidBufferLength is updated with a value that will enable the data to fit. + @retval EFI_INVALID_PARAMETER The KeyGuidBufferLength is NULL. + @retval EFI_INVALID_PARAMETER The value referenced by + KeyGuidBufferLength is not + zero and KeyGuidBuffer is NULL. + @retval EFI_NOT_FOUND There was no keyboard layout. **/ typedef diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Ip4.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Ip4.h new file mode 100644 index 000000000..f174c0cfb --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Ip4.h @@ -0,0 +1,614 @@ +/** @file + This file defines the EFI IPv4 (Internet Protocol version 4) + Protocol interface. It is split into the following three main + sections: + - EFI IPv4 Service Binding Protocol + - EFI IPv4 Variable (deprecated in UEFI 2.4B) + - EFI IPv4 Protocol. + The EFI IPv4 Protocol provides basic network IPv4 packet I/O services, + which includes support foR a subset of the Internet Control Message + Protocol (ICMP) and may include support for the Internet Group Management + Protocol (IGMP). + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.0. + +**/ + +#ifndef __EFI_IP4_PROTOCOL_H__ +#define __EFI_IP4_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/Protocol/ManagedNetwork.h> + +#define EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xc51711e7, 0xb4bf, 0x404a, {0xbf, 0xb8, 0x0a, 0x04, 0x8e, 0xf1, 0xff, 0xe4 } \ + } + +#define EFI_IP4_PROTOCOL_GUID \ + { \ + 0x41d94cd2, 0x35b6, 0x455a, {0x82, 0x58, 0xd4, 0xe5, 0x13, 0x34, 0xaa, 0xdd } \ + } + +typedef struct _EFI_IP4_PROTOCOL EFI_IP4_PROTOCOL; + +/// +/// EFI_IP4_ADDRESS_PAIR is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE InstanceHandle; + EFI_IPv4_ADDRESS Ip4Address; + EFI_IPv4_ADDRESS SubnetMask; +} EFI_IP4_ADDRESS_PAIR; + +/// +/// EFI_IP4_VARIABLE_DATA is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE DriverHandle; + UINT32 AddressCount; + EFI_IP4_ADDRESS_PAIR AddressPairs[1]; +} EFI_IP4_VARIABLE_DATA; + +typedef struct { + /// + /// The default IPv4 protocol packets to send and receive. Ignored + /// when AcceptPromiscuous is TRUE. + /// + UINT8 DefaultProtocol; + /// + /// Set to TRUE to receive all IPv4 packets that get through the receive filters. + /// Set to FALSE to receive only the DefaultProtocol IPv4 + /// packets that get through the receive filters. + /// + BOOLEAN AcceptAnyProtocol; + /// + /// Set to TRUE to receive ICMP error report packets. Ignored when + /// AcceptPromiscuous or AcceptAnyProtocol is TRUE. + /// + BOOLEAN AcceptIcmpErrors; + /// + /// Set to TRUE to receive broadcast IPv4 packets. Ignored when + /// AcceptPromiscuous is TRUE. + /// Set to FALSE to stop receiving broadcast IPv4 packets. + /// + BOOLEAN AcceptBroadcast; + /// + /// Set to TRUE to receive all IPv4 packets that are sent to any + /// hardware address or any protocol address. + /// Set to FALSE to stop receiving all promiscuous IPv4 packets + /// + BOOLEAN AcceptPromiscuous; + /// + /// Set to TRUE to use the default IPv4 address and default routing table. + /// + BOOLEAN UseDefaultAddress; + /// + /// The station IPv4 address that will be assigned to this EFI IPv4Protocol instance. + /// + EFI_IPv4_ADDRESS StationAddress; + /// + /// The subnet address mask that is associated with the station address. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// TypeOfService field in transmitted IPv4 packets. + /// + UINT8 TypeOfService; + /// + /// TimeToLive field in transmitted IPv4 packets. + /// + UINT8 TimeToLive; + /// + /// State of the DoNotFragment bit in transmitted IPv4 packets. + /// + BOOLEAN DoNotFragment; + /// + /// Set to TRUE to send and receive unformatted packets. The other + /// IPv4 receive filters are still applied. Fragmentation is disabled for RawData mode. + /// + BOOLEAN RawData; + /// + /// The timer timeout value (number of microseconds) for the + /// receive timeout event to be associated with each assembled + /// packet. Zero means do not drop assembled packets. + /// + UINT32 ReceiveTimeout; + /// + /// The timer timeout value (number of microseconds) for the + /// transmit timeout event to be associated with each outgoing + /// packet. Zero means do not drop outgoing packets. + /// + UINT32 TransmitTimeout; +} EFI_IP4_CONFIG_DATA; + + +typedef struct { + EFI_IPv4_ADDRESS SubnetAddress; + EFI_IPv4_ADDRESS SubnetMask; + EFI_IPv4_ADDRESS GatewayAddress; +} EFI_IP4_ROUTE_TABLE; + +typedef struct { + UINT8 Type; + UINT8 Code; +} EFI_IP4_ICMP_TYPE; + +typedef struct { + /// + /// Set to TRUE after this EFI IPv4 Protocol instance has been successfully configured. + /// + BOOLEAN IsStarted; + /// + /// The maximum packet size, in bytes, of the packet which the upper layer driver could feed. + /// + UINT32 MaxPacketSize; + /// + /// Current configuration settings. + /// + EFI_IP4_CONFIG_DATA ConfigData; + /// + /// Set to TRUE when the EFI IPv4 Protocol instance has a station address and subnet mask. + /// + BOOLEAN IsConfigured; + /// + /// Number of joined multicast groups. + /// + UINT32 GroupCount; + /// + /// List of joined multicast group addresses. + /// + EFI_IPv4_ADDRESS *GroupTable; + /// + /// Number of entries in the routing table. + /// + UINT32 RouteCount; + /// + /// Routing table entries. + /// + EFI_IP4_ROUTE_TABLE *RouteTable; + /// + /// Number of entries in the supported ICMP types list. + /// + UINT32 IcmpTypeCount; + /// + /// Array of ICMP types and codes that are supported by this EFI IPv4 Protocol driver + /// + EFI_IP4_ICMP_TYPE *IcmpTypeList; +} EFI_IP4_MODE_DATA; + +#pragma pack(1) + +typedef struct { + UINT8 HeaderLength:4; + UINT8 Version:4; + UINT8 TypeOfService; + UINT16 TotalLength; + UINT16 Identification; + UINT16 Fragmentation; + UINT8 TimeToLive; + UINT8 Protocol; + UINT16 Checksum; + EFI_IPv4_ADDRESS SourceAddress; + EFI_IPv4_ADDRESS DestinationAddress; +} EFI_IP4_HEADER; +#pragma pack() + + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_IP4_FRAGMENT_DATA; + + +typedef struct { + EFI_TIME TimeStamp; + EFI_EVENT RecycleSignal; + UINT32 HeaderLength; + EFI_IP4_HEADER *Header; + UINT32 OptionsLength; + VOID *Options; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_IP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP4_RECEIVE_DATA; + + +typedef struct { + EFI_IPv4_ADDRESS SourceAddress; + EFI_IPv4_ADDRESS GatewayAddress; + UINT8 Protocol; + UINT8 TypeOfService; + UINT8 TimeToLive; + BOOLEAN DoNotFragment; +} EFI_IP4_OVERRIDE_DATA; + +typedef struct { + EFI_IPv4_ADDRESS DestinationAddress; + EFI_IP4_OVERRIDE_DATA *OverrideData; //OPTIONAL + UINT32 OptionsLength; //OPTIONAL + VOID *OptionsBuffer; //OPTIONAL + UINT32 TotalDataLength; + UINT32 FragmentCount; + EFI_IP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP4_TRANSMIT_DATA; + +typedef struct { + /// + /// This Event will be signaled after the Status field is updated + /// by the EFI IPv4 Protocol driver. The type of Event must be + /// EFI_NOTIFY_SIGNAL. The Task Priority Level (TPL) of + /// Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// The status that is returned to the caller at the end of the operation + /// to indicate whether this operation completed successfully. + /// + EFI_STATUS Status; + union { + /// + /// When this token is used for receiving, RxData is a pointer to the EFI_IP4_RECEIVE_DATA. + /// + EFI_IP4_RECEIVE_DATA *RxData; + /// + /// When this token is used for transmitting, TxData is a pointer to the EFI_IP4_TRANSMIT_DATA. + /// + EFI_IP4_TRANSMIT_DATA *TxData; + } Packet; +} EFI_IP4_COMPLETION_TOKEN; + +/** + Gets the current operational settings for this instance of the EFI IPv4 Protocol driver. + + The GetModeData() function returns the current operational mode data for this + driver instance. The data fields in EFI_IP4_MODE_DATA are read only. This + function is used optionally to retrieve the operational mode data of underlying + networks or drivers. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param Ip4ModeData The pointer to the EFI IPv4 Protocol mode data structure. + @param MnpConfigData The pointer to the managed network configuration data structure. + @param SnpModeData The pointer to the simple network mode data structure. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_GET_MODE_DATA)( + IN CONST EFI_IP4_PROTOCOL *This, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Assigns an IPv4 address and subnet mask to this EFI IPv4 Protocol driver instance. + + The Configure() function is used to set, change, or reset the operational + parameters and filter settings for this EFI IPv4 Protocol instance. Until these + parameters have been set, no network traffic can be sent or received by this + instance. Once the parameters have been reset (by calling this function with + IpConfigData set to NULL), no more traffic can be sent or received until these + parameters have been set again. Each EFI IPv4 Protocol instance can be started + and stopped independently of each other by enabling or disabling their receive + filter settings with the Configure() function. + + When IpConfigData.UseDefaultAddress is set to FALSE, the new station address will + be appended as an alias address into the addresses list in the EFI IPv4 Protocol + driver. While set to TRUE, Configure() will trigger the EFI_IP4_CONFIG_PROTOCOL + to retrieve the default IPv4 address if it is not available yet. Clients could + frequently call GetModeData() to check the status to ensure that the default IPv4 + address is ready. + + If operational parameters are reset or changed, any pending transmit and receive + requests will be cancelled. Their completion token status will be set to EFI_ABORTED + and their events will be signaled. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param IpConfigData The pointer to the EFI IPv4 Protocol configuration data structure. + + @retval EFI_SUCCESS The driver instance was successfully opened. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + IpConfigData.StationAddress is not a unicast IPv4 address. + IpConfigData.SubnetMask is not a valid IPv4 subnet + @retval EFI_UNSUPPORTED One or more of the following conditions is TRUE: + A configuration protocol (DHCP, BOOTP, RARP, etc.) could + not be located when clients choose to use the default IPv4 + address. This EFI IPv4 Protocol implementation does not + support this requested filter or timeout setting. + @retval EFI_OUT_OF_RESOURCES The EFI IPv4 Protocol driver instance data could not be allocated. + @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the + IPv4 address or subnet mask can be changed. The interface must + also be stopped when switching to/from raw packet mode. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv4 + Protocol driver instance is not opened. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIGURE)( + IN EFI_IP4_PROTOCOL *This, + IN EFI_IP4_CONFIG_DATA *IpConfigData OPTIONAL + ); + +/** + Joins and leaves multicast groups. + + The Groups() function is used to join and leave multicast group sessions. Joining + a group will enable reception of matching multicast packets. Leaving a group will + disable the multicast packet reception. + + If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param JoinFlag Set to TRUE to join the multicast group session and FALSE to leave. + @param GroupAddress The pointer to the IPv4 multicast address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following is TRUE: + - This is NULL. + - JoinFlag is TRUE and GroupAddress is NULL. + - GroupAddress is not NULL and *GroupAddress is + not a multicast IPv4 address. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_OUT_OF_RESOURCES System resources could not be allocated. + @retval EFI_UNSUPPORTED This EFI IPv4 Protocol implementation does not support multicast groups. + @retval EFI_ALREADY_STARTED The group address is already in the group table (when + JoinFlag is TRUE). + @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_GROUPS)( + IN EFI_IP4_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv4_ADDRESS *GroupAddress OPTIONAL + ); + +/** + Adds and deletes routing table entries. + + The Routes() function adds a route to or deletes a route from the routing table. + + Routes are determined by comparing the SubnetAddress with the destination IPv4 + address arithmetically AND-ed with the SubnetMask. The gateway address must be + on the same subnet as the configured station address. + + The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0. + The default route matches all destination IPv4 addresses that do not match any + other routes. + + A GatewayAddress that is zero is a nonroute. Packets are sent to the destination + IP address if it can be found in the ARP cache or on the local subnet. One automatic + nonroute entry will be inserted into the routing table for outgoing packets that + are addressed to a local subnet (gateway address of 0.0.0.0). + + Each EFI IPv4 Protocol instance has its own independent routing table. Those EFI + IPv4 Protocol instances that use the default IPv4 address will also have copies + of the routing table that was provided by the EFI_IP4_CONFIG_PROTOCOL, and these + copies will be updated whenever the EIF IPv4 Protocol driver reconfigures its + instances. As a result, client modification to the routing table will be lost. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param DeleteRoute Set to TRUE to delete this route from the routing table. Set to + FALSE to add this route to the routing table. SubnetAddress + and SubnetMask are used as the key to each route entry. + @param SubnetAddress The address of the subnet that needs to be routed. + @param SubnetMask The subnet mask of SubnetAddress. + @param GatewayAddress The unicast gateway IPv4 address for this route. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The driver instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - SubnetAddress is NULL. + - SubnetMask is NULL. + - GatewayAddress is NULL. + - *SubnetAddress is not a valid subnet address. + - *SubnetMask is not a valid subnet mask. + - *GatewayAddress is not a valid unicast IPv4 address. + @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table. + @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE). + @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when + DeleteRoute is FALSE). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_ROUTES)( + IN EFI_IP4_PROTOCOL *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ); + +/** + Places outgoing data packets into the transmit queue. + + The Transmit() function places a sending request in the transmit queue of this + EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some + errors occur, the event in the token will be signaled and the status is updated. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param Token The pointer to the transmit token. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more pameters are invalid. + @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event + was already in the transmit queue. + @retval EFI_NOT_READY The completion token could not be queued because the transmit + queue is full. + @retval EFI_NOT_FOUND Not route is found to destination address. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data. + @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too + short to transmit. + @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length + total data length is + greater than MTU (or greater than the maximum packet size if + Token.Packet.TxData.OverrideData. + DoNotFragment is TRUE.) + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_TRANSMIT)( + IN EFI_IP4_PROTOCOL *This, + IN EFI_IP4_COMPLETION_TOKEN *Token + ); + +/** + Places a receiving request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. + This function is always asynchronous. + + The Token.Event field in the completion token must be filled in by the caller + and cannot be NULL. When the receive operation completes, the EFI IPv4 Protocol + driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event + is signaled. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param Token The pointer to a token that is associated with the receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, RARP, etc.) + is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system + resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + The EFI IPv4 Protocol instance has been reset to startup defaults. + @retval EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already + in the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + @retval EFI_ICMP_ERROR An ICMP error packet was received. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_RECEIVE)( + IN EFI_IP4_PROTOCOL *This, + IN EFI_IP4_COMPLETION_TOKEN *Token + ); + +/** + Abort an asynchronous transmit or receive request. + + The Cancel() function is used to abort a pending transmit or receive request. + If the token is in the transmit or receive request queues, after calling this + function, Token->Status will be set to EFI_ABORTED and then Token->Event will + be signaled. If the token is not in one of the queues, which usually means the + asynchronous operation has completed, this function will not signal the token + and EFI_NOT_FOUND is returned. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + @param Token The pointer to a token that has been issued by + EFI_IP4_PROTOCOL.Transmit() or + EFI_IP4_PROTOCOL.Receive(). If NULL, all pending + tokens are aborted. Type EFI_IP4_COMPLETION_TOKEN is + defined in EFI_IP4_PROTOCOL.Transmit(). + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and + Token->Event was signaled. When Token is NULL, all + pending requests were aborted and their events were signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was + not found in the transmit or receive queue. It has either completed + or was not issued by Transmit() and Receive(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CANCEL)( + IN EFI_IP4_PROTOCOL *This, + IN EFI_IP4_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function polls for incoming data packets and processes outgoing data + packets. Network drivers and applications can call the EFI_IP4_PROTOCOL.Poll() + function to increase the rate that data packets are moved between the communications + device and the transmit and receive queues. + + In some systems the periodic timer event may not poll the underlying communications + device fast enough to transmit and/or receive all data packets without missing + incoming packets or dropping outgoing packets. Drivers and applications that are + experiencing packet loss should try calling the EFI_IP4_PROTOCOL.Poll() function + more often. + + @param This The pointer to the EFI_IP4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI IPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_POLL)( + IN EFI_IP4_PROTOCOL *This + ); + +/// +/// The EFI IPv4 Protocol implements a simple packet-oriented interface that can be +/// used by drivers, daemons, and applications to transmit and receive network packets. +/// +struct _EFI_IP4_PROTOCOL { + EFI_IP4_GET_MODE_DATA GetModeData; + EFI_IP4_CONFIGURE Configure; + EFI_IP4_GROUPS Groups; + EFI_IP4_ROUTES Routes; + EFI_IP4_TRANSMIT Transmit; + EFI_IP4_RECEIVE Receive; + EFI_IP4_CANCEL Cancel; + EFI_IP4_POLL Poll; +}; + +extern EFI_GUID gEfiIp4ServiceBindingProtocolGuid; +extern EFI_GUID gEfiIp4ProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Ip4Config.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Ip4Config.h new file mode 100644 index 000000000..227ae0399 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Ip4Config.h @@ -0,0 +1,184 @@ +/** @file + This file provides a definition of the EFI IPv4 Configuration + Protocol. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.0. + +**/ +#ifndef __EFI_IP4CONFIG_PROTOCOL_H__ +#define __EFI_IP4CONFIG_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/Protocol/Ip4.h> + +#define EFI_IP4_CONFIG_PROTOCOL_GUID \ + { \ + 0x3b95aa31, 0x3793, 0x434b, {0x86, 0x67, 0xc8, 0x07, 0x08, 0x92, 0xe0, 0x5e } \ + } + +typedef struct _EFI_IP4_CONFIG_PROTOCOL EFI_IP4_CONFIG_PROTOCOL; + +#define IP4_CONFIG_VARIABLE_ATTRIBUTES \ + (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS) + +/// +/// EFI_IP4_IPCONFIG_DATA contains the minimum IPv4 configuration data +/// that is needed to start basic network communication. The StationAddress +/// and SubnetMask must be a valid unicast IP address and subnet mask. +/// If RouteTableSize is not zero, then RouteTable contains a properly +/// formatted routing table for the StationAddress/SubnetMask, with the +/// last entry in the table being the default route. +/// +typedef struct { + /// + /// Default station IP address, stored in network byte order. + /// + EFI_IPv4_ADDRESS StationAddress; + /// + /// Default subnet mask, stored in network byte order. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Number of entries in the following RouteTable. May be zero. + /// + UINT32 RouteTableSize; + /// + /// Default routing table data (stored in network byte order). + /// Ignored if RouteTableSize is zero. + /// + EFI_IP4_ROUTE_TABLE *RouteTable; +} EFI_IP4_IPCONFIG_DATA; + + +/** + Starts running the configuration policy for the EFI IPv4 Protocol driver. + + The Start() function is called to determine and to begin the platform + configuration policy by the EFI IPv4 Protocol driver. This determination may + be as simple as returning EFI_UNSUPPORTED if there is no EFI IPv4 Protocol + driver configuration policy. It may be as involved as loading some defaults + from nonvolatile storage, downloading dynamic data from a DHCP server, and + checking permissions with a site policy server. + Starting the configuration policy is just the beginning. It may finish almost + instantly or it may take several minutes before it fails to retrieve configuration + information from one or more servers. Once the policy is started, drivers + should use the DoneEvent parameter to determine when the configuration policy + has completed. EFI_IP4_CONFIG_PROTOCOL.GetData() must then be called to + determine if the configuration succeeded or failed. + Until the configuration completes successfully, EFI IPv4 Protocol driver instances + that are attempting to use default configurations must return EFI_NO_MAPPING. + Once the configuration is complete, the EFI IPv4 Configuration Protocol driver + signals DoneEvent. The configuration may need to be updated in the future. + Note that in this case the EFI IPv4 Configuration Protocol driver must signal + ReconfigEvent, and all EFI IPv4 Protocol driver instances that are using default + configurations must return EFI_NO_MAPPING until the configuration policy has + been rerun. + + @param This The pointer to the EFI_IP4_CONFIG_PROTOCOL instance. + @param DoneEvent Event that will be signaled when the EFI IPv4 + Protocol driver configuration policy completes + execution. This event must be of type EVT_NOTIFY_SIGNAL. + @param ReconfigEvent Event that will be signaled when the EFI IPv4 + Protocol driver configuration needs to be updated. + This event must be of type EVT_NOTIFY_SIGNAL. + + @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol + driver is now running. + @retval EFI_INVALID_PARAMETER One or more of the following parameters is NULL: + This + DoneEvent + ReconfigEvent + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ALREADY_STARTED The configuration policy for the EFI IPv4 Protocol + driver was already started. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. + @retval EFI_UNSUPPORTED This interface does not support the EFI IPv4 Protocol + driver configuration. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG_START)( + IN EFI_IP4_CONFIG_PROTOCOL *This, + IN EFI_EVENT DoneEvent, + IN EFI_EVENT ReconfigEvent + ); + +/** + Stops running the configuration policy for the EFI IPv4 Protocol driver. + + The Stop() function stops the configuration policy for the EFI IPv4 Protocol driver. + All configuration data will be lost after calling Stop(). + + @param This The pointer to the EFI_IP4_CONFIG_PROTOCOL instance. + + @retval EFI_SUCCESS The configuration policy for the EFI IPv4 Protocol + driver has been stopped. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol + driver was not started. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG_STOP)( + IN EFI_IP4_CONFIG_PROTOCOL *This + ); + +/** + Returns the default configuration data (if any) for the EFI IPv4 Protocol driver. + + The GetData() function returns the current configuration data for the EFI IPv4 + Protocol driver after the configuration policy has completed. + + @param This The pointer to the EFI_IP4_CONFIG_PROTOCOL instance. + @param IpConfigDataSize On input, the size of the IpConfigData buffer. + On output, the count of bytes that were written + into the IpConfigData buffer. + @param IpConfigData The pointer to the EFI IPv4 Configuration Protocol + driver configuration data structure. + Type EFI_IP4_IPCONFIG_DATA is defined in + "Related Definitions" below. + + @retval EFI_SUCCESS The EFI IPv4 Protocol driver configuration has been returned. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED The configuration policy for the EFI IPv4 Protocol + driver is not running. + @retval EFI_NOT_READY EFI IPv4 Protocol driver configuration is still running. + @retval EFI_ABORTED EFI IPv4 Protocol driver configuration could not complete. + @retval EFI_BUFFER_TOO_SMALL *IpConfigDataSize is smaller than the configuration + data buffer or IpConfigData is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG_GET_DATA)( + IN EFI_IP4_CONFIG_PROTOCOL *This, + IN OUT UINTN *IpConfigDataSize, + OUT EFI_IP4_IPCONFIG_DATA *IpConfigData OPTIONAL + ); + +/// +/// The EFI_IP4_CONFIG_PROTOCOL driver performs platform-dependent and policy-dependent +/// configurations for the EFI IPv4 Protocol driver. +/// +struct _EFI_IP4_CONFIG_PROTOCOL { + EFI_IP4_CONFIG_START Start; + EFI_IP4_CONFIG_STOP Stop; + EFI_IP4_CONFIG_GET_DATA GetData; +}; + +extern EFI_GUID gEfiIp4ConfigProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/LoadFile2.h b/roms/ipxe/src/include/ipxe/efi/Protocol/LoadFile2.h new file mode 100644 index 000000000..6cb26fff9 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/LoadFile2.h @@ -0,0 +1,87 @@ +/** @file + Load File protocol as defined in the UEFI 2.0 specification. + + Load file protocol exists to supports the addition of new boot devices, + and to support booting from devices that do not map well to file system. + Network boot is done via a LoadFile protocol. + + UEFI 2.0 can boot from any device that produces a LoadFile protocol. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_LOAD_FILE2_PROTOCOL_H__ +#define __EFI_LOAD_FILE2_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_LOAD_FILE2_PROTOCOL_GUID \ + { \ + 0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d } \ + } + +/// +/// Protocol Guid defined by UEFI2.1. +/// +#define LOAD_FILE2_PROTOCOL EFI_LOAD_FILE2_PROTOCOL_GUID + +typedef struct _EFI_LOAD_FILE2_PROTOCOL EFI_LOAD_FILE2_PROTOCOL; + + +/** + Causes the driver to load a specified file. + + @param This Protocol instance pointer. + @param FilePath The device specific path of the file to load. + @param BootPolicy Should always be FALSE. + @param BufferSize On input the size of Buffer in bytes. On output with a return + code of EFI_SUCCESS, the amount of data transferred to + Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL, + the size of Buffer required to retrieve the requested file. + @param Buffer The memory buffer to transfer the file to. IF Buffer is NULL, + then no the size of the requested file is returned in + BufferSize. + + @retval EFI_SUCCESS The file was loaded. + @retval EFI_UNSUPPORTED BootPolicy is TRUE. + @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or + BufferSize is NULL. + @retval EFI_NO_MEDIA No medium was present to load the file. + @retval EFI_DEVICE_ERROR The file was not loaded due to a device error. + @retval EFI_NO_RESPONSE The remote system did not respond. + @retval EFI_NOT_FOUND The file was not found + @retval EFI_ABORTED The file load process was manually canceled. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current + directory entry. BufferSize has been updated with + the size needed to complete the request. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LOAD_FILE2)( + IN EFI_LOAD_FILE2_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ); + +/// +/// The EFI_LOAD_FILE_PROTOCOL is a simple protocol used to obtain files from arbitrary devices. +/// +struct _EFI_LOAD_FILE2_PROTOCOL { + EFI_LOAD_FILE2 LoadFile; +}; + +extern EFI_GUID gEfiLoadFile2ProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/ManagedNetwork.h b/roms/ipxe/src/include/ipxe/efi/Protocol/ManagedNetwork.h new file mode 100644 index 000000000..2bd092269 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/ManagedNetwork.h @@ -0,0 +1,374 @@ +/** @file + EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL as defined in UEFI 2.0. + EFI_MANAGED_NETWORK_PROTOCOL as defined in UEFI 2.0. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.0 + +**/ + +#ifndef __EFI_MANAGED_NETWORK_PROTOCOL_H__ +#define __EFI_MANAGED_NETWORK_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/Protocol/SimpleNetwork.h> + +#define EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xf36ff770, 0xa7e1, 0x42cf, {0x9e, 0xd2, 0x56, 0xf0, 0xf2, 0x71, 0xf4, 0x4c } \ + } + +#define EFI_MANAGED_NETWORK_PROTOCOL_GUID \ + { \ + 0x7ab33a91, 0xace5, 0x4326, { 0xb5, 0x72, 0xe7, 0xee, 0x33, 0xd3, 0x9f, 0x16 } \ + } + +typedef struct _EFI_MANAGED_NETWORK_PROTOCOL EFI_MANAGED_NETWORK_PROTOCOL; + +typedef struct { + /// + /// Timeout value for a UEFI one-shot timer event. A packet that has not been removed + /// from the MNP receive queue will be dropped if its receive timeout expires. + /// + UINT32 ReceivedQueueTimeoutValue; + /// + /// Timeout value for a UEFI one-shot timer event. A packet that has not been removed + /// from the MNP transmit queue will be dropped if its receive timeout expires. + /// + UINT32 TransmitQueueTimeoutValue; + /// + /// Ethernet type II 16-bit protocol type in host byte order. Valid + /// values are zero and 1,500 to 65,535. + /// + UINT16 ProtocolTypeFilter; + /// + /// Set to TRUE to receive packets that are sent to the network + /// device MAC address. The startup default value is FALSE. + /// + BOOLEAN EnableUnicastReceive; + /// + /// Set to TRUE to receive packets that are sent to any of the + /// active multicast groups. The startup default value is FALSE. + /// + BOOLEAN EnableMulticastReceive; + /// + /// Set to TRUE to receive packets that are sent to the network + /// device broadcast address. The startup default value is FALSE. + /// + BOOLEAN EnableBroadcastReceive; + /// + /// Set to TRUE to receive packets that are sent to any MAC address. + /// The startup default value is FALSE. + /// + BOOLEAN EnablePromiscuousReceive; + /// + /// Set to TRUE to drop queued packets when the configuration + /// is changed. The startup default value is FALSE. + /// + BOOLEAN FlushQueuesOnReset; + /// + /// Set to TRUE to timestamp all packets when they are received + /// by the MNP. Note that timestamps may be unsupported in some + /// MNP implementations. The startup default value is FALSE. + /// + BOOLEAN EnableReceiveTimestamps; + /// + /// Set to TRUE to disable background polling in this MNP + /// instance. Note that background polling may not be supported in + /// all MNP implementations. The startup default value is FALSE, + /// unless background polling is not supported. + /// + BOOLEAN DisableBackgroundPolling; +} EFI_MANAGED_NETWORK_CONFIG_DATA; + +typedef struct { + EFI_TIME Timestamp; + EFI_EVENT RecycleEvent; + UINT32 PacketLength; + UINT32 HeaderLength; + UINT32 AddressLength; + UINT32 DataLength; + BOOLEAN BroadcastFlag; + BOOLEAN MulticastFlag; + BOOLEAN PromiscuousFlag; + UINT16 ProtocolType; + VOID *DestinationAddress; + VOID *SourceAddress; + VOID *MediaHeader; + VOID *PacketData; +} EFI_MANAGED_NETWORK_RECEIVE_DATA; + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_MANAGED_NETWORK_FRAGMENT_DATA; + +typedef struct { + EFI_MAC_ADDRESS *DestinationAddress; //OPTIONAL + EFI_MAC_ADDRESS *SourceAddress; //OPTIONAL + UINT16 ProtocolType; //OPTIONAL + UINT32 DataLength; + UINT16 HeaderLength; //OPTIONAL + UINT16 FragmentCount; + EFI_MANAGED_NETWORK_FRAGMENT_DATA FragmentTable[1]; +} EFI_MANAGED_NETWORK_TRANSMIT_DATA; + + +typedef struct { + /// + /// This Event will be signaled after the Status field is updated + /// by the MNP. The type of Event must be + /// EFI_NOTIFY_SIGNAL. The Task Priority Level (TPL) of + /// Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// The status that is returned to the caller at the end of the operation + /// to indicate whether this operation completed successfully. + /// + EFI_STATUS Status; + union { + /// + /// When this token is used for receiving, RxData is a pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA. + /// + EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData; + /// + /// When this token is used for transmitting, TxData is a pointer to the EFI_MANAGED_NETWORK_TRANSMIT_DATA. + /// + EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData; + } Packet; +} EFI_MANAGED_NETWORK_COMPLETION_TOKEN; + +/** + Returns the operational parameters for the current MNP child driver. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param MnpConfigData The pointer to storage for MNP operational parameters. + @param SnpModeData The pointer to storage for SNP operational parameters. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_UNSUPPORTED The requested feature is unsupported in this MNP implementation. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. The default + values are returned in MnpConfigData if it is not NULL. + @retval Other The mode data could not be read. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_GET_MODE_DATA)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Sets or clears the operational parameters for the MNP child driver. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param MnpConfigData The pointer to configuration data that will be assigned to the MNP + child driver instance. If NULL, the MNP child driver instance is + reset to startup defaults and all pending transmit and receive + requests are flushed. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Required system resources (usually memory) could not be + allocated. + @retval EFI_UNSUPPORTED The requested feature is unsupported in this [MNP] + implementation. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Other The MNP child driver instance has been reset to startup defaults. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_CONFIGURE)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + IN EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL + ); + +/** + Translates an IP multicast address to a hardware (MAC) multicast address. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param Ipv6Flag Set to TRUE to if IpAddress is an IPv6 multicast address. + Set to FALSE if IpAddress is an IPv4 multicast address. + @param IpAddress The pointer to the multicast IP address (in network byte order) to convert. + @param MacAddress The pointer to the resulting multicast MAC address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One of the following conditions is TRUE: + - This is NULL. + - IpAddress is NULL. + - *IpAddress is not a valid multicast IP address. + - MacAddress is NULL. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. + @retval EFI_UNSUPPORTED The requested feature is unsupported in this MNP implementation. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval Other The address could not be converted. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_MCAST_IP_TO_MAC)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + IN BOOLEAN Ipv6Flag, + IN EFI_IP_ADDRESS *IpAddress, + OUT EFI_MAC_ADDRESS *MacAddress + ); + +/** + Enables and disables receive filters for multicast address. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param JoinFlag Set to TRUE to join this multicast group. + Set to FALSE to leave this multicast group. + @param MacAddress The pointer to the multicast MAC group (address) to join or leave. + + @retval EFI_SUCCESS The requested operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - JoinFlag is TRUE and MacAddress is NULL. + - *MacAddress is not a valid multicast MAC address. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. + @retval EFI_ALREADY_STARTED The supplied multicast group is already joined. + @retval EFI_NOT_FOUND The supplied multicast group is not joined. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_UNSUPPORTED The requested feature is unsupported in this MNP implementation. + @retval Other The requested operation could not be completed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_GROUPS)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_MAC_ADDRESS *MacAddress OPTIONAL + ); + +/** + Places asynchronous outgoing data packets into the transmit queue. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param Token The pointer to a token associated with the transmit data descriptor. + + @retval EFI_SUCCESS The transmit completion token was cached. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED The transmit completion token is already in the transmit queue. + @retval EFI_OUT_OF_RESOURCES The transmit data could not be queued due to a lack of system resources + (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY The transmit request could not be queued because the transmit queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_TRANSMIT)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token + ); + +/** + Places an asynchronous receiving request into the receiving queue. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param Token The pointer to a token associated with the receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The transmit data could not be queued due to a lack of system resources + (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_ACCESS_DENIED The receive completion token was already in the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_RECEIVE)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token + ); + + +/** + Aborts an asynchronous transmit or receive request. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + @param Token The pointer to a token that has been issued by + EFI_MANAGED_NETWORK_PROTOCOL.Transmit() or + EFI_MANAGED_NETWORK_PROTOCOL.Receive(). If + NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and Token.Event + was signaled. When Token is NULL, all pending requests were + aborted and their events were signaled. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was + not found in the transmit or receive queue. It has either completed + or was not issued by Transmit() and Receive(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_CANCEL)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This, + IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + @param This The pointer to the EFI_MANAGED_NETWORK_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This MNP child driver instance has not been configured. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY No incoming or outgoing data was processed. Consider increasing + the polling rate. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MANAGED_NETWORK_POLL)( + IN EFI_MANAGED_NETWORK_PROTOCOL *This + ); + +/// +/// The MNP is used by network applications (and drivers) to +/// perform raw (unformatted) asynchronous network packet I/O. +/// +struct _EFI_MANAGED_NETWORK_PROTOCOL { + EFI_MANAGED_NETWORK_GET_MODE_DATA GetModeData; + EFI_MANAGED_NETWORK_CONFIGURE Configure; + EFI_MANAGED_NETWORK_MCAST_IP_TO_MAC McastIpToMac; + EFI_MANAGED_NETWORK_GROUPS Groups; + EFI_MANAGED_NETWORK_TRANSMIT Transmit; + EFI_MANAGED_NETWORK_RECEIVE Receive; + EFI_MANAGED_NETWORK_CANCEL Cancel; + EFI_MANAGED_NETWORK_POLL Poll; +}; + +extern EFI_GUID gEfiManagedNetworkServiceBindingProtocolGuid; +extern EFI_GUID gEfiManagedNetworkProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Mtftp4.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Mtftp4.h new file mode 100644 index 000000000..0e961cfd4 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Mtftp4.h @@ -0,0 +1,595 @@ +/** @file + EFI Multicast Trivial File Tranfer Protocol Definition + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.0 + +**/ + +#ifndef __EFI_MTFTP4_PROTOCOL_H__ +#define __EFI_MTFTP4_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x2FE800BE, 0x8F01, 0x4aa6, {0x94, 0x6B, 0xD7, 0x13, 0x88, 0xE1, 0x83, 0x3F } \ + } + +#define EFI_MTFTP4_PROTOCOL_GUID \ + { \ + 0x78247c57, 0x63db, 0x4708, {0x99, 0xc2, 0xa8, 0xb4, 0xa9, 0xa6, 0x1f, 0x6b } \ + } + +typedef struct _EFI_MTFTP4_PROTOCOL EFI_MTFTP4_PROTOCOL; +typedef struct _EFI_MTFTP4_TOKEN EFI_MTFTP4_TOKEN; + +// +//MTFTP4 packet opcode definition +// +#define EFI_MTFTP4_OPCODE_RRQ 1 +#define EFI_MTFTP4_OPCODE_WRQ 2 +#define EFI_MTFTP4_OPCODE_DATA 3 +#define EFI_MTFTP4_OPCODE_ACK 4 +#define EFI_MTFTP4_OPCODE_ERROR 5 +#define EFI_MTFTP4_OPCODE_OACK 6 +#define EFI_MTFTP4_OPCODE_DIR 7 +#define EFI_MTFTP4_OPCODE_DATA8 8 +#define EFI_MTFTP4_OPCODE_ACK8 9 + +// +// MTFTP4 error code definition +// +#define EFI_MTFTP4_ERRORCODE_NOT_DEFINED 0 +#define EFI_MTFTP4_ERRORCODE_FILE_NOT_FOUND 1 +#define EFI_MTFTP4_ERRORCODE_ACCESS_VIOLATION 2 +#define EFI_MTFTP4_ERRORCODE_DISK_FULL 3 +#define EFI_MTFTP4_ERRORCODE_ILLEGAL_OPERATION 4 +#define EFI_MTFTP4_ERRORCODE_UNKNOWN_TRANSFER_ID 5 +#define EFI_MTFTP4_ERRORCODE_FILE_ALREADY_EXISTS 6 +#define EFI_MTFTP4_ERRORCODE_NO_SUCH_USER 7 +#define EFI_MTFTP4_ERRORCODE_REQUEST_DENIED 8 + +// +// MTFTP4 pacekt definitions +// +#pragma pack(1) + +typedef struct { + UINT16 OpCode; + UINT8 Filename[1]; +} EFI_MTFTP4_REQ_HEADER; + +typedef struct { + UINT16 OpCode; + UINT8 Data[1]; +} EFI_MTFTP4_OACK_HEADER; + +typedef struct { + UINT16 OpCode; + UINT16 Block; + UINT8 Data[1]; +} EFI_MTFTP4_DATA_HEADER; + +typedef struct { + UINT16 OpCode; + UINT16 Block[1]; +} EFI_MTFTP4_ACK_HEADER; + +typedef struct { + UINT16 OpCode; + UINT64 Block; + UINT8 Data[1]; +} EFI_MTFTP4_DATA8_HEADER; + +typedef struct { + UINT16 OpCode; + UINT64 Block[1]; +} EFI_MTFTP4_ACK8_HEADER; + +typedef struct { + UINT16 OpCode; + UINT16 ErrorCode; + UINT8 ErrorMessage[1]; +} EFI_MTFTP4_ERROR_HEADER; + +typedef union { + /// + /// Type of packets as defined by the MTFTPv4 packet opcodes. + /// + UINT16 OpCode; + /// + /// Read request packet header. + /// + EFI_MTFTP4_REQ_HEADER Rrq; + /// + /// Write request packet header. + /// + EFI_MTFTP4_REQ_HEADER Wrq; + /// + /// Option acknowledge packet header. + /// + EFI_MTFTP4_OACK_HEADER Oack; + /// + /// Data packet header. + /// + EFI_MTFTP4_DATA_HEADER Data; + /// + /// Acknowledgement packet header. + /// + EFI_MTFTP4_ACK_HEADER Ack; + /// + /// Data packet header with big block number. + /// + EFI_MTFTP4_DATA8_HEADER Data8; + /// + /// Acknowledgement header with big block num. + /// + EFI_MTFTP4_ACK8_HEADER Ack8; + /// + /// Error packet header. + /// + EFI_MTFTP4_ERROR_HEADER Error; +} EFI_MTFTP4_PACKET; + +#pragma pack() + +/// +/// MTFTP4 option definition. +/// +typedef struct { + UINT8 *OptionStr; + UINT8 *ValueStr; +} EFI_MTFTP4_OPTION; + + +typedef struct { + BOOLEAN UseDefaultSetting; + EFI_IPv4_ADDRESS StationIp; + EFI_IPv4_ADDRESS SubnetMask; + UINT16 LocalPort; + EFI_IPv4_ADDRESS GatewayIp; + EFI_IPv4_ADDRESS ServerIp; + UINT16 InitialServerPort; + UINT16 TryCount; + UINT16 TimeoutValue; +} EFI_MTFTP4_CONFIG_DATA; + + +typedef struct { + EFI_MTFTP4_CONFIG_DATA ConfigData; + UINT8 SupportedOptionCount; + UINT8 **SupportedOptoins; + UINT8 UnsupportedOptionCount; + UINT8 **UnsupportedOptoins; +} EFI_MTFTP4_MODE_DATA; + + +typedef struct { + EFI_IPv4_ADDRESS GatewayIp; + EFI_IPv4_ADDRESS ServerIp; + UINT16 ServerPort; + UINT16 TryCount; + UINT16 TimeoutValue; +} EFI_MTFTP4_OVERRIDE_DATA; + +// +// Protocol interfaces definition +// + +/** + A callback function that is provided by the caller to intercept + the EFI_MTFTP4_OPCODE_DATA or EFI_MTFTP4_OPCODE_DATA8 packets processed in the + EFI_MTFTP4_PROTOCOL.ReadFile() function, and alternatively to intercept + EFI_MTFTP4_OPCODE_OACK or EFI_MTFTP4_OPCODE_ERROR packets during a call to + EFI_MTFTP4_PROTOCOL.ReadFile(), WriteFile() or ReadDirectory(). + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param Token The token that the caller provided in the + EFI_MTFTP4_PROTOCOL.ReadFile(), WriteFile() + or ReadDirectory() function. + @param PacketLen Indicates the length of the packet. + @param Packet The pointer to an MTFTPv4 packet. + + @retval EFI_SUCCESS The operation was successful. + @retval Others Aborts the transfer process. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_CHECK_PACKET)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP4_PACKET *Paket + ); + +/** + Timeout callback funtion. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param Token The token that is provided in the + EFI_MTFTP4_PROTOCOL.ReadFile() or + EFI_MTFTP4_PROTOCOL.WriteFile() or + EFI_MTFTP4_PROTOCOL.ReadDirectory() functions + by the caller. + + @retval EFI_SUCCESS The operation was successful. + @retval Others Aborts download process. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_TIMEOUT_CALLBACK)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token + ); + +/** + A callback function that the caller provides to feed data to the + EFI_MTFTP4_PROTOCOL.WriteFile() function. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param Token The token provided in the + EFI_MTFTP4_PROTOCOL.WriteFile() by the caller. + @param Length Indicates the length of the raw data wanted on input, and the + length the data available on output. + @param Buffer The pointer to the buffer where the data is stored. + + @retval EFI_SUCCESS The operation was successful. + @retval Others Aborts session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_PACKET_NEEDED)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN OUT UINT16 *Length, + OUT VOID **Buffer + ); + + +/** + Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param ModeData The pointer to storage for the EFI MTFTPv4 Protocol driver mode data. + + @retval EFI_SUCCESS The configuration data was successfully returned. + @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated. + @retval EFI_INVALID_PARAMETER This is NULL or ModeData is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_GET_MODE_DATA)( + IN EFI_MTFTP4_PROTOCOL *This, + OUT EFI_MTFTP4_MODE_DATA *ModeData + ); + + +/** + Initializes, changes, or resets the default operational setting for this + EFI MTFTPv4 Protocol driver instance. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param MtftpConfigData The pointer to the configuration data structure. + + @retval EFI_SUCCESS The EFI MTFTPv4 Protocol driver was configured successfully. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED The EFI configuration could not be changed at this time because + there is one MTFTP background operation in progress. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) has not finished yet. + @retval EFI_UNSUPPORTED A configuration protocol (DHCP, BOOTP, RARP, etc.) could not + be located when clients choose to use the default address + settings. + @retval EFI_OUT_OF_RESOURCES The EFI MTFTPv4 Protocol driver instance data could not be + allocated. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI + MTFTPv4 Protocol driver instance is not configured. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_CONFIGURE)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_CONFIG_DATA *MtftpConfigData OPTIONAL + ); + + +/** + Gets information about a file from an MTFTPv4 server. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param OverrideData Data that is used to override the existing parameters. If NULL, + the default parameters that were set in the + EFI_MTFTP4_PROTOCOL.Configure() function are used. + @param Filename The pointer to null-terminated ASCII file name string. + @param ModeStr The pointer to null-terminated ASCII mode string. If NULL, "octet" will be used. + @param OptionCount Number of option/value string pairs in OptionList. + @param OptionList The pointer to array of option/value string pairs. Ignored if + OptionCount is zero. + @param PacketLength The number of bytes in the returned packet. + @param Packet The pointer to the received packet. This buffer must be freed by + the caller. + + @retval EFI_SUCCESS An MTFTPv4 OACK packet was received and is in the Packet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Filename is NULL. + - OptionCount is not zero and OptionList is NULL. + - One or more options in OptionList have wrong format. + - PacketLength is NULL. + - One or more IPv4 addresses in OverrideData are not valid + unicast IPv4 addresses if OverrideData is not NULL. + @retval EFI_UNSUPPORTED One or more options in the OptionList are in the + unsupported list of structure EFI_MTFTP4_MODE_DATA. + @retval EFI_NOT_STARTED The EFI MTFTPv4 Protocol driver has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) has not finished yet. + @retval EFI_ACCESS_DENIED The previous operation has not completed yet. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_TFTP_ERROR An MTFTPv4 ERROR packet was received and is in the Packet. + @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received and the Packet is set to NULL. + @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received and the Packet is set to NULL. + @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received and the Packet is set to NULL. + @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received and the Packet is set to NULL. + @retval EFI_ICMP_ERROR Some other ICMP ERROR packet was received and is in the Buffer. + @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv4 packet was received and is in the Packet. + @retval EFI_TIMEOUT No responses were received from the MTFTPv4 server. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + @retval EFI_NO_MEDIA There was a media error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_GET_INFO)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_OVERRIDE_DATA *OverrideData OPTIONAL, + IN UINT8 *Filename, + IN UINT8 *ModeStr OPTIONAL, + IN UINT8 OptionCount, + IN EFI_MTFTP4_OPTION *OptionList, + OUT UINT32 *PacketLength, + OUT EFI_MTFTP4_PACKET **Packet OPTIONAL + ); + +/** + Parses the options in an MTFTPv4 OACK packet. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param PacketLen Length of the OACK packet to be parsed. + @param Packet The pointer to the OACK packet to be parsed. + @param OptionCount The pointer to the number of options in following OptionList. + @param OptionList The pointer to EFI_MTFTP4_OPTION storage. Call the EFI Boot + Service FreePool() to release the OptionList if the options + in this OptionList are not needed any more. + + @retval EFI_SUCCESS The OACK packet was valid and the OptionCount and + OptionList parameters have been updated. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - PacketLen is 0. + - Packet is NULL or Packet is not a valid MTFTPv4 packet. + - OptionCount is NULL. + @retval EFI_NOT_FOUND No options were found in the OACK packet. + @retval EFI_OUT_OF_RESOURCES Storage for the OptionList array cannot be allocated. + @retval EFI_PROTOCOL_ERROR One or more of the option fields is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_PARSE_OPTIONS)( + IN EFI_MTFTP4_PROTOCOL *This, + IN UINT32 PacketLen, + IN EFI_MTFTP4_PACKET *Packet, + OUT UINT32 *OptionCount, + OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL + ); + + +/** + Downloads a file from an MTFTPv4 server. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param Token The pointer to the token structure to provide the parameters that are + used in this operation. + + @retval EFI_SUCCESS The data file has been transferred successfully. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_BUFFER_TOO_SMALL BufferSize is not zero but not large enough to hold the + downloaded data in downloading process. + @retval EFI_ABORTED Current operation is aborted by user. + @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received. + @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received. + @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received. + @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received. + @retval EFI_ICMP_ERROR Some other ICMP ERROR packet was received. + @retval EFI_TIMEOUT No responses were received from the MTFTPv4 server. + @retval EFI_TFTP_ERROR An MTFTPv4 ERROR packet was received. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + @retval EFI_NO_MEDIA There was a media error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_READ_FILE)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token + ); + + + +/** + Sends a file to an MTFTPv4 server. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param Token The pointer to the token structure to provide the parameters that are + used in this operation. + + @retval EFI_SUCCESS The upload session has started. + @retval EFI_UNSUPPORTED The operation is not supported by this implementation. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are in + the unsupported list of structure EFI_MTFTP4_MODE_DATA. + @retval EFI_NOT_STARTED The EFI MTFTPv4 Protocol driver has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv4 session. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The previous operation has not completed yet. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_WRITE_FILE)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token + ); + + +/** + Downloads a data file "directory" from an MTFTPv4 server. May be unsupported in some EFI + implementations. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + @param Token The pointer to the token structure to provide the parameters that are + used in this operation. + + @retval EFI_SUCCESS The MTFTPv4 related file "directory" has been downloaded. + @retval EFI_UNSUPPORTED The operation is not supported by this implementation. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are in + the unsupported list of structure EFI_MTFTP4_MODE_DATA. + @retval EFI_NOT_STARTED The EFI MTFTPv4 Protocol driver has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv4 session. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The previous operation has not completed yet. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_READ_DIRECTORY)( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + @param This The pointer to the EFI_MTFTP4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI MTFTPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP4_POLL)( + IN EFI_MTFTP4_PROTOCOL *This + ); + +/// +/// The EFI_MTFTP4_PROTOCOL is designed to be used by UEFI drivers and applications +/// to transmit and receive data files. The EFI MTFTPv4 Protocol driver uses +/// the underlying EFI UDPv4 Protocol driver and EFI IPv4 Protocol driver. +/// +struct _EFI_MTFTP4_PROTOCOL { + EFI_MTFTP4_GET_MODE_DATA GetModeData; + EFI_MTFTP4_CONFIGURE Configure; + EFI_MTFTP4_GET_INFO GetInfo; + EFI_MTFTP4_PARSE_OPTIONS ParseOptions; + EFI_MTFTP4_READ_FILE ReadFile; + EFI_MTFTP4_WRITE_FILE WriteFile; + EFI_MTFTP4_READ_DIRECTORY ReadDirectory; + EFI_MTFTP4_POLL Poll; +}; + +struct _EFI_MTFTP4_TOKEN { + /// + /// The status that is returned to the caller at the end of the operation + /// to indicate whether this operation completed successfully. + /// + EFI_STATUS Status; + /// + /// The event that will be signaled when the operation completes. If + /// set to NULL, the corresponding function will wait until the read or + /// write operation finishes. The type of Event must be + /// EVT_NOTIFY_SIGNAL. The Task Priority Level (TPL) of + /// Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// If not NULL, the data that will be used to override the existing configure data. + /// + EFI_MTFTP4_OVERRIDE_DATA *OverrideData; + /// + /// The pointer to the null-terminated ASCII file name string. + /// + UINT8 *Filename; + /// + /// The pointer to the null-terminated ASCII mode string. If NULL, "octet" is used. + /// + UINT8 *ModeStr; + /// + /// Number of option/value string pairs. + /// + UINT32 OptionCount; + /// + /// The pointer to an array of option/value string pairs. Ignored if OptionCount is zero. + /// + EFI_MTFTP4_OPTION *OptionList; + /// + /// The size of the data buffer. + /// + UINT64 BufferSize; + /// + /// The pointer to the data buffer. Data that is downloaded from the + /// MTFTPv4 server is stored here. Data that is uploaded to the + /// MTFTPv4 server is read from here. Ignored if BufferSize is zero. + /// + VOID *Buffer; + /// + /// The pointer to the context that will be used by CheckPacket, + /// TimeoutCallback and PacketNeeded. + /// + VOID *Context; + /// + /// The pointer to the callback function to check the contents of the received packet. + /// + EFI_MTFTP4_CHECK_PACKET CheckPacket; + /// + /// The pointer to the function to be called when a timeout occurs. + /// + EFI_MTFTP4_TIMEOUT_CALLBACK TimeoutCallback; + /// + /// The pointer to the function to provide the needed packet contents. + /// + EFI_MTFTP4_PACKET_NEEDED PacketNeeded; +}; + +extern EFI_GUID gEfiMtftp4ServiceBindingProtocolGuid; +extern EFI_GUID gEfiMtftp4ProtocolGuid; + +#endif + diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h b/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h index 29319069f..5adedd8e9 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h @@ -1,7 +1,7 @@ /** @file EFI Network Interface Identifier Protocol. -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -36,7 +36,11 @@ FILE_LICENCE ( BSD3 ); 0x1ACED566, 0x76ED, 0x4218, {0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } \ } -#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION 0x00010000 +// +// Revision defined in UEFI Specification 2.4 +// +#define EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION 0x00020000 + /// /// Revision defined in EFI1.1. @@ -72,9 +76,9 @@ struct _EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL { UINT8 MajorVer; ///< Major version number. UINT8 MinorVer; ///< Minor version number. BOOLEAN Ipv6Supported; ///< TRUE if the network interface supports IPv6; otherwise FALSE. - UINT8 IfNum; ///< The network interface number that is being identified by this Network - ///< Interface Identifier Protocol. This field must be less than or equal - ///< to the IFcnt field in the !PXE structure. + UINT16 IfNum; ///< The network interface number that is being identified by this Network + ///< Interface Identifier Protocol. This field must be less than or + ///< equal to the (IFcnt | IFcntExt <<8 ) fields in the !PXE structure. }; diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/PxeBaseCode.h b/roms/ipxe/src/include/ipxe/efi/Protocol/PxeBaseCode.h new file mode 100644 index 000000000..26447987d --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/PxeBaseCode.h @@ -0,0 +1,936 @@ +/** @file + EFI PXE Base Code Protocol definitions, which is used to access PXE-compatible + devices for network access and network booting. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in EFI Specification 1.10. + +**/ +#ifndef __PXE_BASE_CODE_PROTOCOL_H__ +#define __PXE_BASE_CODE_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +/// +/// PXE Base Code protocol. +/// +#define EFI_PXE_BASE_CODE_PROTOCOL_GUID \ + { \ + 0x03c4e603, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +typedef struct _EFI_PXE_BASE_CODE_PROTOCOL EFI_PXE_BASE_CODE_PROTOCOL; + +/// +/// Protocol defined in EFI1.1. +/// +typedef EFI_PXE_BASE_CODE_PROTOCOL EFI_PXE_BASE_CODE; + +/// +/// Default IP TTL and ToS. +/// +#define DEFAULT_TTL 16 +#define DEFAULT_ToS 0 + +/// +/// ICMP error format. +/// +typedef struct { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + union { + UINT32 reserved; + UINT32 Mtu; + UINT32 Pointer; + struct { + UINT16 Identifier; + UINT16 Sequence; + } Echo; + } u; + UINT8 Data[494]; +} EFI_PXE_BASE_CODE_ICMP_ERROR; + +/// +/// TFTP error format. +/// +typedef struct { + UINT8 ErrorCode; + CHAR8 ErrorString[127]; +} EFI_PXE_BASE_CODE_TFTP_ERROR; + +/// +/// IP Receive Filter definitions. +/// +#define EFI_PXE_BASE_CODE_MAX_IPCNT 8 + +/// +/// IP Receive Filter structure. +/// +typedef struct { + UINT8 Filters; + UINT8 IpCnt; + UINT16 reserved; + EFI_IP_ADDRESS IpList[EFI_PXE_BASE_CODE_MAX_IPCNT]; +} EFI_PXE_BASE_CODE_IP_FILTER; + +#define EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP 0x0001 +#define EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST 0x0002 +#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS 0x0004 +#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST 0x0008 + +/// +/// ARP cache entries. +/// +typedef struct { + EFI_IP_ADDRESS IpAddr; + EFI_MAC_ADDRESS MacAddr; +} EFI_PXE_BASE_CODE_ARP_ENTRY; + +/// +/// ARP route table entries. +/// +typedef struct { + EFI_IP_ADDRESS IpAddr; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS GwAddr; +} EFI_PXE_BASE_CODE_ROUTE_ENTRY; + +// +// UDP definitions +// +typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT; + +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP 0x0001 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT 0x0002 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP 0x0004 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT 0x0008 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER 0x0010 +#define EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT 0x0020 + +// +// Discover() definitions +// +#define EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP 0 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_MS_WINNT_RIS 1 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_INTEL_LCM 2 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_DOSUNDI 3 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_NEC_ESMPRO 4 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_WSoD 5 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_IBM_LCCM 6 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_CA_UNICENTER_TNG 7 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_HP_OPENVIEW 8 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_9 9 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_10 10 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_ALTIRIS_11 11 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_NOT_USED_12 12 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_INSTALL 13 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REDHAT_BOOT 14 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_REMBO 15 +#define EFI_PXE_BASE_CODE_BOOT_TYPE_BEOBOOT 16 +// +// 17 through 32767 are reserved +// 32768 through 65279 are for vendor use +// 65280 through 65534 are reserved +// +#define EFI_PXE_BASE_CODE_BOOT_TYPE_PXETEST 65535 + +#define EFI_PXE_BASE_CODE_BOOT_LAYER_MASK 0x7FFF +#define EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL 0x0000 + +// +// PXE Tag definition that identifies the processor +// and programming environment of the client system. +// These identifiers are defined by IETF: +// http://www.ietf.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml +// +#if defined (MDE_CPU_IA32) +#define EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE 0x0006 +#elif defined (MDE_CPU_IPF) +#define EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE 0x0002 +#elif defined (MDE_CPU_X64) +#define EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE 0x0007 +#elif defined (MDE_CPU_ARM) +#define EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE 0x000A +#elif defined (MDE_CPU_AARCH64) +#define EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE 0x000B +#endif + + +/// +/// Discover() server list structure. +/// +typedef struct { + UINT16 Type; + BOOLEAN AcceptAnyResponse; + UINT8 Reserved; + EFI_IP_ADDRESS IpAddr; +} EFI_PXE_BASE_CODE_SRVLIST; + +/// +/// Discover() information override structure. +/// +typedef struct { + BOOLEAN UseMCast; + BOOLEAN UseBCast; + BOOLEAN UseUCast; + BOOLEAN MustUseList; + EFI_IP_ADDRESS ServerMCastIp; + UINT16 IpCnt; + EFI_PXE_BASE_CODE_SRVLIST SrvList[1]; +} EFI_PXE_BASE_CODE_DISCOVER_INFO; + +/// +/// TFTP opcode definitions. +/// +typedef enum { + EFI_PXE_BASE_CODE_TFTP_FIRST, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, + EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, + EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, + EFI_PXE_BASE_CODE_MTFTP_READ_FILE, + EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, + EFI_PXE_BASE_CODE_MTFTP_LAST +} EFI_PXE_BASE_CODE_TFTP_OPCODE; + +/// +/// MTFTP information. This information is required +/// to start or join a multicast TFTP session. It is also required to +/// perform the "get file size" and "read directory" operations of MTFTP. +/// +typedef struct { + EFI_IP_ADDRESS MCastIp; + EFI_PXE_BASE_CODE_UDP_PORT CPort; + EFI_PXE_BASE_CODE_UDP_PORT SPort; + UINT16 ListenTimeout; + UINT16 TransmitTimeout; +} EFI_PXE_BASE_CODE_MTFTP_INFO; + +/// +/// DHCPV4 Packet structure. +/// +typedef struct { + UINT8 BootpOpcode; + UINT8 BootpHwType; + UINT8 BootpHwAddrLen; + UINT8 BootpGateHops; + UINT32 BootpIdent; + UINT16 BootpSeconds; + UINT16 BootpFlags; + UINT8 BootpCiAddr[4]; + UINT8 BootpYiAddr[4]; + UINT8 BootpSiAddr[4]; + UINT8 BootpGiAddr[4]; + UINT8 BootpHwAddr[16]; + UINT8 BootpSrvName[64]; + UINT8 BootpBootFile[128]; + UINT32 DhcpMagik; + UINT8 DhcpOptions[56]; +} EFI_PXE_BASE_CODE_DHCPV4_PACKET; + +/// +/// DHCPV6 Packet structure. +/// +typedef struct { + UINT32 MessageType:8; + UINT32 TransactionId:24; + UINT8 DhcpOptions[1024]; +} EFI_PXE_BASE_CODE_DHCPV6_PACKET; + +/// +/// Packet structure. +/// +typedef union { + UINT8 Raw[1472]; + EFI_PXE_BASE_CODE_DHCPV4_PACKET Dhcpv4; + EFI_PXE_BASE_CODE_DHCPV6_PACKET Dhcpv6; +} EFI_PXE_BASE_CODE_PACKET; + +// +// PXE Base Code Mode structure +// +#define EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 +#define EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 + +/// +/// EFI_PXE_BASE_CODE_MODE. +/// The data values in this structure are read-only and +/// are updated by the code that produces the +/// EFI_PXE_BASE_CODE_PROTOCOL functions. +/// +typedef struct { + BOOLEAN Started; + BOOLEAN Ipv6Available; + BOOLEAN Ipv6Supported; + BOOLEAN UsingIpv6; + BOOLEAN BisSupported; + BOOLEAN BisDetected; + BOOLEAN AutoArp; + BOOLEAN SendGUID; + BOOLEAN DhcpDiscoverValid; + BOOLEAN DhcpAckReceived; + BOOLEAN ProxyOfferReceived; + BOOLEAN PxeDiscoverValid; + BOOLEAN PxeReplyReceived; + BOOLEAN PxeBisReplyReceived; + BOOLEAN IcmpErrorReceived; + BOOLEAN TftpErrorReceived; + BOOLEAN MakeCallbacks; + UINT8 TTL; + UINT8 ToS; + EFI_IP_ADDRESS StationIp; + EFI_IP_ADDRESS SubnetMask; + EFI_PXE_BASE_CODE_PACKET DhcpDiscover; + EFI_PXE_BASE_CODE_PACKET DhcpAck; + EFI_PXE_BASE_CODE_PACKET ProxyOffer; + EFI_PXE_BASE_CODE_PACKET PxeDiscover; + EFI_PXE_BASE_CODE_PACKET PxeReply; + EFI_PXE_BASE_CODE_PACKET PxeBisReply; + EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + UINT32 ArpCacheEntries; + EFI_PXE_BASE_CODE_ARP_ENTRY ArpCache[EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; + UINT32 RouteTableEntries; + EFI_PXE_BASE_CODE_ROUTE_ENTRY RouteTable[EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + EFI_PXE_BASE_CODE_ICMP_ERROR IcmpError; + EFI_PXE_BASE_CODE_TFTP_ERROR TftpError; +} EFI_PXE_BASE_CODE_MODE; + +// +// PXE Base Code Interface Function definitions +// + +/** + Enables the use of the PXE Base Code Protocol functions. + + This function enables the use of the PXE Base Code Protocol functions. If the + Started field of the EFI_PXE_BASE_CODE_MODE structure is already TRUE, then + EFI_ALREADY_STARTED will be returned. If UseIpv6 is TRUE, then IPv6 formatted + addresses will be used in this session. If UseIpv6 is FALSE, then IPv4 formatted + addresses will be used in this session. If UseIpv6 is TRUE, and the Ipv6Supported + field of the EFI_PXE_BASE_CODE_MODE structure is FALSE, then EFI_UNSUPPORTED will + be returned. If there is not enough memory or other resources to start the PXE + Base Code Protocol, then EFI_OUT_OF_RESOURCES will be returned. Otherwise, the + PXE Base Code Protocol will be started, and all of the fields of the EFI_PXE_BASE_CODE_MODE + structure will be initialized as follows: + StartedSet to TRUE. + Ipv6SupportedUnchanged. + Ipv6AvailableUnchanged. + UsingIpv6Set to UseIpv6. + BisSupportedUnchanged. + BisDetectedUnchanged. + AutoArpSet to TRUE. + SendGUIDSet to FALSE. + TTLSet to DEFAULT_TTL. + ToSSet to DEFAULT_ToS. + DhcpCompletedSet to FALSE. + ProxyOfferReceivedSet to FALSE. + StationIpSet to an address of all zeros. + SubnetMaskSet to a subnet mask of all zeros. + DhcpDiscoverZero-filled. + DhcpAckZero-filled. + ProxyOfferZero-filled. + PxeDiscoverValidSet to FALSE. + PxeDiscoverZero-filled. + PxeReplyValidSet to FALSE. + PxeReplyZero-filled. + PxeBisReplyValidSet to FALSE. + PxeBisReplyZero-filled. + IpFilterSet the Filters field to 0 and the IpCnt field to 0. + ArpCacheEntriesSet to 0. + ArpCacheZero-filled. + RouteTableEntriesSet to 0. + RouteTableZero-filled. + IcmpErrorReceivedSet to FALSE. + IcmpErrorZero-filled. + TftpErroReceivedSet to FALSE. + TftpErrorZero-filled. + MakeCallbacksSet to TRUE if the PXE Base Code Callback Protocol is available. + Set to FALSE if the PXE Base Code Callback Protocol is not available. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param UseIpv6 Specifies the type of IP addresses that are to be used during the session + that is being started. Set to TRUE for IPv6 addresses, and FALSE for + IPv4 addresses. + + @retval EFI_SUCCESS The PXE Base Code Protocol was started. + @retval EFI_DEVICE_ERROR The network device encountered an error during this oper + @retval EFI_UNSUPPORTED UseIpv6 is TRUE, but the Ipv6Supported field of the + EFI_PXE_BASE_CODE_MODE structure is FALSE. + @retval EFI_ALREADY_STARTED The PXE Base Code Protocol is already in the started state. + @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough memory or other resources to start the + PXE Base Code Protocol. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_START)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN UseIpv6 + ); + +/** + Disables the use of the PXE Base Code Protocol functions. + + This function stops all activity on the network device. All the resources allocated + in Start() are released, the Started field of the EFI_PXE_BASE_CODE_MODE structure is + set to FALSE and EFI_SUCCESS is returned. If the Started field of the EFI_PXE_BASE_CODE_MODE + structure is already FALSE, then EFI_NOT_STARTED will be returned. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + + @retval EFI_SUCCESS The PXE Base Code Protocol was stopped. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is already in the stopped state. + @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The network device encountered an error during this operation. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_STOP)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This + ); + +/** + Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / acknowledge) or DHCPv6 + S.A.R.R (solicit / advertise / request / reply) sequence. + + This function attempts to complete the DHCP sequence. If this sequence is completed, + then EFI_SUCCESS is returned, and the DhcpCompleted, ProxyOfferReceived, StationIp, + SubnetMask, DhcpDiscover, DhcpAck, and ProxyOffer fields of the EFI_PXE_BASE_CODE_MODE + structure are filled in. + If SortOffers is TRUE, then the cached DHCP offer packets will be sorted before + they are tried. If SortOffers is FALSE, then the cached DHCP offer packets will + be tried in the order in which they are received. Please see the Preboot Execution + Environment (PXE) Specification for additional details on the implementation of DHCP. + This function can take at least 31 seconds to timeout and return control to the + caller. If the DHCP sequence does not complete, then EFI_TIMEOUT will be returned. + If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, + then the DHCP sequence will be stopped and EFI_ABORTED will be returned. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param SortOffers TRUE if the offers received should be sorted. Set to FALSE to try the + offers in the order that they are received. + + @retval EFI_SUCCESS Valid DHCP has completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The network device encountered an error during this operation. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough memory to complete the DHCP Protocol. + @retval EFI_ABORTED The callback function aborted the DHCP Protocol. + @retval EFI_TIMEOUT The DHCP Protocol timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during the DHCP session. + @retval EFI_NO_RESPONSE Valid PXE offer was not received. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_DHCP)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN SortOffers + ); + +/** + Attempts to complete the PXE Boot Server and/or boot image discovery sequence. + + This function attempts to complete the PXE Boot Server and/or boot image discovery + sequence. If this sequence is completed, then EFI_SUCCESS is returned, and the + PxeDiscoverValid, PxeDiscover, PxeReplyReceived, and PxeReply fields of the + EFI_PXE_BASE_CODE_MODE structure are filled in. If UseBis is TRUE, then the + PxeBisReplyReceived and PxeBisReply fields of the EFI_PXE_BASE_CODE_MODE structure + will also be filled in. If UseBis is FALSE, then PxeBisReplyValid will be set to FALSE. + In the structure referenced by parameter Info, the PXE Boot Server list, SrvList[], + has two uses: It is the Boot Server IP address list used for unicast discovery + (if the UseUCast field is TRUE), and it is the list used for Boot Server verification + (if the MustUseList field is TRUE). Also, if the MustUseList field in that structure + is TRUE and the AcceptAnyResponse field in the SrvList[] array is TRUE, any Boot + Server reply of that type will be accepted. If the AcceptAnyResponse field is + FALSE, only responses from Boot Servers with matching IP addresses will be accepted. + This function can take at least 10 seconds to timeout and return control to the + caller. If the Discovery sequence does not complete, then EFI_TIMEOUT will be + returned. Please see the Preboot Execution Environment (PXE) Specification for + additional details on the implementation of the Discovery sequence. + If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, + then the Discovery sequence is stopped and EFI_ABORTED will be returned. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param Type The type of bootstrap to perform. + @param Layer The pointer to the boot server layer number to discover, which must be + PXE_BOOT_LAYER_INITIAL when a new server type is being + discovered. + @param UseBis TRUE if Boot Integrity Services are to be used. FALSE otherwise. + @param Info The pointer to a data structure that contains additional information on the + type of discovery operation that is to be performed. + + @retval EFI_SUCCESS The Discovery sequence has been completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error during this operation. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough memory to complete Discovery. + @retval EFI_ABORTED The callback function aborted the Discovery sequence. + @retval EFI_TIMEOUT The Discovery sequence timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during the PXE discovery + session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_DISCOVER)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_PXE_BASE_CODE_DISCOVER_INFO *Info OPTIONAL + ); + +/** + Used to perform TFTP and MTFTP services. + + This function is used to perform TFTP and MTFTP services. This includes the + TFTP operations to get the size of a file, read a directory, read a file, and + write a file. It also includes the MTFTP operations to get the size of a file, + read a directory, and read a file. The type of operation is specified by Operation. + If the callback function that is invoked during the TFTP/MTFTP operation does + not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will + be returned. + For read operations, the return data will be placed in the buffer specified by + BufferPtr. If BufferSize is too small to contain the entire downloaded file, + then EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero + or the size of the requested file (the size of the requested file is only returned + if the TFTP server supports TFTP options). If BufferSize is large enough for the + read operation, then BufferSize will be set to the size of the downloaded file, + and EFI_SUCCESS will be returned. Applications using the PxeBc.Mtftp() services + should use the get-file-size operations to determine the size of the downloaded + file prior to using the read-file operations--especially when downloading large + (greater than 64 MB) files--instead of making two calls to the read-file operation. + Following this recommendation will save time if the file is larger than expected + and the TFTP server does not support TFTP option extensions. Without TFTP option + extension support, the client has to download the entire file, counting and discarding + the received packets, to determine the file size. + For write operations, the data to be sent is in the buffer specified by BufferPtr. + BufferSize specifies the number of bytes to send. If the write operation completes + successfully, then EFI_SUCCESS will be returned. + For TFTP "get file size" operations, the size of the requested file or directory + is returned in BufferSize, and EFI_SUCCESS will be returned. If the TFTP server + does not support options, the file will be downloaded into a bit bucket and the + length of the downloaded file will be returned. For MTFTP "get file size" operations, + if the MTFTP server does not support the "get file size" option, EFI_UNSUPPORTED + will be returned. + This function can take up to 10 seconds to timeout and return control to the caller. + If the TFTP sequence does not complete, EFI_TIMEOUT will be returned. + If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, + then the TFTP sequence is stopped and EFI_ABORTED will be returned. + The format of the data returned from a TFTP read directory operation is a null-terminated + filename followed by a null-terminated information string, of the form + "size year-month-day hour:minute:second" (i.e. %d %d-%d-%d %d:%d:%f - note that + the seconds field can be a decimal number), where the date and time are UTC. For + an MTFTP read directory command, there is additionally a null-terminated multicast + IP address preceding the filename of the form %d.%d.%d.%d for IP v4. The final + entry is itself null-terminated, so that the final information string is terminated + with two null octets. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param Operation The type of operation to perform. + @param BufferPtr A pointer to the data buffer. + @param Overwrite Only used on write file operations. TRUE if a file on a remote server can + be overwritten. + @param BufferSize For get-file-size operations, *BufferSize returns the size of the + requested file. + @param BlockSize The requested block size to be used during a TFTP transfer. + @param ServerIp The TFTP / MTFTP server IP address. + @param Filename A Null-terminated ASCII string that specifies a directory name or a file + name. + @param Info The pointer to the MTFTP information. + @param DontUseBuffer Set to FALSE for normal TFTP and MTFTP read file operation. + + @retval EFI_SUCCESS The TFTP/MTFTP operation was completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error during this operation. + @retval EFI_BUFFER_TOO_SMALL The buffer is not large enough to complete the read operation. + @retval EFI_ABORTED The callback function aborted the TFTP/MTFTP operation. + @retval EFI_TIMEOUT The TFTP/MTFTP operation timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during the MTFTP session. + @retval EFI_TFTP_ERROR A TFTP error packet was received during the MTFTP session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_MTFTP)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS *ServerIp, + IN UINT8 *Filename OPTIONAL, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ); + +/** + Writes a UDP packet to the network interface. + + This function writes a UDP packet specified by the (optional HeaderPtr and) + BufferPtr parameters to the network interface. The UDP header is automatically + built by this routine. It uses the parameters OpFlags, DestIp, DestPort, GatewayIp, + SrcIp, and SrcPort to build this header. If the packet is successfully built and + transmitted through the network interface, then EFI_SUCCESS will be returned. + If a timeout occurs during the transmission of the packet, then EFI_TIMEOUT will + be returned. If an ICMP error occurs during the transmission of the packet, then + the IcmpErrorReceived field is set to TRUE, the IcmpError field is filled in and + EFI_ICMP_ERROR will be returned. If the Callback Protocol does not return + EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will be returned. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param OpFlags The UDP operation flags. + @param DestIp The destination IP address. + @param DestPort The destination UDP port number. + @param GatewayIp The gateway IP address. + @param SrcIp The source IP address. + @param SrcPort The source UDP port number. + @param HeaderSize An optional field which may be set to the length of a header at + HeaderPtr to be prefixed to the data at BufferPtr. + @param HeaderPtr If HeaderSize is not NULL, a pointer to a header to be prefixed to the + data at BufferPtr. + @param BufferSize A pointer to the size of the data at BufferPtr. + @param BufferPtr A pointer to the data to be written. + + @retval EFI_SUCCESS The UDP Write operation was completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_BAD_BUFFER_SIZE The buffer is too long to be transmitted. + @retval EFI_ABORTED The callback function aborted the UDP Write operation. + @retval EFI_TIMEOUT The UDP Write operation timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during the UDP write session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_UDP_WRITE)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN EFI_IP_ADDRESS *DestIp, + IN EFI_PXE_BASE_CODE_UDP_PORT *DestPort, + IN EFI_IP_ADDRESS *GatewayIp, OPTIONAL + IN EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN UINTN *BufferSize, + IN VOID *BufferPtr + ); + +/** + Reads a UDP packet from the network interface. + + This function reads a UDP packet from a network interface. The data contents + are returned in (the optional HeaderPtr and) BufferPtr, and the size of the + buffer received is returned in BufferSize. If the input BufferSize is smaller + than the UDP packet received (less optional HeaderSize), it will be set to the + required size, and EFI_BUFFER_TOO_SMALL will be returned. In this case, the + contents of BufferPtr are undefined, and the packet is lost. If a UDP packet is + successfully received, then EFI_SUCCESS will be returned, and the information + from the UDP header will be returned in DestIp, DestPort, SrcIp, and SrcPort if + they are not NULL. + Depending on the values of OpFlags and the DestIp, DestPort, SrcIp, and SrcPort + input values, different types of UDP packet receive filtering will be performed. + The following tables summarize these receive filter operations. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param OpFlags The UDP operation flags. + @param DestIp The destination IP address. + @param DestPort The destination UDP port number. + @param SrcIp The source IP address. + @param SrcPort The source UDP port number. + @param HeaderSize An optional field which may be set to the length of a header at + HeaderPtr to be prefixed to the data at BufferPtr. + @param HeaderPtr If HeaderSize is not NULL, a pointer to a header to be prefixed to the + data at BufferPtr. + @param BufferSize A pointer to the size of the data at BufferPtr. + @param BufferPtr A pointer to the data to be read. + + @retval EFI_SUCCESS The UDP Read operation was completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error during this operation. + @retval EFI_BUFFER_TOO_SMALL The packet is larger than Buffer can hold. + @retval EFI_ABORTED The callback function aborted the UDP Read operation. + @retval EFI_TIMEOUT The UDP Read operation timed out. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_UDP_READ)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN UINT16 OpFlags, + IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL + IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL + IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL + IN UINTN *HeaderSize, OPTIONAL + IN VOID *HeaderPtr, OPTIONAL + IN OUT UINTN *BufferSize, + IN VOID *BufferPtr + ); + +/** + Updates the IP receive filters of a network device and enables software filtering. + + The NewFilter field is used to modify the network device's current IP receive + filter settings and to enable a software filter. This function updates the IpFilter + field of the EFI_PXE_BASE_CODE_MODE structure with the contents of NewIpFilter. + The software filter is used when the USE_FILTER in OpFlags is set to UdpRead(). + The current hardware filter remains in effect no matter what the settings of OpFlags + are, so that the meaning of ANY_DEST_IP set in OpFlags to UdpRead() is from those + packets whose reception is enabled in hardware - physical NIC address (unicast), + broadcast address, logical address or addresses (multicast), or all (promiscuous). + UdpRead() does not modify the IP filter settings. + Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP receive + filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP. + If an application or driver wishes to preserve the IP receive filter settings, + it will have to preserve the IP receive filter settings before these calls, and + use SetIpFilter() to restore them after the calls. If incompatible filtering is + requested (for example, PROMISCUOUS with anything else), or if the device does not + support a requested filter setting and it cannot be accommodated in software + (for example, PROMISCUOUS not supported), EFI_INVALID_PARAMETER will be returned. + The IPlist field is used to enable IPs other than the StationIP. They may be + multicast or unicast. If IPcnt is set as well as EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP, + then both the StationIP and the IPs from the IPlist will be used. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param NewFilter The pointer to the new set of IP receive filters. + + @retval EFI_SUCCESS The IP receive filter settings were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_IP_FILTER)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter + ); + +/** + Uses the ARP protocol to resolve a MAC address. + + This function uses the ARP protocol to resolve a MAC address. The UsingIpv6 field + of the EFI_PXE_BASE_CODE_MODE structure is used to determine if IPv4 or IPv6 + addresses are being used. The IP address specified by IpAddr is used to resolve + a MAC address. If the ARP protocol succeeds in resolving the specified address, + then the ArpCacheEntries and ArpCache fields of the EFI_PXE_BASE_CODE_MODE structure + are updated, and EFI_SUCCESS is returned. If MacAddr is not NULL, the resolved + MAC address is placed there as well. + If the PXE Base Code protocol is in the stopped state, then EFI_NOT_STARTED is + returned. If the ARP protocol encounters a timeout condition while attempting + to resolve an address, then EFI_TIMEOUT is returned. If the Callback Protocol + does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED is + returned. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param IpAddr The pointer to the IP address that is used to resolve a MAC address. + @param MacAddr If not NULL, a pointer to the MAC address that was resolved with the + ARP protocol. + + @retval EFI_SUCCESS The IP or MAC address was resolved. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error during this operation. + @retval EFI_ABORTED The callback function aborted the ARP Protocol. + @retval EFI_TIMEOUT The ARP Protocol encountered a timeout condition. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_ARP)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_IP_ADDRESS *IpAddr, + IN EFI_MAC_ADDRESS *MacAddr OPTIONAL + ); + +/** + Updates the parameters that affect the operation of the PXE Base Code Protocol. + + This function sets parameters that affect the operation of the PXE Base Code Protocol. + The parameter specified by NewAutoArp is used to control the generation of ARP + protocol packets. If NewAutoArp is TRUE, then ARP Protocol packets will be generated + as required by the PXE Base Code Protocol. If NewAutoArp is FALSE, then no ARP + Protocol packets will be generated. In this case, the only mappings that are + available are those stored in the ArpCache of the EFI_PXE_BASE_CODE_MODE structure. + If there are not enough mappings in the ArpCache to perform a PXE Base Code Protocol + service, then the service will fail. This function updates the AutoArp field of + the EFI_PXE_BASE_CODE_MODE structure to NewAutoArp. + The SetParameters() call must be invoked after a Callback Protocol is installed + to enable the use of callbacks. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param NewAutoArp If not NULL, a pointer to a value that specifies whether to replace the + current value of AutoARP. + @param NewSendGUID If not NULL, a pointer to a value that specifies whether to replace the + current value of SendGUID. + @param NewTTL If not NULL, a pointer to be used in place of the current value of TTL, + the "time to live" field of the IP header. + @param NewToS If not NULL, a pointer to be used in place of the current value of ToS, + the "type of service" field of the IP header. + @param NewMakeCallback If not NULL, a pointer to a value that specifies whether to replace the + current value of the MakeCallback field of the Mode structure. + + @retval EFI_SUCCESS The new parameters values were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_PARAMETERS)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN *NewAutoArp, OPTIONAL + IN BOOLEAN *NewSendGUID, OPTIONAL + IN UINT8 *NewTTL, OPTIONAL + IN UINT8 *NewToS, OPTIONAL + IN BOOLEAN *NewMakeCallback OPTIONAL + ); + +/** + Updates the station IP address and/or subnet mask values of a network device. + + This function updates the station IP address and/or subnet mask values of a network + device. + The NewStationIp field is used to modify the network device's current IP address. + If NewStationIP is NULL, then the current IP address will not be modified. Otherwise, + this function updates the StationIp field of the EFI_PXE_BASE_CODE_MODE structure + with NewStationIp. + The NewSubnetMask field is used to modify the network device's current subnet + mask. If NewSubnetMask is NULL, then the current subnet mask will not be modified. + Otherwise, this function updates the SubnetMask field of the EFI_PXE_BASE_CODE_MODE + structure with NewSubnetMask. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param NewStationIp The pointer to the new IP address to be used by the network device. + @param NewSubnetMask The pointer to the new subnet mask to be used by the network device. + + @retval EFI_SUCCESS The new station IP address and/or subnet mask were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_STATION_IP)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ); + +/** + Updates the contents of the cached DHCP and Discover packets. + + The pointers to the new packets are used to update the contents of the cached + packets in the EFI_PXE_BASE_CODE_MODE structure. + + @param This The pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance. + @param NewDhcpDiscoverValid The pointer to a value that will replace the current + DhcpDiscoverValid field. + @param NewDhcpAckReceived The pointer to a value that will replace the current + DhcpAckReceived field. + @param NewProxyOfferReceived The pointer to a value that will replace the current + ProxyOfferReceived field. + @param NewPxeDiscoverValid The pointer to a value that will replace the current + ProxyOfferReceived field. + @param NewPxeReplyReceived The pointer to a value that will replace the current + PxeReplyReceived field. + @param NewPxeBisReplyReceived The pointer to a value that will replace the current + PxeBisReplyReceived field. + @param NewDhcpDiscover The pointer to the new cached DHCP Discover packet contents. + @param NewDhcpAck The pointer to the new cached DHCP Ack packet contents. + @param NewProxyOffer The pointer to the new cached Proxy Offer packet contents. + @param NewPxeDiscover The pointer to the new cached PXE Discover packet contents. + @param NewPxeReply The pointer to the new cached PXE Reply packet contents. + @param NewPxeBisReply The pointer to the new cached PXE BIS Reply packet contents. + + @retval EFI_SUCCESS The cached packet contents were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopped state. + @retval EFI_INVALID_PARAMETER This is NULL or not point to a valid EFI_PXE_BASE_CODE_PROTOCOL structure. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_PXE_BASE_CODE_SET_PACKETS)( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + BOOLEAN *NewDhcpDiscoverValid, OPTIONAL + BOOLEAN *NewDhcpAckReceived, OPTIONAL + BOOLEAN *NewProxyOfferReceived, OPTIONAL + BOOLEAN *NewPxeDiscoverValid, OPTIONAL + BOOLEAN *NewPxeReplyReceived, OPTIONAL + BOOLEAN *NewPxeBisReplyReceived, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewDhcpDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewDhcpAck, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewProxyOffer, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeDiscover, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeReply, OPTIONAL + IN EFI_PXE_BASE_CODE_PACKET *NewPxeBisReply OPTIONAL + ); + +// +// PXE Base Code Protocol structure +// +#define EFI_PXE_BASE_CODE_PROTOCOL_REVISION 0x00010000 + +// +// Revision defined in EFI1.1 +// +#define EFI_PXE_BASE_CODE_INTERFACE_REVISION EFI_PXE_BASE_CODE_PROTOCOL_REVISION + +/// +/// The EFI_PXE_BASE_CODE_PROTOCOL is used to control PXE-compatible devices. +/// An EFI_PXE_BASE_CODE_PROTOCOL will be layered on top of an +/// EFI_MANAGED_NETWORK_PROTOCOL protocol in order to perform packet level transactions. +/// The EFI_PXE_BASE_CODE_PROTOCOL handle also supports the +/// EFI_LOAD_FILE_PROTOCOL protocol. This provides a clean way to obtain control from the +/// boot manager if the boot path is from the remote device. +/// +struct _EFI_PXE_BASE_CODE_PROTOCOL { + /// + /// The revision of the EFI_PXE_BASE_CODE_PROTOCOL. All future revisions must + /// be backwards compatible. If a future version is not backwards compatible + /// it is not the same GUID. + /// + UINT64 Revision; + EFI_PXE_BASE_CODE_START Start; + EFI_PXE_BASE_CODE_STOP Stop; + EFI_PXE_BASE_CODE_DHCP Dhcp; + EFI_PXE_BASE_CODE_DISCOVER Discover; + EFI_PXE_BASE_CODE_MTFTP Mtftp; + EFI_PXE_BASE_CODE_UDP_WRITE UdpWrite; + EFI_PXE_BASE_CODE_UDP_READ UdpRead; + EFI_PXE_BASE_CODE_SET_IP_FILTER SetIpFilter; + EFI_PXE_BASE_CODE_ARP Arp; + EFI_PXE_BASE_CODE_SET_PARAMETERS SetParameters; + EFI_PXE_BASE_CODE_SET_STATION_IP SetStationIp; + EFI_PXE_BASE_CODE_SET_PACKETS SetPackets; + /// + /// The pointer to the EFI_PXE_BASE_CODE_MODE data for this device. + /// + EFI_PXE_BASE_CODE_MODE *Mode; +}; + +extern EFI_GUID gEfiPxeBaseCodeProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h index 198180864..b6bacfd9c 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h @@ -7,7 +7,7 @@ UEFI 2.0 can boot from any valid EFI image contained in a SimpleFileSystem. -Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -192,7 +192,7 @@ EFI_STATUS @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_BUFFER_TO_SMALL The BufferSize is too small to read the current directory + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. BufferSize has been updated with the size needed to complete the request. @@ -365,7 +365,164 @@ EFI_STATUS IN EFI_FILE_PROTOCOL *This ); -#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +typedef struct { + // + // If Event is NULL, then blocking I/O is performed. + // If Event is not NULL and non-blocking I/O is supported, then non-blocking I/O is performed, + // and Event will be signaled when the read request is completed. + // The caller must be prepared to handle the case where the callback associated with Event + // occurs before the original asynchronous I/O request call returns. + // + EFI_EVENT Event; + + // + // Defines whether or not the signaled event encountered an error. + // + EFI_STATUS Status; + + // + // For OpenEx(): Not Used, ignored. + // For ReadEx(): On input, the size of the Buffer. On output, the amount of data returned in Buffer. + // In both cases, the size is measured in bytes. + // For WriteEx(): On input, the size of the Buffer. On output, the amount of data actually written. + // In both cases, the size is measured in bytes. + // For FlushEx(): Not used, ignored. + // + UINTN BufferSize; + + // + // For OpenEx(): Not Used, ignored. + // For ReadEx(): The buffer into which the data is read. + // For WriteEx(): The buffer of data to write. + // For FlushEx(): Not Used, ignored. + // + VOID *Buffer; +} EFI_FILE_IO_TOKEN; + +/** + Opens a new file relative to the source directory's location. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to the source location. + @param NewHandle A pointer to the location to return the opened handle for the new + file. + @param FileName The Null-terminated string of the name of the file to be opened. + The file name may contain the following path modifiers: "\", ".", + and "..". + @param OpenMode The mode to open the file. The only valid combinations that the + file may be opened with are: Read, Read/Write, or Create/Read/Write. + @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the + attribute bits for the newly created file. + @param Token A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read successfully. + If Event is not NULL (asynchronous I/O): The request was successfully + queued for processing. + @retval EFI_NOT_FOUND The specified file could not be found on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_OPEN_EX)( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes, + IN OUT EFI_FILE_IO_TOKEN *Token + ); + + +/** + Reads data from a file. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to read data from. + @param Token A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read successfully. + If Event is not NULL (asynchronous I/O): The request was successfully + queued for processing. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. + @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_OUT_OF_RESOURCES Unable to queue the request due to lack of resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_READ_EX) ( + IN EFI_FILE_PROTOCOL *This, + IN OUT EFI_FILE_IO_TOKEN *Token +); + + +/** + Writes data to a file. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to write data to. + @param Token A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read successfully. + If Event is not NULL (asynchronous I/O): The request was successfully + queued for processing. + @retval EFI_UNSUPPORTED Writes to open directory files are not supported. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write-protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_OUT_OF_RESOURCES Unable to queue the request due to lack of resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_WRITE_EX) ( + IN EFI_FILE_PROTOCOL *This, + IN OUT EFI_FILE_IO_TOKEN *Token +); + +/** + Flushes all modified data associated with a file to a device. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to flush. + @param Token A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read successfully. + If Event is not NULL (asynchronous I/O): The request was successfully + queued for processing. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write-protected. + @retval EFI_ACCESS_DENIED The file was opened read-only. + @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_OUT_OF_RESOURCES Unable to queue the request due to lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_FLUSH_EX) ( + IN EFI_FILE_PROTOCOL *This, + IN OUT EFI_FILE_IO_TOKEN *Token + ); + +#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +#define EFI_FILE_PROTOCOL_REVISION2 0x00020000 +#define EFI_FILE_PROTOCOL_LATEST_REVISION EFI_FILE_PROTOCOL_REVISION2 + // // Revision defined in EFI1.1. // @@ -381,8 +538,8 @@ EFI_STATUS struct _EFI_FILE_PROTOCOL { /// /// The version of the EFI_FILE_PROTOCOL interface. The version specified - /// by this specification is 0x00010000. Future versions are required - /// to be backward compatible to version 1.0. + /// by this specification is EFI_FILE_PROTOCOL_LATEST_REVISION. + /// Future versions are required to be backward compatible to version 1.0. /// UINT64 Revision; EFI_FILE_OPEN Open; @@ -395,6 +552,10 @@ struct _EFI_FILE_PROTOCOL { EFI_FILE_GET_INFO GetInfo; EFI_FILE_SET_INFO SetInfo; EFI_FILE_FLUSH Flush; + EFI_FILE_OPEN_EX OpenEx; + EFI_FILE_READ_EX ReadEx; + EFI_FILE_WRITE_EX WriteEx; + EFI_FILE_FLUSH_EX FlushEx; }; diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/TcgService.h b/roms/ipxe/src/include/ipxe/efi/Protocol/TcgService.h new file mode 100644 index 000000000..1068448f0 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/TcgService.h @@ -0,0 +1,209 @@ +/** @file + TCG Service Protocol as defined in TCG_EFI_Protocol_1_20_Final + See http://trustedcomputinggroup.org for the latest specification + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TCG_SERVICE_PROTOCOL_H_ +#define _TCG_SERVICE_PROTOCOL_H_ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/IndustryStandard/UefiTcgPlatform.h> + +#define EFI_TCG_PROTOCOL_GUID \ + {0xf541796d, 0xa62e, 0x4954, { 0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd } } + +typedef struct _EFI_TCG_PROTOCOL EFI_TCG_PROTOCOL; + +typedef struct { + UINT8 Major; + UINT8 Minor; + UINT8 RevMajor; + UINT8 RevMinor; +} TCG_VERSION; + +typedef struct _TCG_EFI_BOOT_SERVICE_CAPABILITY { + UINT8 Size; /// Size of this structure. + TCG_VERSION StructureVersion; + TCG_VERSION ProtocolSpecVersion; + UINT8 HashAlgorithmBitmap; /// Hash algorithms . + /// This protocol is capable of : 01=SHA-1. + BOOLEAN TPMPresentFlag; /// 00h = TPM not present. + BOOLEAN TPMDeactivatedFlag; /// 01h = TPM currently deactivated. +} TCG_EFI_BOOT_SERVICE_CAPABILITY; + +typedef UINT32 TCG_ALGORITHM_ID; + +/// +/// Note: +/// Status codes returned for functions of EFI_TCG_PROTOCOL do not exactly match +/// those defined in the TCG EFI Protocol 1.20 Final Specification. +/// + +/** + This service provides EFI protocol capability information, state information + about the TPM, and Event Log state information. + + @param This Indicates the calling context + @param ProtocolCapability The callee allocates memory for a TCG_BOOT_SERVICE_CAPABILITY + structure and fills in the fields with the EFI protocol + capability information and the current TPM state information. + @param TCGFeatureFlags This is a pointer to the feature flags. No feature + flags are currently defined so this parameter + MUST be set to 0. However, in the future, + feature flags may be defined that, for example, + enable hash algorithm agility. + @param EventLogLocation This is a pointer to the address of the event log in memory. + @param EventLogLastEntry If the Event Log contains more than one entry, + this is a pointer to the address of the start of + the last entry in the event log in memory. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER ProtocolCapability does not match TCG capability. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG_STATUS_CHECK)( + IN EFI_TCG_PROTOCOL *This, + OUT TCG_EFI_BOOT_SERVICE_CAPABILITY + *ProtocolCapability, + OUT UINT32 *TCGFeatureFlags, + OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry + ); + +/** + This service abstracts the capability to do a hash operation on a data buffer. + + @param This Indicates the calling context. + @param HashData The pointer to the data buffer to be hashed. + @param HashDataLen The length of the data buffer to be hashed. + @param AlgorithmId Identification of the Algorithm to use for the hashing operation. + @param HashedDataLen Resultant length of the hashed data. + @param HashedDataResult Resultant buffer of the hashed data. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER HashDataLen is NULL. + @retval EFI_INVALID_PARAMETER HashDataLenResult is NULL. + @retval EFI_OUT_OF_RESOURCES Cannot allocate buffer of size *HashedDataLen. + @retval EFI_UNSUPPORTED AlgorithmId not supported. + @retval EFI_BUFFER_TOO_SMALL *HashedDataLen < sizeof (TCG_DIGEST). +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG_HASH_ALL)( + IN EFI_TCG_PROTOCOL *This, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN TCG_ALGORITHM_ID AlgorithmId, + IN OUT UINT64 *HashedDataLen, + IN OUT UINT8 **HashedDataResult + ); + +/** + This service abstracts the capability to add an entry to the Event Log. + + @param This Indicates the calling context + @param TCGLogData The pointer to the start of the data buffer containing + the TCG_PCR_EVENT data structure. All fields in + this structure are properly filled by the caller. + @param EventNumber The event number of the event just logged. + @param Flags Indicates additional flags. Only one flag has been + defined at this time, which is 0x01 and means the + extend operation should not be performed. All + other bits are reserved. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Insufficient memory in the event log to complete this action. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG_LOG_EVENT)( + IN EFI_TCG_PROTOCOL *This, + IN TCG_PCR_EVENT *TCGLogData, + IN OUT UINT32 *EventNumber, + IN UINT32 Flags + ); + +/** + This service is a proxy for commands to the TPM. + + @param This Indicates the calling context. + @param TpmInputParameterBlockSize Size of the TPM input parameter block. + @param TpmInputParameterBlock The pointer to the TPM input parameter block. + @param TpmOutputParameterBlockSize Size of the TPM output parameter block. + @param TpmOutputParameterBlock The pointer to the TPM output parameter block. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Invalid ordinal. + @retval EFI_UNSUPPORTED Current Task Priority Level >= EFI_TPL_CALLBACK. + @retval EFI_TIMEOUT The TIS timed-out. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG_PASS_THROUGH_TO_TPM)( + IN EFI_TCG_PROTOCOL *This, + IN UINT32 TpmInputParameterBlockSize, + IN UINT8 *TpmInputParameterBlock, + IN UINT32 TpmOutputParameterBlockSize, + IN UINT8 *TpmOutputParameterBlock + ); + +/** + This service abstracts the capability to do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, and add an entry to the Event Log + + @param This Indicates the calling context + @param HashData The physical address of the start of the data buffer + to be hashed, extended, and logged. + @param HashDataLen The length, in bytes, of the buffer referenced by HashData + @param AlgorithmId Identification of the Algorithm to use for the hashing operation + @param TCGLogData The physical address of the start of the data + buffer containing the TCG_PCR_EVENT data structure. + @param EventNumber The event number of the event just logged. + @param EventLogLastEntry The physical address of the first byte of the entry + just placed in the Event Log. If the Event Log was + empty when this function was called then this physical + address will be the same as the physical address of + the start of the Event Log. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED AlgorithmId != TPM_ALG_SHA. + @retval EFI_UNSUPPORTED Current TPL >= EFI_TPL_CALLBACK. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCG_HASH_LOG_EXTEND_EVENT)( + IN EFI_TCG_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS HashData, + IN UINT64 HashDataLen, + IN TCG_ALGORITHM_ID AlgorithmId, + IN OUT TCG_PCR_EVENT *TCGLogData, + IN OUT UINT32 *EventNumber, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry + ); + +/// +/// The EFI_TCG Protocol abstracts TCG activity. +/// +struct _EFI_TCG_PROTOCOL { + EFI_TCG_STATUS_CHECK StatusCheck; + EFI_TCG_HASH_ALL HashAll; + EFI_TCG_LOG_EVENT LogEvent; + EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTpm; + EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; +}; + +extern EFI_GUID gEfiTcgProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Tcp4.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Tcp4.h new file mode 100644 index 000000000..1771bc55f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Tcp4.h @@ -0,0 +1,579 @@ +/** @file + EFI TCPv4(Transmission Control Protocol version 4) Protocol Definition + The EFI TCPv4 Service Binding Protocol is used to locate EFI TCPv4 Protocol drivers to create + and destroy child of the driver to communicate with other host using TCP protocol. + The EFI TCPv4 Protocol provides services to send and receive data stream. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.0. + +**/ + +#ifndef __EFI_TCP4_PROTOCOL_H__ +#define __EFI_TCP4_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/Protocol/Ip4.h> + +#define EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x00720665, 0x67EB, 0x4a99, {0xBA, 0xF7, 0xD3, 0xC3, 0x3A, 0x1C, 0x7C, 0xC9 } \ + } + +#define EFI_TCP4_PROTOCOL_GUID \ + { \ + 0x65530BC7, 0xA359, 0x410f, {0xB0, 0x10, 0x5A, 0xAD, 0xC7, 0xEC, 0x2B, 0x62 } \ + } + +typedef struct _EFI_TCP4_PROTOCOL EFI_TCP4_PROTOCOL; + +/// +/// EFI_TCP4_SERVICE_POINT is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE InstanceHandle; + EFI_IPv4_ADDRESS LocalAddress; + UINT16 LocalPort; + EFI_IPv4_ADDRESS RemoteAddress; + UINT16 RemotePort; +} EFI_TCP4_SERVICE_POINT; + +/// +/// EFI_TCP4_VARIABLE_DATA is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE DriverHandle; + UINT32 ServiceCount; + EFI_TCP4_SERVICE_POINT Services[1]; +} EFI_TCP4_VARIABLE_DATA; + +typedef struct { + BOOLEAN UseDefaultAddress; + EFI_IPv4_ADDRESS StationAddress; + EFI_IPv4_ADDRESS SubnetMask; + UINT16 StationPort; + EFI_IPv4_ADDRESS RemoteAddress; + UINT16 RemotePort; + BOOLEAN ActiveFlag; +} EFI_TCP4_ACCESS_POINT; + +typedef struct { + UINT32 ReceiveBufferSize; + UINT32 SendBufferSize; + UINT32 MaxSynBackLog; + UINT32 ConnectionTimeout; + UINT32 DataRetries; + UINT32 FinTimeout; + UINT32 TimeWaitTimeout; + UINT32 KeepAliveProbes; + UINT32 KeepAliveTime; + UINT32 KeepAliveInterval; + BOOLEAN EnableNagle; + BOOLEAN EnableTimeStamp; + BOOLEAN EnableWindowScaling; + BOOLEAN EnableSelectiveAck; + BOOLEAN EnablePathMtuDiscovery; +} EFI_TCP4_OPTION; + +typedef struct { + // + // I/O parameters + // + UINT8 TypeOfService; + UINT8 TimeToLive; + + // + // Access Point + // + EFI_TCP4_ACCESS_POINT AccessPoint; + + // + // TCP Control Options + // + EFI_TCP4_OPTION *ControlOption; +} EFI_TCP4_CONFIG_DATA; + +/// +/// TCP4 connnection state +/// +typedef enum { + Tcp4StateClosed = 0, + Tcp4StateListen = 1, + Tcp4StateSynSent = 2, + Tcp4StateSynReceived = 3, + Tcp4StateEstablished = 4, + Tcp4StateFinWait1 = 5, + Tcp4StateFinWait2 = 6, + Tcp4StateClosing = 7, + Tcp4StateTimeWait = 8, + Tcp4StateCloseWait = 9, + Tcp4StateLastAck = 10 +} EFI_TCP4_CONNECTION_STATE; + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; +} EFI_TCP4_COMPLETION_TOKEN; + +typedef struct { + /// + /// The Status in the CompletionToken will be set to one of + /// the following values if the active open succeeds or an unexpected + /// error happens: + /// EFI_SUCCESS: The active open succeeds and the instance's + /// state is Tcp4StateEstablished. + /// EFI_CONNECTION_RESET: The connect fails because the connection is reset + /// either by instance itself or the communication peer. + /// EFI_CONNECTION_REFUSED: The connect fails because this connection is initiated with + /// an active open and the connection is refused. + /// EFI_ABORTED: The active open is aborted. + /// EFI_TIMEOUT: The connection establishment timer expires and + /// no more specific information is available. + /// EFI_NETWORK_UNREACHABLE: The active open fails because + /// an ICMP network unreachable error is received. + /// EFI_HOST_UNREACHABLE: The active open fails because an + /// ICMP host unreachable error is received. + /// EFI_PROTOCOL_UNREACHABLE: The active open fails + /// because an ICMP protocol unreachable error is received. + /// EFI_PORT_UNREACHABLE: The connection establishment + /// timer times out and an ICMP port unreachable error is received. + /// EFI_ICMP_ERROR: The connection establishment timer timeout and some other ICMP + /// error is received. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// EFI_NO_MEDIA: There was a media error. + /// + EFI_TCP4_COMPLETION_TOKEN CompletionToken; +} EFI_TCP4_CONNECTION_TOKEN; + +typedef struct { + EFI_TCP4_COMPLETION_TOKEN CompletionToken; + EFI_HANDLE NewChildHandle; +} EFI_TCP4_LISTEN_TOKEN; + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_TCP4_FRAGMENT_DATA; + +typedef struct { + BOOLEAN UrgentFlag; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP4_RECEIVE_DATA; + +typedef struct { + BOOLEAN Push; + BOOLEAN Urgent; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_TCP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP4_TRANSMIT_DATA; + +typedef struct { + /// + /// When transmission finishes or meets any unexpected error it will + /// be set to one of the following values: + /// EFI_SUCCESS: The receiving or transmission operation + /// completes successfully. + /// EFI_CONNECTION_FIN: The receiving operation fails because the communication peer + /// has closed the connection and there is no more data in the + /// receive buffer of the instance. + /// EFI_CONNECTION_RESET: The receiving or transmission operation fails + /// because this connection is reset either by instance + /// itself or the communication peer. + /// EFI_ABORTED: The receiving or transmission is aborted. + /// EFI_TIMEOUT: The transmission timer expires and no more + /// specific information is available. + /// EFI_NETWORK_UNREACHABLE: The transmission fails + /// because an ICMP network unreachable error is received. + /// EFI_HOST_UNREACHABLE: The transmission fails because an + /// ICMP host unreachable error is received. + /// EFI_PROTOCOL_UNREACHABLE: The transmission fails + /// because an ICMP protocol unreachable error is received. + /// EFI_PORT_UNREACHABLE: The transmission fails and an + /// ICMP port unreachable error is received. + /// EFI_ICMP_ERROR: The transmission fails and some other + /// ICMP error is received. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurs. + /// EFI_NO_MEDIA: There was a media error. + /// + EFI_TCP4_COMPLETION_TOKEN CompletionToken; + union { + /// + /// When this token is used for receiving, RxData is a pointer to EFI_TCP4_RECEIVE_DATA. + /// + EFI_TCP4_RECEIVE_DATA *RxData; + /// + /// When this token is used for transmitting, TxData is a pointer to EFI_TCP4_TRANSMIT_DATA. + /// + EFI_TCP4_TRANSMIT_DATA *TxData; + } Packet; +} EFI_TCP4_IO_TOKEN; + +typedef struct { + EFI_TCP4_COMPLETION_TOKEN CompletionToken; + BOOLEAN AbortOnClose; +} EFI_TCP4_CLOSE_TOKEN; + +// +// Interface definition for TCP4 protocol +// + +/** + Get the current operational status. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param Tcp4State The pointer to the buffer to receive the current TCP state. + @param Tcp4ConfigData The pointer to the buffer to receive the current TCP configuration. + @param Ip4ModeData The pointer to the buffer to receive the current IPv4 configuration + data used by the TCPv4 instance. + @param MnpConfigData The pointer to the buffer to receive the current MNP configuration + data used indirectly by the TCPv4 instance. + @param SnpModeData The pointer to the buffer to receive the current SNP configuration + data used indirectly by the TCPv4 instance. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED No configuration data is available because this instance hasn't + been started. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_GET_MODE_DATA)( + IN EFI_TCP4_PROTOCOL *This, + OUT EFI_TCP4_CONNECTION_STATE *Tcp4State OPTIONAL, + OUT EFI_TCP4_CONFIG_DATA *Tcp4ConfigData OPTIONAL, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Initialize or brutally reset the operational parameters for this EFI TCPv4 instance. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param Tcp4ConfigData The pointer to the configure data to configure the instance. + + @retval EFI_SUCCESS The operational settings are set, changed, or reset + successfully. + @retval EFI_INVALID_PARAMETER Some parameter is invalid. + @retval EFI_NO_MAPPING When using a default address, configuration (through + DHCP, BOOTP, RARP, etc.) is not finished yet. + @retval EFI_ACCESS_DENIED Configuring TCP instance when it is configured without + calling Configure() with NULL to reset it. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_UNSUPPORTED One or more of the control options are not supported in + the implementation. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when + executing Configure(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CONFIGURE)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_CONFIG_DATA *TcpConfigData OPTIONAL + ); + + +/** + Add or delete a route entry to the route table + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param DeleteRoute Set it to TRUE to delete this route from the routing table. Set it to + FALSE to add this route to the routing table. + DestinationAddress and SubnetMask are used as the + keywords to search route entry. + @param SubnetAddress The destination network. + @param SubnetMask The subnet mask of the destination network. + @param GatewayAddress The gateway address for this route. It must be on the same + subnet with the station address unless a direct route is specified. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI TCPv4 Protocol instance has not been configured. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - SubnetAddress is NULL. + - SubnetMask is NULL. + - GatewayAddress is NULL. + - *SubnetAddress is not NULL a valid subnet address. + - *SubnetMask is not a valid subnet mask. + - *GatewayAddress is not a valid unicast IP address or it + is not in the same subnet. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough resources to add the entry to the + routing table. + @retval EFI_NOT_FOUND This route is not in the routing table. + @retval EFI_ACCESS_DENIED The route is already defined in the routing table. + @retval EFI_UNSUPPORTED The TCP driver does not support this operation. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_ROUTES)( + IN EFI_TCP4_PROTOCOL *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ); + +/** + Initiate a nonblocking TCP connection request for an active TCP instance. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param ConnectionToken The pointer to the connection token to return when the TCP three + way handshake finishes. + + @retval EFI_SUCCESS The connection request is successfully initiated and the state + of this TCPv4 instance has been changed to Tcp4StateSynSent. + @retval EFI_NOT_STARTED This EFI TCPv4 Protocol instance has not been configured. + @retval EFI_ACCESS_DENIED One or more of the following conditions are TRUE: + - This instance is not configured as an active one. + - This instance is not in Tcp4StateClosed state. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - ConnectionToken is NULL. + - ConnectionToken->CompletionToken.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The driver can't allocate enough resource to initiate the activ eopen. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CONNECT)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_CONNECTION_TOKEN *ConnectionToken + ); + + +/** + Listen on the passive instance to accept an incoming connection request. This is a nonblocking operation. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param ListenToken The pointer to the listen token to return when operation finishes. + + @retval EFI_SUCCESS The listen token has been queued successfully. + @retval EFI_NOT_STARTED This EFI TCPv4 Protocol instance has not been configured. + @retval EFI_ACCESS_DENIED One or more of the following are TRUE: + - This instance is not a passive instance. + - This instance is not in Tcp4StateListen state. + - The same listen token has already existed in the listen + token queue of this TCP instance. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - ListenToken is NULL. + - ListentToken->CompletionToken.Event is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough resource to finish the operation. + @retval EFI_DEVICE_ERROR Any unexpected and not belonged to above category error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_ACCEPT)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_LISTEN_TOKEN *ListenToken + ); + +/** + Queues outgoing data into the transmit queue. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param Token The pointer to the completion token to queue to the transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI TCPv4 Protocol instance has not been configured. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - Token is NULL. + - Token->CompletionToken.Event is NULL. + - Token->Packet.TxData is NULL L. + - Token->Packet.FragmentCount is zero. + - Token->Packet.DataLength is not equal to the sum of fragment lengths. + @retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE: + - A transmit completion token with the same Token->CompletionToken.Event + was already in the transmission queue. + - The current instance is in Tcp4StateClosed state. + - The current instance is a passive one and it is in + Tcp4StateListen state. + - User has called Close() to disconnect this connection. + @retval EFI_NOT_READY The completion token could not be queued because the + transmit queue is full. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data because of resource + shortage. + @retval EFI_NETWORK_UNREACHABLE There is no route to the destination network or address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_TRANSMIT)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_IO_TOKEN *Token + ); + + +/** + Places an asynchronous receive request into the receiving queue. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param Token The pointer to a token that is associated with the receive data + descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI TCPv4 Protocol instance has not been configured. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, RARP, + etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token->CompletionToken.Event is NULL. + - Token->Packet.RxData is NULL. + - Token->Packet.RxData->DataLength is 0. + - The Token->Packet.RxData->DataLength is not + the sum of all FragmentBuffer length in FragmentTable. + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of + system resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE: + - A receive completion token with the same Token- + >CompletionToken.Event was already in the receive + queue. + - The current instance is in Tcp4StateClosed state. + - The current instance is a passive one and it is in + Tcp4StateListen state. + - User has called Close() to disconnect this connection. + @retval EFI_CONNECTION_FIN The communication peer has closed the connection and there is + no any buffered data in the receive buffer of this instance. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_RECEIVE)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_IO_TOKEN *Token + ); + +/** + Disconnecting a TCP connection gracefully or reset a TCP connection. This function is a + nonblocking operation. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param CloseToken The pointer to the close token to return when operation finishes. + + @retval EFI_SUCCESS The Close() is called successfully. + @retval EFI_NOT_STARTED This EFI TCPv4 Protocol instance has not been configured. + @retval EFI_ACCESS_DENIED One or more of the following are TRUE: + - Configure() has been called with + TcpConfigData set to NULL and this function has + not returned. + - Previous Close() call on this instance has not + finished. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - CloseToken is NULL. + - CloseToken->CompletionToken.Event is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough resource to finish the operation. + @retval EFI_DEVICE_ERROR Any unexpected and not belonged to above category error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CLOSE)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_CLOSE_TOKEN *CloseToken + ); + +/** + Abort an asynchronous connection, listen, transmission or receive request. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + @param Token The pointer to a token that has been issued by + EFI_TCP4_PROTOCOL.Connect(), + EFI_TCP4_PROTOCOL.Accept(), + EFI_TCP4_PROTOCOL.Transmit() or + EFI_TCP4_PROTOCOL.Receive(). If NULL, all pending + tokens issued by above four functions will be aborted. Type + EFI_TCP4_COMPLETION_TOKEN is defined in + EFI_TCP4_PROTOCOL.Connect(). + + @retval EFI_SUCCESS The asynchronous I/O request is aborted and Token->Event + is signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance hasn't been configured. + @retval EFI_NO_MAPPING When using the default address, configuration + (DHCP, BOOTP,RARP, etc.) hasn't finished yet. + @retval EFI_NOT_FOUND The asynchronous I/O request isn't found in the + transmission or receive queue. It has either + completed or wasn't issued by Transmit() and Receive(). + @retval EFI_UNSUPPORTED The implementation does not support this function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_CANCEL)( + IN EFI_TCP4_PROTOCOL *This, + IN EFI_TCP4_COMPLETION_TOKEN *Token OPTIONAL + ); + + +/** + Poll to receive incoming data and transmit outgoing segments. + + @param This The pointer to the EFI_TCP4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_TIMEOUT Data was dropped out of the transmission or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP4_POLL)( + IN EFI_TCP4_PROTOCOL *This + ); + +/// +/// The EFI_TCP4_PROTOCOL defines the EFI TCPv4 Protocol child to be used by +/// any network drivers or applications to send or receive data stream. +/// It can either listen on a specified port as a service or actively connected +/// to remote peer as a client. Each instance has its own independent settings, +/// such as the routing table. +/// +struct _EFI_TCP4_PROTOCOL { + EFI_TCP4_GET_MODE_DATA GetModeData; + EFI_TCP4_CONFIGURE Configure; + EFI_TCP4_ROUTES Routes; + EFI_TCP4_CONNECT Connect; + EFI_TCP4_ACCEPT Accept; + EFI_TCP4_TRANSMIT Transmit; + EFI_TCP4_RECEIVE Receive; + EFI_TCP4_CLOSE Close; + EFI_TCP4_CANCEL Cancel; + EFI_TCP4_POLL Poll; +}; + +extern EFI_GUID gEfiTcp4ServiceBindingProtocolGuid; +extern EFI_GUID gEfiTcp4ProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Udp4.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Udp4.h new file mode 100644 index 000000000..3c61db8c2 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Udp4.h @@ -0,0 +1,447 @@ +/** @file + UDP4 Service Binding Protocol as defined in UEFI specification. + + The EFI UDPv4 Protocol provides simple packet-oriented services + to transmit and receive UDP packets. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.0. + +**/ + +#ifndef __EFI_UDP4_PROTOCOL_H__ +#define __EFI_UDP4_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +#include <ipxe/efi/Protocol/Ip4.h> +// +//GUID definitions +// +#define EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x83f01464, 0x99bd, 0x45e5, {0xb3, 0x83, 0xaf, 0x63, 0x05, 0xd8, 0xe9, 0xe6 } \ + } + +#define EFI_UDP4_PROTOCOL_GUID \ + { \ + 0x3ad9df29, 0x4501, 0x478d, {0xb1, 0xf8, 0x7f, 0x7f, 0xe7, 0x0e, 0x50, 0xf3 } \ + } + +typedef struct _EFI_UDP4_PROTOCOL EFI_UDP4_PROTOCOL; + +/// +/// EFI_UDP4_SERVICE_POINT is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE InstanceHandle; + EFI_IPv4_ADDRESS LocalAddress; + UINT16 LocalPort; + EFI_IPv4_ADDRESS RemoteAddress; + UINT16 RemotePort; +} EFI_UDP4_SERVICE_POINT; + +/// +/// EFI_UDP4_VARIABLE_DATA is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE DriverHandle; + UINT32 ServiceCount; + EFI_UDP4_SERVICE_POINT Services[1]; +} EFI_UDP4_VARIABLE_DATA; + +typedef struct { + UINT32 FragmentLength; + VOID *FragmentBuffer; +} EFI_UDP4_FRAGMENT_DATA; + +typedef struct { + EFI_IPv4_ADDRESS SourceAddress; + UINT16 SourcePort; + EFI_IPv4_ADDRESS DestinationAddress; + UINT16 DestinationPort; +} EFI_UDP4_SESSION_DATA; +typedef struct { + // + // Receiving Filters + // + BOOLEAN AcceptBroadcast; + BOOLEAN AcceptPromiscuous; + BOOLEAN AcceptAnyPort; + BOOLEAN AllowDuplicatePort; + // + // I/O parameters + // + UINT8 TypeOfService; + UINT8 TimeToLive; + BOOLEAN DoNotFragment; + UINT32 ReceiveTimeout; + UINT32 TransmitTimeout; + // + // Access Point + // + BOOLEAN UseDefaultAddress; + EFI_IPv4_ADDRESS StationAddress; + EFI_IPv4_ADDRESS SubnetMask; + UINT16 StationPort; + EFI_IPv4_ADDRESS RemoteAddress; + UINT16 RemotePort; +} EFI_UDP4_CONFIG_DATA; + +typedef struct { + EFI_UDP4_SESSION_DATA *UdpSessionData; //OPTIONAL + EFI_IPv4_ADDRESS *GatewayAddress; //OPTIONAL + UINT32 DataLength; + UINT32 FragmentCount; + EFI_UDP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP4_TRANSMIT_DATA; + +typedef struct { + EFI_TIME TimeStamp; + EFI_EVENT RecycleSignal; + EFI_UDP4_SESSION_DATA UdpSession; + UINT32 DataLength; + UINT32 FragmentCount; + EFI_UDP4_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP4_RECEIVE_DATA; + + +typedef struct { + EFI_EVENT Event; + EFI_STATUS Status; + union { + EFI_UDP4_RECEIVE_DATA *RxData; + EFI_UDP4_TRANSMIT_DATA *TxData; + } Packet; +} EFI_UDP4_COMPLETION_TOKEN; + +/** + Reads the current operational settings. + + The GetModeData() function copies the current operational settings of this EFI + UDPv4 Protocol instance into user-supplied buffers. This function is used + optionally to retrieve the operational mode data of underlying networks or + drivers. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param Udp4ConfigData The pointer to the buffer to receive the current configuration data. + @param Ip4ModeData The pointer to the EFI IPv4 Protocol mode data structure. + @param MnpConfigData The pointer to the managed network configuration data structure. + @param SnpModeData The pointer to the simple network mode data structure. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED When Udp4ConfigData is queried, no configuration data is + available because this instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_GET_MODE_DATA)( + IN EFI_UDP4_PROTOCOL *This, + OUT EFI_UDP4_CONFIG_DATA *Udp4ConfigData OPTIONAL, + OUT EFI_IP4_MODE_DATA *Ip4ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + + +/** + Initializes, changes, or resets the operational parameters for this instance of the EFI UDPv4 + Protocol. + + The Configure() function is used to do the following: + * Initialize and start this instance of the EFI UDPv4 Protocol. + * Change the filtering rules and operational parameters. + * Reset this instance of the EFI UDPv4 Protocol. + Until these parameters are initialized, no network traffic can be sent or + received by this instance. This instance can be also reset by calling Configure() + with UdpConfigData set to NULL. Once reset, the receiving queue and transmitting + queue are flushed and no traffic is allowed through this instance. + With different parameters in UdpConfigData, Configure() can be used to bind + this instance to specified port. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param Udp4ConfigData The pointer to the buffer to receive the current configuration data. + + @retval EFI_SUCCESS The configuration settings were set, changed, or reset successfully. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_INVALID_PARAMETER UdpConfigData.StationAddress is not a valid unicast IPv4 address. + @retval EFI_INVALID_PARAMETER UdpConfigData.SubnetMask is not a valid IPv4 address mask. The subnet + mask must be contiguous. + @retval EFI_INVALID_PARAMETER UdpConfigData.RemoteAddress is not a valid unicast IPv4 address if it + is not zero. + @retval EFI_ALREADY_STARTED The EFI UDPv4 Protocol instance is already started/configured + and must be stopped/reset before it can be reconfigured. + @retval EFI_ACCESS_DENIED UdpConfigData. AllowDuplicatePort is FALSE + and UdpConfigData.StationPort is already used by + other instance. + @retval EFI_OUT_OF_RESOURCES The EFI UDPv4 Protocol driver cannot allocate memory for this + EFI UDPv4 Protocol instance. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred and this instance + was not opened. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_CONFIGURE)( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_CONFIG_DATA *UdpConfigData OPTIONAL + ); + +/** + Joins and leaves multicast groups. + + The Groups() function is used to enable and disable the multicast group + filtering. If the JoinFlag is FALSE and the MulticastAddress is NULL, then all + currently joined groups are left. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param JoinFlag Set to TRUE to join a multicast group. Set to FALSE to leave one + or all multicast groups. + @param MulticastAddress The pointer to multicast group address to join or leave. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_OUT_OF_RESOURCES Could not allocate resources to join the group. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - JoinFlag is TRUE and MulticastAddress is NULL. + - JoinFlag is TRUE and *MulticastAddress is not + a valid multicast address. + @retval EFI_ALREADY_STARTED The group address is already in the group table (when + JoinFlag is TRUE). + @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is + FALSE). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_GROUPS)( + IN EFI_UDP4_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv4_ADDRESS *MulticastAddress OPTIONAL + ); + +/** + Adds and deletes routing table entries. + + The Routes() function adds a route to or deletes a route from the routing table. + Routes are determined by comparing the SubnetAddress with the destination IP + address and arithmetically AND-ing it with the SubnetMask. The gateway address + must be on the same subnet as the configured station address. + The default route is added with SubnetAddress and SubnetMask both set to 0.0.0.0. + The default route matches all destination IP addresses that do not match any + other routes. + A zero GatewayAddress is a nonroute. Packets are sent to the destination IP + address if it can be found in the Address Resolution Protocol (ARP) cache or + on the local subnet. One automatic nonroute entry will be inserted into the + routing table for outgoing packets that are addressed to a local subnet + (gateway address of 0.0.0.0). + Each instance of the EFI UDPv4 Protocol has its own independent routing table. + Instances of the EFI UDPv4 Protocol that use the default IP address will also + have copies of the routing table provided by the EFI_IP4_CONFIG_PROTOCOL. These + copies will be updated automatically whenever the IP driver reconfigures its + instances; as a result, the previous modification to these copies will be lost. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param DeleteRoute Set to TRUE to delete this route from the routing table. + Set to FALSE to add this route to the routing table. + @param SubnetAddress The destination network address that needs to be routed. + @param SubnetMask The subnet mask of SubnetAddress. + @param GatewayAddress The gateway IP address for this route. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + - RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table. + @retval EFI_NOT_FOUND This route is not in the routing table. + @retval EFI_ACCESS_DENIED The route is already defined in the routing table. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_ROUTES)( + IN EFI_UDP4_PROTOCOL *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv4_ADDRESS *SubnetAddress, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *GatewayAddress + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase + the rate that data packets are moved between the communications device and the + transmit and receive queues. + In some systems, the periodic timer event in the managed network driver may not + poll the underlying communications device fast enough to transmit and/or receive + all data packets without missing incoming packets or dropping outgoing packets. + Drivers and applications that are experiencing packet loss should try calling + the Poll() function more often. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_POLL)( + IN EFI_UDP4_PROTOCOL *This + ); + +/** + Places an asynchronous receive request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. + This function is always asynchronous. + The caller must fill in the Token.Event field in the completion token, and this + field cannot be NULL. When the receive operation completes, the EFI UDPv4 Protocol + driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event + is signaled. Providing a proper notification function and context for the event + will enable the user to receive the notification and receiving status. That + notification function is guaranteed to not be re-entered. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param Token The pointer to a token that is associated with the receive data + descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, RARP, etc.) + is not finished yet. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_INVALID_PARAMETER Token is NULL. + @retval EFI_INVALID_PARAMETER Token.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system + resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_ACCESS_DENIED A receive completion token with the same Token.Event was already in + the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_RECEIVE)( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +/** + Queues outgoing data packets into the transmit queue. + + The Transmit() function places a sending request to this instance of the EFI + UDPv4 Protocol, alongside the transmit data that was filled by the user. Whenever + the packet in the token is sent out or some errors occur, the Token.Event will + be signaled and Token.Status is updated. Providing a proper notification function + and context for the event will enable the user to receive the notification and + transmitting status. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param Token The pointer to the completion token that will be placed into the + transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI UDPv4 Protocol instance has not been started. + @retval EFI_NO_MAPPING When using a default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_ACCESS_DENIED The transmit completion token with the same + Token.Event was already in the transmit queue. + @retval EFI_NOT_READY The completion token could not be queued because the + transmit queue is full. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data. + @retval EFI_NOT_FOUND There is no route to the destination network or address. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP packet + size. Or the length of the IP header + UDP header + data + length is greater than MTU if DoNotFragment is TRUE. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_TRANSMIT)( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token + ); + +/** + Aborts an asynchronous transmit or receive request. + + The Cancel() function is used to abort a pending transmit or receive request. + If the token is in the transmit or receive request queues, after calling this + function, Token.Status will be set to EFI_ABORTED and then Token.Event will be + signaled. If the token is not in one of the queues, which usually means that + the asynchronous operation has completed, this function will not signal the + token and EFI_NOT_FOUND is returned. + + @param This The pointer to the EFI_UDP4_PROTOCOL instance. + @param Token The pointer to a token that has been issued by + EFI_UDP4_PROTOCOL.Transmit() or + EFI_UDP4_PROTOCOL.Receive().If NULL, all pending + tokens are aborted. + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and Token.Event + was signaled. When Token is NULL, all pending requests are + aborted and their events are signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING When using the default address, configuration (DHCP, BOOTP, + RARP, etc.) is not finished yet. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was + not found in the transmit or receive queue. It has either completed + or was not issued by Transmit() and Receive(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP4_CANCEL)( + IN EFI_UDP4_PROTOCOL *This, + IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL + ); + +/// +/// The EFI_UDP4_PROTOCOL defines an EFI UDPv4 Protocol session that can be used +/// by any network drivers, applications, or daemons to transmit or receive UDP packets. +/// This protocol instance can either be bound to a specified port as a service or +/// connected to some remote peer as an active client. Each instance has its own settings, +/// such as the routing table and group table, which are independent from each other. +/// +struct _EFI_UDP4_PROTOCOL { + EFI_UDP4_GET_MODE_DATA GetModeData; + EFI_UDP4_CONFIGURE Configure; + EFI_UDP4_GROUPS Groups; + EFI_UDP4_ROUTES Routes; + EFI_UDP4_TRANSMIT Transmit; + EFI_UDP4_RECEIVE Receive; + EFI_UDP4_CANCEL Cancel; + EFI_UDP4_POLL Poll; +}; + +extern EFI_GUID gEfiUdp4ServiceBindingProtocolGuid; +extern EFI_GUID gEfiUdp4ProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/VlanConfig.h b/roms/ipxe/src/include/ipxe/efi/Protocol/VlanConfig.h new file mode 100644 index 000000000..928faded2 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/VlanConfig.h @@ -0,0 +1,145 @@ +/** @file + EFI VLAN Config protocol is to provide manageability interface for VLAN configuration. + + Copyright (c) 2009, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.2 + +**/ + +#ifndef __EFI_VLANCONFIG_PROTOCOL_H__ +#define __EFI_VLANCONFIG_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + + +#define EFI_VLAN_CONFIG_PROTOCOL_GUID \ + { \ + 0x9e23d768, 0xd2f3, 0x4366, {0x9f, 0xc3, 0x3a, 0x7a, 0xba, 0x86, 0x43, 0x74 } \ + } + +typedef struct _EFI_VLAN_CONFIG_PROTOCOL EFI_VLAN_CONFIG_PROTOCOL; + + +/// +/// EFI_VLAN_FIND_DATA +/// +typedef struct { + UINT16 VlanId; ///< Vlan Identifier. + UINT8 Priority; ///< Priority of this VLAN. +} EFI_VLAN_FIND_DATA; + + +/** + Create a VLAN device or modify the configuration parameter of an + already-configured VLAN. + + The Set() function is used to create a new VLAN device or change the VLAN + configuration parameters. If the VlanId hasn't been configured in the + physical Ethernet device, a new VLAN device will be created. If a VLAN with + this VlanId is already configured, then related configuration will be updated + as the input parameters. + + If VlanId is zero, the VLAN device will send and receive untagged frames. + Otherwise, the VLAN device will send and receive VLAN-tagged frames containing the VlanId. + If VlanId is out of scope of (0-4094), EFI_INVALID_PARAMETER is returned. + If Priority is out of the scope of (0-7), then EFI_INVALID_PARAMETER is returned. + If there is not enough system memory to perform the registration, then + EFI_OUT_OF_RESOURCES is returned. + + @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL. + @param[in] VlanId A unique identifier (1-4094) of the VLAN which is being created + or modified, or zero (0). + @param[in] Priority 3 bit priority in VLAN header. Priority 0 is default value. If + VlanId is zero (0), Priority is ignored. + + @retval EFI_SUCCESS The VLAN is successfully configured. + @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE: + - This is NULL. + - VlanId is an invalid VLAN Identifier. + - Priority is invalid. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to perform the registration. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_VLAN_CONFIG_SET)( + IN EFI_VLAN_CONFIG_PROTOCOL *This, + IN UINT16 VlanId, + IN UINT8 Priority + ); + +/** + Find configuration information for specified VLAN or all configured VLANs. + + The Find() function is used to find the configuration information for matching + VLAN and allocate a buffer into which those entries are copied. + + @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL. + @param[in] VlanId Pointer to VLAN identifier. Set to NULL to find all + configured VLANs. + @param[out] NumberOfVlan The number of VLANs which is found by the specified criteria. + @param[out] Entries The buffer which receive the VLAN configuration. + + @retval EFI_SUCCESS The VLAN is successfully found. + @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE: + - This is NULL. + - Specified VlanId is invalid. + @retval EFI_NOT_FOUND No matching VLAN is found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_VLAN_CONFIG_FIND)( + IN EFI_VLAN_CONFIG_PROTOCOL *This, + IN UINT16 *VlanId OPTIONAL, + OUT UINT16 *NumberOfVlan, + OUT EFI_VLAN_FIND_DATA **Entries + ); + +/** + Remove the configured VLAN device. + + The Remove() function is used to remove the specified VLAN device. + If the VlanId is out of the scope of (0-4094), EFI_INVALID_PARAMETER is returned. + If specified VLAN hasn't been previously configured, EFI_NOT_FOUND is returned. + + @param[in] This Points to the EFI_VLAN_CONFIG_PROTOCOL. + @param[in] VlanId Identifier (0-4094) of the VLAN to be removed. + + @retval EFI_SUCCESS The VLAN is successfully removed. + @retval EFI_INVALID_PARAMETER One or more of following conditions is TRUE: + - This is NULL. + - VlanId is an invalid parameter. + @retval EFI_NOT_FOUND The to-be-removed VLAN does not exist. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_VLAN_CONFIG_REMOVE)( + IN EFI_VLAN_CONFIG_PROTOCOL *This, + IN UINT16 VlanId + ); + +/// +/// EFI_VLAN_CONFIG_PROTOCOL +/// provide manageability interface for VLAN setting. The intended +/// VLAN tagging implementation is IEEE802.1Q. +/// +struct _EFI_VLAN_CONFIG_PROTOCOL { + EFI_VLAN_CONFIG_SET Set; + EFI_VLAN_CONFIG_FIND Find; + EFI_VLAN_CONFIG_REMOVE Remove; +}; + +extern EFI_GUID gEfiVlanConfigProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h index c56f3757b..371dae649 100644 --- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h +++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h @@ -2,6 +2,8 @@ Defines data types and constants introduced in UEFI. Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR> + This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -243,6 +245,11 @@ typedef union { /// #define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED 0x01C2 +/// +/// PE32+ Machine type for AARCH64 A64 images. +/// +#define EFI_IMAGE_MACHINE_AARCH64 0xAA64 + #if defined (MDE_CPU_IA32) @@ -272,6 +279,13 @@ typedef union { #define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) ((Machine) == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED) +#elif defined (MDE_CPU_AARCH64) + +#define EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Machine) \ + (((Machine) == EFI_IMAGE_MACHINE_AARCH64) || ((Machine) == EFI_IMAGE_MACHINE_EBC)) + +#define EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED(Machine) (FALSE) + #elif defined (MDE_CPU_EBC) /// diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h index e792473c1..19121dea7 100644 --- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h +++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h @@ -3,7 +3,7 @@ IFR is primarily consumed by the EFI presentation engine, and produced by EFI internal application and drivers as well as all add-in card option-ROM drivers -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -781,6 +781,7 @@ typedef union { #define EFI_IFR_SECURITY_OP 0x60 #define EFI_IFR_MODAL_TAG_OP 0x61 #define EFI_IFR_REFRESH_ID_OP 0x62 +#define EFI_IFR_WARNING_IF_OP 0x63 // // Definitions of IFR Standard Headers @@ -1128,6 +1129,12 @@ typedef struct _EFI_IFR_NO_SUBMIT_IF { EFI_STRING_ID Error; } EFI_IFR_NO_SUBMIT_IF; +typedef struct _EFI_IFR_WARNING_IF { + EFI_IFR_OP_HEADER Header; + EFI_STRING_ID Warning; + UINT8 TimeOut; +} EFI_IFR_WARNING_IF; + typedef struct _EFI_IFR_REFRESH { EFI_IFR_OP_HEADER Header; UINT8 RefreshInterval; diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h index 0b8da5fa9..5c0b2038f 100644 --- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h +++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiPxe.h @@ -3,7 +3,7 @@ structure prototypes, global variables and constants that are needed for porting PXE to EFI. -Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -721,10 +721,11 @@ typedef struct s_pxe_hw_undi { PXE_UINT8 Len; ///< sizeof(PXE_HW_UNDI). PXE_UINT8 Fudge; ///< makes 8-bit cksum equal zero. PXE_UINT8 Rev; ///< PXE_ROMID_REV. - PXE_UINT8 IFcnt; ///< physical connector count. + PXE_UINT8 IFcnt; ///< physical connector count lower byte. PXE_UINT8 MajorVer; ///< PXE_ROMID_MAJORVER. PXE_UINT8 MinorVer; ///< PXE_ROMID_MINORVER. - PXE_UINT16 reserved; ///< zero, not used. + PXE_UINT8 IFcntExt; ///< physical connector count upper byte. + PXE_UINT8 reserved; ///< zero, not used. PXE_UINT32 Implementation; ///< implementation flags. ///< reserved ///< vendor use. ///< UINT32 Status; ///< status port. @@ -817,10 +818,11 @@ typedef struct s_pxe_sw_undi { PXE_UINT8 Len; ///< sizeof(PXE_SW_UNDI). PXE_UINT8 Fudge; ///< makes 8-bit cksum zero. PXE_UINT8 Rev; ///< PXE_ROMID_REV. - PXE_UINT8 IFcnt; ///< physical connector count. + PXE_UINT8 IFcnt; ///< physical connector count lower byte. PXE_UINT8 MajorVer; ///< PXE_ROMID_MAJORVER. PXE_UINT8 MinorVer; ///< PXE_ROMID_MINORVER. - PXE_UINT16 reserved1; ///< zero, not used. + PXE_UINT8 IFcntExt; ///< physical connector count upper byte. + PXE_UINT8 reserved1; ///< zero, not used. PXE_UINT32 Implementation; ///< Implementation flags. PXE_UINT64 EntryPoint; ///< API entry point. PXE_UINT8 reserved2[3]; ///< zero, not used. diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h index 141bccd75..422b2f30e 100644 --- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h +++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h @@ -1,11 +1,11 @@ /** @file Include file that supports UEFI. - This include file must contain things defined in the UEFI 2.3 specification. - If a code construct is defined in the UEFI 2.3 specification it must be included + This include file must contain things defined in the UEFI 2.4 specification. + If a code construct is defined in the UEFI 2.4 specification it must be included by this include file. -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at @@ -459,11 +459,11 @@ typedef enum { /// TimerCancel, /// - /// An event is to be signalled periodically at a specified interval from the current time. + /// An event is to be signaled periodically at a specified interval from the current time. /// TimerPeriodic, /// - /// An event is to be signalled once at a specified interval from the current time. + /// An event is to be signaled once at a specified interval from the current time. /// TimerRelative } EFI_TIMER_DELAY; @@ -664,13 +664,20 @@ EFI_STATUS then EFI_INVALID_PARAMETER is returned. @param VendorGuid A unique identifier for the vendor. @param Attributes Attributes bitmask to set for the variable. - @param DataSize The size in bytes of the Data buffer. A size of zero causes the - variable to be deleted. + @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero + causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is + set, then a SetVariable() call with a DataSize of zero will not cause any change to + the variable value (the timestamp associated with the variable may be updated however + even if no new data value is provided,see the description of the + EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not + be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). @param Data The contents for the variable. @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as defined by the Attributes. - @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the DataSize exceeds the maximum allowed. @retval EFI_INVALID_PARAMETER VariableName is an empty string. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @@ -678,8 +685,9 @@ EFI_STATUS @retval EFI_WRITE_PROTECTED The variable in question is read-only. @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS - set but the AuthInfo does NOT pass the validation check carried out - by the firmware. + or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo + does NOT pass the validation check carried out by the firmware. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. **/ @@ -989,7 +997,15 @@ typedef enum { /// state. If the system does not support this reset type, then when the system /// is rebooted, it should exhibit the EfiResetCold attributes. /// - EfiResetShutdown + EfiResetShutdown, + /// + /// Used to induce a system-wide reset. The exact type of the reset is defined by + /// the EFI_GUID that follows the Null-terminated Unicode string passed into + /// ResetData. If the platform does not recognize the EFI_GUID in ResetData the + /// platform must pick a supported reset type to perform. The platform may + /// optionally log the parameters from any non-normal reset that occurs. + /// + EfiResetPlatformSpecific } EFI_RESET_TYPE; /** @@ -1150,6 +1166,8 @@ EFI_STATUS @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols. @retval EFI_ALREADY_STARTED A Device Path Protocol instance was passed in that is already present in the handle database. + @retval EFI_INVALID_PARAMETER Handle is NULL. + @retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle. **/ typedef @@ -1655,7 +1673,11 @@ typedef struct { @retval EFI_INVALID_PARAMETER CapsuleCount is 0. @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error. @retval EFI_UNSUPPORTED The capsule type is not supported on this platform. - @retval EFI_OUT_OF_RESOURCES There were insufficient resources to process the capsule. + @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule + is compatible with this platform but is not capable of being submitted or processed + in runtime. The caller may resubmit the capsule prior to ExitBootServices(). + @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates + the capsule is compatible with this platform but there are insufficient resources to process. **/ typedef @@ -1682,7 +1704,11 @@ EFI_STATUS @retval EFI_UNSUPPORTED The capsule type is not supported on this platform, and MaximumCapsuleSize and ResetType are undefined. @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL. - @retval EFI_OUT_OF_RESOURCES There were insufficient resources to process the query request. + @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule + is compatible with this platform but is not capable of being submitted or processed + in runtime. The caller may resubmit the capsule prior to ExitBootServices(). + @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates + the capsule is compatible with this platform but there are insufficient resources to process. **/ typedef @@ -1728,12 +1754,17 @@ EFI_STATUS // // Firmware should stop at a firmware user interface on next boot // -#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 +#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 +#define EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION 0x0000000000000002 +#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED 0x0000000000000004 +#define EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED 0x0000000000000008 +#define EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED 0x0000000000000010 // // EFI Runtime Services Table // #define EFI_SYSTEM_TABLE_SIGNATURE SIGNATURE_64 ('I','B','I',' ','S','Y','S','T') +#define EFI_2_40_SYSTEM_TABLE_REVISION ((2 << 16) | (40)) #define EFI_2_31_SYSTEM_TABLE_REVISION ((2 << 16) | (31)) #define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30)) #define EFI_2_20_SYSTEM_TABLE_REVISION ((2 << 16) | (20)) @@ -1741,10 +1772,11 @@ EFI_STATUS #define EFI_2_00_SYSTEM_TABLE_REVISION ((2 << 16) | (00)) #define EFI_1_10_SYSTEM_TABLE_REVISION ((1 << 16) | (10)) #define EFI_1_02_SYSTEM_TABLE_REVISION ((1 << 16) | (02)) -#define EFI_SYSTEM_TABLE_REVISION EFI_2_31_SYSTEM_TABLE_REVISION +#define EFI_SYSTEM_TABLE_REVISION EFI_2_40_SYSTEM_TABLE_REVISION +#define EFI_SPECIFICATION_VERSION EFI_SYSTEM_TABLE_REVISION #define EFI_RUNTIME_SERVICES_SIGNATURE SIGNATURE_64 ('R','U','N','T','S','E','R','V') -#define EFI_RUNTIME_SERVICES_REVISION EFI_2_31_SYSTEM_TABLE_REVISION +#define EFI_RUNTIME_SERVICES_REVISION EFI_SPECIFICATION_VERSION /// /// EFI Runtime Services Table. @@ -1796,7 +1828,7 @@ typedef struct { #define EFI_BOOT_SERVICES_SIGNATURE SIGNATURE_64 ('B','O','O','T','S','E','R','V') -#define EFI_BOOT_SERVICES_REVISION EFI_2_31_SYSTEM_TABLE_REVISION +#define EFI_BOOT_SERVICES_REVISION EFI_SPECIFICATION_VERSION /// /// EFI Boot Services Table. @@ -2013,41 +2045,46 @@ EFI_STATUS /// /// EFI Boot Key Data /// -typedef UINT32 EFI_BOOT_KEY_DATA; -/// -/// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0. -/// -#define EFI_KEY_OPTION_REVISION_MASK 0x000000FF -/// -/// Either the left or right Shift keys must be pressed (1) or must not be pressed (0). -/// -#define EFI_KEY_OPTION_SHIFT_PRESSED_MASK BIT8 -/// -/// Either the left or right Control keys must be pressed (1) or must not be pressed (0). -/// -#define EFI_KEY_OPTION_CONTROL_PRESSED_MASK BIT9 -/// -/// Either the left or right Alt keys must be pressed (1) or must not be pressed (0). -/// -#define EFI_KEY_OPTION_ALT_PRESSED_MASK BIT10 -/// -/// Either the left or right Logo keys must be pressed (1) or must not be pressed (0). -/// -#define EFI_KEY_OPTION_LOGO_PRESSED_MASK BIT11 -/// -/// The Menu key must be pressed (1) or must not be pressed (0). -/// -#define EFI_KEY_OPTION_MENU_PRESSED_MASK BIT12 -/// -/// The SysReq key must be pressed (1) or must not be pressed (0). -/// -#define EFI_KEY_OPTION_SYS_REQ_PRESSED_MASK BIT13 -/// -/// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If -/// zero, then only the shift state is considered. If more than one, then the boot option will -/// only be launched if all of the specified keys are pressed with the same shift state. -/// -#define EFI_KEY_OPTION_INPUT_KEY_COUNT_MASK (BIT30 | BIT31) +typedef union { + struct { + /// + /// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0. + /// + UINT32 Revision : 8; + /// + /// Either the left or right Shift keys must be pressed (1) or must not be pressed (0). + /// + UINT32 ShiftPressed : 1; + /// + /// Either the left or right Control keys must be pressed (1) or must not be pressed (0). + /// + UINT32 ControlPressed : 1; + /// + /// Either the left or right Alt keys must be pressed (1) or must not be pressed (0). + /// + UINT32 AltPressed : 1; + /// + /// Either the left or right Logo keys must be pressed (1) or must not be pressed (0). + /// + UINT32 LogoPressed : 1; + /// + /// The Menu key must be pressed (1) or must not be pressed (0). + /// + UINT32 MenuPressed : 1; + /// + /// The SysReq key must be pressed (1) or must not be pressed (0). + /// + UINT32 SysReqPressed : 1; + UINT32 Reserved : 16; + /// + /// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If + /// zero, then only the shift state is considered. If more than one, then the boot option will + /// only be launched if all of the specified keys are pressed with the same shift state. + /// + UINT32 InputKeyCount : 2; + } Options; + UINT32 PackedValue; +} EFI_BOOT_KEY_DATA; /// /// EFI Key Option. @@ -2085,6 +2122,7 @@ typedef struct { #define EFI_REMOVABLE_MEDIA_FILE_NAME_IA64 L"\\EFI\\BOOT\\BOOTIA64.EFI" #define EFI_REMOVABLE_MEDIA_FILE_NAME_X64 L"\\EFI\\BOOT\\BOOTX64.EFI" #define EFI_REMOVABLE_MEDIA_FILE_NAME_ARM L"\\EFI\\BOOT\\BOOTARM.EFI" +#define EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64 L"\\EFI\\BOOT\\BOOTAA64.EFI" #if defined (MDE_CPU_IA32) #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_IA32 @@ -2095,6 +2133,8 @@ typedef struct { #elif defined (MDE_CPU_EBC) #elif defined (MDE_CPU_ARM) #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_ARM +#elif defined (MDE_CPU_AARCH64) + #define EFI_REMOVABLE_MEDIA_FILE_NAME EFI_REMOVABLE_MEDIA_FILE_NAME_AARCH64 #else #error Unknown Processor Type #endif diff --git a/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h b/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h index e10e3b549..4f21bb8de 100644 --- a/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h +++ b/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h @@ -1,7 +1,7 @@ /** @file Processor or Compiler specific defines and types x64 (Intel 64, AMD64). - Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -230,6 +230,12 @@ typedef INT64 INTN; #define MAX_ADDRESS 0xFFFFFFFFFFFFFFFFULL /// +/// Maximum legal x64 INTN and UINTN values. +/// +#define MAX_INTN ((INTN)0x7FFFFFFFFFFFFFFFULL) +#define MAX_UINTN ((UINTN)0xFFFFFFFFFFFFFFFFULL) + +/// /// The stack alignment required for x64 /// #define CPU_STACK_ALIGNMENT 16 @@ -286,5 +292,9 @@ typedef INT64 INTN; **/ #define FUNCTION_ENTRY_POINT(FunctionPointer) (VOID *)(UINTN)(FunctionPointer) +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif + #endif diff --git a/roms/ipxe/src/include/ipxe/efi/efi.h b/roms/ipxe/src/include/ipxe/efi/efi.h index a98b5588d..ab52dd9e0 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi.h +++ b/roms/ipxe/src/include/ipxe/efi/efi.h @@ -41,6 +41,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define EFIAPI __attribute__((cdecl,regparm(0))) #endif +/* EFI headers define EFI_HANDLE as a void pointer, which renders type + * checking somewhat useless. Work around this bizarre sabotage + * attempt by redefining EFI_HANDLE as a pointer to an anonymous + * structure. + */ +#define EFI_HANDLE STUPID_EFI_HANDLE +#include <ipxe/efi/Uefi/UefiBaseType.h> +#undef EFI_HANDLE +typedef struct {} *EFI_HANDLE; + /* Include the top-level EFI header files */ #include <ipxe/efi/Uefi.h> #include <ipxe/efi/PiDxe.h> @@ -59,6 +69,8 @@ struct efi_protocol { EFI_GUID guid; /** Variable containing pointer to protocol structure */ void **protocol; + /** Protocol is required */ + int required; }; /** EFI protocol table */ @@ -78,6 +90,21 @@ struct efi_protocol { .protocol = ( ( void ** ) ( void * ) \ ( ( (_ptr) == ( ( _protocol ** ) (_ptr) ) ) ? \ (_ptr) : (_ptr) ) ), \ + .required = 1, \ + } + +/** Declare an EFI protocol to be requested by iPXE + * + * @v _protocol EFI protocol name + * @v _ptr Pointer to protocol instance + */ +#define EFI_REQUEST_PROTOCOL( _protocol, _ptr ) \ + struct efi_protocol __ ## _protocol __efi_protocol = { \ + .guid = _protocol ## _GUID, \ + .protocol = ( ( void ** ) ( void * ) \ + ( ( (_ptr) == ( ( _protocol ** ) (_ptr) ) ) ? \ + (_ptr) : (_ptr) ) ), \ + .required = 0, \ } /** An EFI configuration table used by iPXE */ @@ -126,45 +153,94 @@ struct efi_config_table { */ #define EEFI( efirc ) EPLATFORM ( EINFO_EPLATFORM, efirc ) +extern EFI_GUID efi_arp_protocol_guid; +extern EFI_GUID efi_arp_service_binding_protocol_guid; +extern EFI_GUID efi_block_io_protocol_guid; +extern EFI_GUID efi_bus_specific_driver_override_protocol_guid; +extern EFI_GUID efi_component_name_protocol_guid; +extern EFI_GUID efi_component_name2_protocol_guid; +extern EFI_GUID efi_device_path_protocol_guid; +extern EFI_GUID efi_dhcp4_protocol_guid; +extern EFI_GUID efi_dhcp4_service_binding_protocol_guid; +extern EFI_GUID efi_disk_io_protocol_guid; +extern EFI_GUID efi_driver_binding_protocol_guid; +extern EFI_GUID efi_graphics_output_protocol_guid; +extern EFI_GUID efi_hii_config_access_protocol_guid; +extern EFI_GUID efi_ip4_protocol_guid; +extern EFI_GUID efi_ip4_config_protocol_guid; +extern EFI_GUID efi_ip4_service_binding_protocol_guid; +extern EFI_GUID efi_load_file_protocol_guid; +extern EFI_GUID efi_load_file2_protocol_guid; +extern EFI_GUID efi_loaded_image_protocol_guid; +extern EFI_GUID efi_loaded_image_device_path_protocol_guid; +extern EFI_GUID efi_managed_network_protocol_guid; +extern EFI_GUID efi_managed_network_service_binding_protocol_guid; +extern EFI_GUID efi_mtftp4_protocol_guid; +extern EFI_GUID efi_mtftp4_service_binding_protocol_guid; +extern EFI_GUID efi_nii_protocol_guid; +extern EFI_GUID efi_nii31_protocol_guid; +extern EFI_GUID efi_pci_io_protocol_guid; +extern EFI_GUID efi_pci_root_bridge_io_protocol_guid; +extern EFI_GUID efi_pxe_base_code_protocol_guid; +extern EFI_GUID efi_simple_file_system_protocol_guid; +extern EFI_GUID efi_simple_network_protocol_guid; +extern EFI_GUID efi_tcg_protocol_guid; +extern EFI_GUID efi_tcp4_protocol_guid; +extern EFI_GUID efi_tcp4_service_binding_protocol_guid; +extern EFI_GUID efi_udp4_protocol_guid; +extern EFI_GUID efi_udp4_service_binding_protocol_guid; +extern EFI_GUID efi_vlan_config_protocol_guid; + extern EFI_HANDLE efi_image_handle; extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image; extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; extern EFI_SYSTEM_TABLE *efi_systab; extern const char * efi_guid_ntoa ( EFI_GUID *guid ); +extern const char * efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern const char * efi_handle_name ( EFI_HANDLE handle ); +extern void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ); extern void dbg_efi_protocols ( EFI_HANDLE handle ); -extern void dbg_efi_devpath ( EFI_DEVICE_PATH_PROTOCOL *path ); -#define DBG_EFI_PROTOCOLS_IF( level, handle ) do { \ +#define DBG_EFI_OPENERS_IF( level, handle, protocol ) do { \ if ( DBG_ ## level ) { \ - dbg_efi_protocols ( handle ); \ + dbg_efi_openers ( handle, protocol ); \ } \ } while ( 0 ) -#define DBG_EFI_DEVPATH_IF( level, path ) do { \ +#define DBG_EFI_PROTOCOLS_IF( level, handle ) do { \ if ( DBG_ ## level ) { \ - dbg_efi_devpath ( path ); \ + dbg_efi_protocols ( handle ); \ } \ } while ( 0 ) -#define DBGC_EFI_PROTOCOLS_IF( level, id, ... ) do { \ +#define DBGC_EFI_OPENERS_IF( level, id, ... ) do { \ DBG_AC_IF ( level, id ); \ - DBG_EFI_PROTOCOLS_IF ( level, __VA_ARGS__ ); \ + DBG_EFI_OPENERS_IF ( level, __VA_ARGS__ ); \ DBG_DC_IF ( level ); \ } while ( 0 ) -#define DBGC_EFI_DEVPATH_IF( level, id, ... ) do { \ +#define DBGC_EFI_PROTOCOLS_IF( level, id, ... ) do { \ DBG_AC_IF ( level, id ); \ - DBG_EFI_DEVPATH_IF ( level, __VA_ARGS__ ); \ + DBG_EFI_PROTOCOLS_IF ( level, __VA_ARGS__ ); \ DBG_DC_IF ( level ); \ } while ( 0 ) +#define DBGC_EFI_OPENERS( ... ) \ + DBGC_EFI_OPENERS_IF ( LOG, ##__VA_ARGS__ ) #define DBGC_EFI_PROTOCOLS( ... ) \ - DBGC_EFI_PROTOCOLS_IF( LOG, ##__VA_ARGS__ ) + DBGC_EFI_PROTOCOLS_IF ( LOG, ##__VA_ARGS__ ) + +#define DBGC2_EFI_OPENERS( ... ) \ + DBGC_EFI_OPENERS_IF ( EXTRA, ##__VA_ARGS__ ) +#define DBGC2_EFI_PROTOCOLS( ... ) \ + DBGC_EFI_PROTOCOLS_IF ( EXTRA, ##__VA_ARGS__ ) -#define DBGC_EFI_DEVPATH( ... ) \ - DBGC_EFI_DEVPATH_IF( LOG, ##__VA_ARGS__ ) +#define DBGCP_EFI_OPENERS( ... ) \ + DBGC_EFI_OPENERS_IF ( PROFILE, ##__VA_ARGS__ ) +#define DBGCP_EFI_PROTOCOLS( ... ) \ + DBGC_EFI_PROTOCOLS_IF ( PROFILE, ##__VA_ARGS__ ) extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ); diff --git a/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h b/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h new file mode 100644 index 000000000..d4a26850c --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/efi_autoboot.h @@ -0,0 +1,14 @@ +#ifndef _IPXE_EFI_AUTOBOOT_H +#define _IPXE_EFI_AUTOBOOT_H + +/** @file + * + * EFI autoboot device + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern void efi_set_autoboot ( void ); + +#endif /* _IPXE_EFI_AUTOBOOT_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_download.h b/roms/ipxe/src/include/ipxe/efi/efi_download.h index 3ce497221..740fcadf5 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_download.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_download.h @@ -151,7 +151,7 @@ struct _IPXE_DOWNLOAD_PROTOCOL { 0x3eaeaebd, 0xdecf, 0x493b, { 0x9b, 0xd1, 0xcd, 0xb2, 0xde, 0xca, 0xe7, 0x19 } \ } -extern int efi_download_install ( EFI_HANDLE *device ); -extern void efi_download_uninstall ( EFI_HANDLE device ); +extern int efi_download_install ( EFI_HANDLE handle ); +extern void efi_download_uninstall ( EFI_HANDLE handle ); #endif /* _IPXE_DOWNLOAD_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_driver.h b/roms/ipxe/src/include/ipxe/efi/efi_driver.h index afa574d08..e16a24daa 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_driver.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_driver.h @@ -8,43 +8,85 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include <ipxe/device.h> +#include <ipxe/tables.h> #include <ipxe/efi/efi.h> -#include <ipxe/efi/Protocol/DriverBinding.h> -#include <ipxe/efi/Protocol/ComponentName2.h> #include <ipxe/efi/Protocol/DevicePath.h> +/** An EFI device */ +struct efi_device { + /** Generic device */ + struct device dev; + /** EFI device handle */ + EFI_HANDLE device; + /** Driver for this device */ + struct efi_driver *driver; + /** Driver-private data */ + void *priv; +}; + /** An EFI driver */ struct efi_driver { /** Name */ const char *name; - /** EFI name */ - CHAR16 wname[32]; - /** EFI driver binding protocol */ - EFI_DRIVER_BINDING_PROTOCOL driver; - /** EFI component name protocol */ - EFI_COMPONENT_NAME2_PROTOCOL wtf; + /** + * Check if driver supports device + * + * @v device EFI device handle + * @ret rc Return status code + */ + int ( * supported ) ( EFI_HANDLE device ); + /** + * Attach driver to device + * + * @v efidev EFI device + * @ret rc Return status code + */ + int ( * start ) ( struct efi_device *efidev ); + /** + * Detach driver from device + * + * @v efidev EFI device + */ + void ( * stop ) ( struct efi_device *efidev ); }; -/** Initialise an EFI driver +/** EFI driver table */ +#define EFI_DRIVERS __table ( struct efi_driver, "efi_drivers" ) + +/** Declare an EFI driver */ +#define __efi_driver( order ) __table_entry ( EFI_DRIVERS, order ) + +#define EFI_DRIVER_EARLY 01 /**< Early drivers */ +#define EFI_DRIVER_NORMAL 02 /**< Normal drivers */ +#define EFI_DRIVER_LATE 03 /**< Late drivers */ + +/** + * Set EFI driver-private data * - * @v name Driver name - * @v supported Device supported method - * @v start Device start method - * @v stop Device stop method + * @v efidev EFI device + * @v priv Private data */ -#define EFI_DRIVER_INIT( _name, _supported, _start, _stop ) { \ - .name = _name, \ - .driver = { \ - .Supported = _supported, \ - .Start = _start, \ - .Stop = _stop, \ - .Version = 0x10, \ - } } - -extern EFI_DEVICE_PATH_PROTOCOL * -efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ); - -extern int efi_driver_install ( struct efi_driver *efidrv ); -extern void efi_driver_uninstall ( struct efi_driver *efidrv ); +static inline void efidev_set_drvdata ( struct efi_device *efidev, + void *priv ) { + efidev->priv = priv; +} + +/** + * Get EFI driver-private data + * + * @v efidev EFI device + * @ret priv Private data + */ +static inline void * efidev_get_drvdata ( struct efi_device *efidev ) { + return efidev->priv; +} + +extern struct efi_device * efidev_parent ( struct device *dev ); +extern int efi_driver_install ( void ); +extern void efi_driver_uninstall ( void ); +extern int efi_driver_connect_all ( void ); +extern void efi_driver_disconnect_all ( void ); +extern void efi_driver_reconnect_all ( void ); #endif /* _IPXE_EFI_DRIVER_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_file.h b/roms/ipxe/src/include/ipxe/efi/efi_file.h index 0d75cf5b0..e4db0305a 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_file.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_file.h @@ -7,7 +7,7 @@ * */ -extern int efi_file_install ( EFI_HANDLE *handle ); +extern int efi_file_install ( EFI_HANDLE handle ); extern void efi_file_uninstall ( EFI_HANDLE handle ); #endif /* _IPXE_EFI_FILE_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_pci.h b/roms/ipxe/src/include/ipxe/efi/efi_pci.h index e6b319709..af36613d9 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_pci.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_pci.h @@ -8,44 +8,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include <ipxe/pci.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/PciIo.h> -#include <ipxe/efi/Protocol/DevicePath.h> /* PciRootBridgeIo.h uses LShiftU64(), which isn't defined anywhere else */ static inline EFIAPI uint64_t LShiftU64 ( UINT64 value, UINTN shift ) { return ( value << shift ); } -struct efi_driver; -struct device; - -/** An EFI PCI device */ -struct efi_pci_device { - /** List of EFI PCI devices */ - struct list_head list; - /** iPXE PCI device */ - struct pci_device pci; - /** Underlying EFI device */ - EFI_HANDLE device; - /** PCI I/O protocol */ - EFI_PCI_IO_PROTOCOL *pci_io; - /** Device path */ - EFI_DEVICE_PATH_PROTOCOL *path; - /** EFI driver */ - struct efi_driver *efidrv; -}; - -extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, - EFI_HANDLE device ); -extern int efipci_enable ( struct efi_pci_device *efipci ); -extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ); -extern struct efi_pci_device * efipci_find ( struct device *dev ); -extern int efipci_child_add ( struct efi_pci_device *efipci, - EFI_HANDLE device ); -extern void efipci_child_del ( struct efi_pci_device *efipci, - EFI_HANDLE device ); -extern void efipci_destroy ( struct efi_driver *efidrv, - struct efi_pci_device *efipci ); +extern int efipci_open ( EFI_HANDLE device, UINT32 attributes, + struct pci_device *pci ); +extern void efipci_close ( EFI_HANDLE device ); +extern int efipci_info ( EFI_HANDLE device, struct pci_device *pci ); #endif /* _IPXE_EFI_PCI_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h b/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h index 1bc43e303..498a0388b 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_pci_api.h @@ -55,6 +55,7 @@ static inline __always_inline int PCIAPI_INLINE ( efi, pci_read_config_byte ) ( struct pci_device *pci, unsigned int where, uint8_t *value ) { + *value = 0xff; return efipci_read ( pci, EFIPCI_LOCATION ( where, EFIPCI_WIDTH_BYTE ), value ); @@ -72,6 +73,7 @@ static inline __always_inline int PCIAPI_INLINE ( efi, pci_read_config_word ) ( struct pci_device *pci, unsigned int where, uint16_t *value ) { + *value = 0xffff; return efipci_read ( pci, EFIPCI_LOCATION ( where, EFIPCI_WIDTH_WORD ), value ); @@ -89,6 +91,7 @@ static inline __always_inline int PCIAPI_INLINE ( efi, pci_read_config_dword ) ( struct pci_device *pci, unsigned int where, uint32_t *value ) { + *value = 0xffffffffUL; return efipci_read ( pci, EFIPCI_LOCATION ( where, EFIPCI_WIDTH_DWORD ), value ); diff --git a/roms/ipxe/src/include/ipxe/efi/efi_snp.h b/roms/ipxe/src/include/ipxe/efi/efi_snp.h index e1b866eb8..a18bced5f 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_snp.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_snp.h @@ -24,8 +24,8 @@ struct efi_snp_device { struct list_head list; /** The underlying iPXE network device */ struct net_device *netdev; - /** The underlying EFI PCI device */ - struct efi_pci_device *efipci; + /** The underlying EFI device */ + struct efi_device *efidev; /** EFI device handle */ EFI_HANDLE handle; /** The SNP structure itself */ @@ -65,19 +65,31 @@ struct efi_snp_device { /** Driver name */ wchar_t driver_name[16]; /** Controller name */ - wchar_t controller_name[32]; - /** The device path - * - * This field is variable in size and must appear at the end - * of the structure. - */ - EFI_DEVICE_PATH_PROTOCOL path; + wchar_t controller_name[64]; + /** The device path */ + EFI_DEVICE_PATH_PROTOCOL *path; }; extern int efi_snp_hii_install ( struct efi_snp_device *snpdev ); extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ); +extern struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ); extern struct efi_snp_device * last_opened_snpdev ( void ); -extern void efi_snp_claim ( void ); -extern void efi_snp_release ( void ); +extern void efi_snp_set_claimed ( int claimed ); + +/** + * Claim network devices for use by iPXE + * + */ +static inline void efi_snp_claim ( void ) { + efi_snp_set_claimed ( 1 ); +} + +/** + * Release network devices for use via SNP + * + */ +static inline void efi_snp_release ( void ) { + efi_snp_set_claimed ( 0 ); +} #endif /* _IPXE_EFI_SNP_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_utils.h b/roms/ipxe/src/include/ipxe/efi/efi_utils.h new file mode 100644 index 000000000..9164be190 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/efi_utils.h @@ -0,0 +1,25 @@ +#ifndef _IPXE_EFI_UTILS_H +#define _IPXE_EFI_UTILS_H + +/** @file + * + * EFI utilities + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/efi/efi.h> +#include <ipxe/efi/Protocol/DevicePath.h> + +struct device; + +extern EFI_DEVICE_PATH_PROTOCOL * +efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, + EFI_HANDLE *parent ); +extern int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ); +extern void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ); +extern void efi_device_info ( EFI_HANDLE device, const char *prefix, + struct device *dev ); + +#endif /* _IPXE_EFI_UTILS_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_wrap.h b/roms/ipxe/src/include/ipxe/efi/efi_wrap.h new file mode 100644 index 000000000..7579e0fe9 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/efi_wrap.h @@ -0,0 +1,15 @@ +#ifndef _IPXE_EFI_WRAP_H +#define _IPXE_EFI_WRAP_H + +/** @file + * + * EFI driver interface + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/efi/efi.h> + +extern void efi_wrap ( EFI_HANDLE handle ); + +#endif /* _IPXE_EFI_WRAP_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/import.pl b/roms/ipxe/src/include/ipxe/efi/import.pl index 995514681..f5a3f546f 100755 --- a/roms/ipxe/src/include/ipxe/efi/import.pl +++ b/roms/ipxe/src/include/ipxe/efi/import.pl @@ -78,9 +78,8 @@ sub try_import_file { # Write out line print $outfh "$_\n"; # Apply FILE_LICENCE() immediately after include guard - if ( defined $maybe_guard ) { + if ( defined $maybe_guard && ! defined $guard ) { if ( /^\#define\s+_?_${maybe_guard}_?_$/ ) { - die "Duplicate header guard detected in $infile\n" if $guard; $guard = $maybe_guard; print $outfh "\nFILE_LICENCE ( $licence );\n" if $licence; } @@ -120,7 +119,7 @@ my $edktop = shift; # Identify edk import directories my $edkdirs = [ "MdePkg/Include", "IntelFrameworkPkg/Include", - "MdeModulePkg/Include" ]; + "MdeModulePkg/Include", "EdkCompatibilityPkg/Foundation" ]; foreach my $edkdir ( @$edkdirs ) { die "Directory \"$edktop\" does not appear to contain the EFI EDK2 " ."(missing \"$edkdir\")\n" unless -d catdir ( $edktop, $edkdir ); diff --git a/roms/ipxe/src/include/ipxe/errfile.h b/roms/ipxe/src/include/ipxe/errfile.h index bd12c7cbe..f809337ff 100644 --- a/roms/ipxe/src/include/ipxe/errfile.h +++ b/roms/ipxe/src/include/ipxe/errfile.h @@ -154,6 +154,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_intel ( ERRFILE_DRIVER | 0x00650000 ) #define ERRFILE_myson ( ERRFILE_DRIVER | 0x00660000 ) #define ERRFILE_intelx ( ERRFILE_DRIVER | 0x00670000 ) +#define ERRFILE_snp ( ERRFILE_DRIVER | 0x00680000 ) +#define ERRFILE_netfront ( ERRFILE_DRIVER | 0x00690000 ) +#define ERRFILE_nii ( ERRFILE_DRIVER | 0x006a0000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) @@ -223,6 +226,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_icmp ( ERRFILE_NET | 0x00390000 ) #define ERRFILE_ping ( ERRFILE_NET | 0x003a0000 ) #define ERRFILE_dhcpv6 ( ERRFILE_NET | 0x003b0000 ) +#define ERRFILE_nfs_uri ( ERRFILE_NET | 0x003c0000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) @@ -299,6 +303,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_memmap_settings ( ERRFILE_OTHER | 0x003f0000 ) #define ERRFILE_param_cmd ( ERRFILE_OTHER | 0x00400000 ) #define ERRFILE_deflate ( ERRFILE_OTHER | 0x00410000 ) +#define ERRFILE_xenstore ( ERRFILE_OTHER | 0x00420000 ) +#define ERRFILE_xenbus ( ERRFILE_OTHER | 0x00430000 ) +#define ERRFILE_xengrant ( ERRFILE_OTHER | 0x00440000 ) +#define ERRFILE_efi_utils ( ERRFILE_OTHER | 0x00450000 ) +#define ERRFILE_efi_wrap ( ERRFILE_OTHER | 0x00460000 ) /** @} */ diff --git a/roms/ipxe/src/include/ipxe/ethernet.h b/roms/ipxe/src/include/ipxe/ethernet.h index 5ffc45b73..d1263d7c3 100644 --- a/roms/ipxe/src/include/ipxe/ethernet.h +++ b/roms/ipxe/src/include/ipxe/ethernet.h @@ -80,6 +80,8 @@ static inline int is_valid_ether_addr ( const void *addr ) { } extern uint8_t eth_broadcast[]; +extern struct ll_protocol ethernet_protocol __ll_protocol; + extern int eth_push ( struct net_device *netdev, struct io_buffer *iobuf, const void *ll_dest, const void *ll_source, uint16_t net_proto ); @@ -87,6 +89,7 @@ extern int eth_pull ( struct net_device *netdev, struct io_buffer *iobuf, const void **ll_dest, const void **ll_source, uint16_t *net_proto, unsigned int *flags ); extern void eth_init_addr ( const void *hw_addr, void *ll_addr ); +extern void eth_random_addr ( void *hw_addr ); extern const char * eth_ntoa ( const void *ll_addr ); extern int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ); diff --git a/roms/ipxe/src/include/ipxe/ibft.h b/roms/ipxe/src/include/ipxe/ibft.h index 73372122d..35f15105c 100644 --- a/roms/ipxe/src/include/ipxe/ibft.h +++ b/roms/ipxe/src/include/ipxe/ibft.h @@ -197,6 +197,14 @@ struct ibft_nic { /** NIC global / link local */ #define IBFT_FL_NIC_GLOBAL 0x04 +/** NIC IP address origin */ +#define IBFT_NIC_ORIGIN_OTHER 0x00 +#define IBFT_NIC_ORIGIN_MANUAL 0x01 +#define IBFT_NIC_ORIGIN_WELLKNOWN 0x02 +#define IBFT_NIC_ORIGIN_DHCP 0x03 +#define IBFT_NIC_ORIGIN_RA 0x04 +#define IBFT_NIC_ORIGIN_UNCHANGED 0x0f + /** * iBFT Target structure * diff --git a/roms/ipxe/src/include/ipxe/in.h b/roms/ipxe/src/include/ipxe/in.h index 36032470c..de96ca22a 100644 --- a/roms/ipxe/src/include/ipxe/in.h +++ b/roms/ipxe/src/include/ipxe/in.h @@ -61,7 +61,7 @@ struct in6_addr { #define IN6_IS_ADDR_LINKLOCAL( addr ) \ ( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \ - htonl ( 0xfe80 ) ) + htons ( 0xfe80 ) ) /** * IPv4 socket address diff --git a/roms/ipxe/src/include/ipxe/io.h b/roms/ipxe/src/include/ipxe/io.h index b8b8aa313..29ccfd1fa 100644 --- a/roms/ipxe/src/include/ipxe/io.h +++ b/roms/ipxe/src/include/ipxe/io.h @@ -23,6 +23,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <config/ioapi.h> #include <ipxe/uaccess.h> +/** Page size */ +#define PAGE_SIZE ( 1 << PAGE_SHIFT ) + +/** Page mask */ +#define PAGE_MASK ( PAGE_SIZE - 1 ) + /** * Calculate static inline I/O API function name * diff --git a/roms/ipxe/src/include/ipxe/list.h b/roms/ipxe/src/include/ipxe/list.h index 0d0973077..581ec9806 100644 --- a/roms/ipxe/src/include/ipxe/list.h +++ b/roms/ipxe/src/include/ipxe/list.h @@ -69,6 +69,8 @@ struct list_head { #define list_add( new, head ) do { \ list_check ( (head) ); \ extern_list_add ( (new), (head) ); \ + list_check ( (head) ); \ + list_check ( (new) ); \ } while ( 0 ) static inline void inline_list_add ( struct list_head *new, struct list_head *head ) { @@ -91,6 +93,8 @@ extern void extern_list_add ( struct list_head *new, #define list_add_tail( new, head ) do { \ list_check ( (head) ); \ extern_list_add_tail ( (new), (head) ); \ + list_check ( (head) ); \ + list_check ( (new) ); \ } while ( 0 ) static inline void inline_list_add_tail ( struct list_head *new, struct list_head *head ) { diff --git a/roms/ipxe/src/include/ipxe/netdevice.h b/roms/ipxe/src/include/ipxe/netdevice.h index 6ef9cb1e5..95ad1cf1b 100644 --- a/roms/ipxe/src/include/ipxe/netdevice.h +++ b/roms/ipxe/src/include/ipxe/netdevice.h @@ -685,6 +685,8 @@ extern struct net_device * find_netdev ( const char *name ); extern struct net_device * find_netdev_by_index ( unsigned int index ); extern struct net_device * find_netdev_by_location ( unsigned int bus_type, unsigned int location ); +extern struct net_device * +find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol, const void *ll_addr ); extern struct net_device * last_opened_netdev ( void ); extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest, diff --git a/roms/ipxe/src/include/ipxe/nfs_uri.h b/roms/ipxe/src/include/ipxe/nfs_uri.h new file mode 100644 index 000000000..d88bd6f65 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/nfs_uri.h @@ -0,0 +1,29 @@ +#ifndef _IPXE_NFS_URI_H +#define _IPXE_NFS_URI_H + +/** @file + * + * Network File System protocol URI handling functions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/uri.h> + +struct nfs_uri { + char *mountpoint; + char *filename; + char *path; + char *lookup_pos; +}; + +int nfs_uri_init ( struct nfs_uri *nfs_uri, const struct uri *uri ); +int nfs_uri_next_mountpoint ( struct nfs_uri *uri ); +int nfs_uri_symlink ( struct nfs_uri *uri, const char *symlink_value ); +char *nfs_uri_mountpoint ( const struct nfs_uri *uri ); +char *nfs_uri_next_path_component ( struct nfs_uri *uri ); +void nfs_uri_free ( struct nfs_uri *uri ); + + +#endif /* _IPXE_NFS_URI_H */ diff --git a/roms/ipxe/src/include/ipxe/pinger.h b/roms/ipxe/src/include/ipxe/pinger.h index 2d8403313..9932df6b0 100644 --- a/roms/ipxe/src/include/ipxe/pinger.h +++ b/roms/ipxe/src/include/ipxe/pinger.h @@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); extern int create_pinger ( struct interface *job, const char *hostname, unsigned long timeout, size_t len, + unsigned int count, void ( * callback ) ( struct sockaddr *peer, unsigned int sequence, size_t len, diff --git a/roms/ipxe/src/include/ipxe/profile.h b/roms/ipxe/src/include/ipxe/profile.h index d4fc4f90f..3a745fcfa 100644 --- a/roms/ipxe/src/include/ipxe/profile.h +++ b/roms/ipxe/src/include/ipxe/profile.h @@ -58,12 +58,66 @@ struct profiler { #define __profiler #endif +extern unsigned long profile_excluded; + extern void profile_update ( struct profiler *profiler, unsigned long sample ); extern unsigned long profile_mean ( struct profiler *profiler ); extern unsigned long profile_variance ( struct profiler *profiler ); extern unsigned long profile_stddev ( struct profiler *profiler ); /** + * Get start time + * + * @v profiler Profiler + * @ret started Start time + */ +static inline __attribute__ (( always_inline )) unsigned long +profile_started ( struct profiler *profiler ) { + + /* If profiling is active then return start time */ + if ( PROFILING ) { + return ( profiler->started + profile_excluded ); + } else { + return 0; + } +} + +/** + * Get stop time + * + * @v profiler Profiler + * @ret stopped Stop time + */ +static inline __attribute__ (( always_inline )) unsigned long +profile_stopped ( struct profiler *profiler ) { + + /* If profiling is active then return start time */ + if ( PROFILING ) { + return ( profiler->stopped + profile_excluded ); + } else { + return 0; + } +} + +/** + * Get elapsed time + * + * @v profiler Profiler + * @ret elapsed Elapsed time + */ +static inline __attribute__ (( always_inline )) unsigned long +profile_elapsed ( struct profiler *profiler ) { + + /* If profiling is active then return elapsed time */ + if ( PROFILING ) { + return ( profile_stopped ( profiler ) - + profile_started ( profiler ) ); + } else { + return 0; + } +} + +/** * Start profiling * * @v profiler Profiler @@ -74,7 +128,23 @@ profile_start_at ( struct profiler *profiler, unsigned long started ) { /* If profiling is active then record start timestamp */ if ( PROFILING ) - profiler->started = started; + profiler->started = ( started - profile_excluded ); +} + +/** + * Stop profiling + * + * @v profiler Profiler + * @v stopped Stop timestamp + */ +static inline __attribute__ (( always_inline )) void +profile_stop_at ( struct profiler *profiler, unsigned long stopped ) { + + /* If profiling is active then record end timestamp and update stats */ + if ( PROFILING ) { + profiler->stopped = ( stopped - profile_excluded ); + profile_update ( profiler, profile_elapsed ( profiler ) ); + } } /** @@ -91,32 +161,29 @@ profile_start ( struct profiler *profiler ) { } /** - * Record profiling result + * Stop profiling * * @v profiler Profiler - * @v stopped Stop timestamp */ static inline __attribute__ (( always_inline )) void -profile_stop_at ( struct profiler *profiler, unsigned long stopped ) { +profile_stop ( struct profiler *profiler ) { /* If profiling is active then record end timestamp and update stats */ - if ( PROFILING ) { - profiler->stopped = stopped; - profile_update ( profiler, ( stopped - profiler->started ) ); - } + if ( PROFILING ) + profile_stop_at ( profiler, profile_timestamp() ); } /** - * Record profiling result + * Exclude time from other ongoing profiling results * * @v profiler Profiler */ static inline __attribute__ (( always_inline )) void -profile_stop ( struct profiler *profiler ) { +profile_exclude ( struct profiler *profiler ) { - /* If profiling is active then record end timestamp and update stats */ + /* If profiling is active then update accumulated excluded time */ if ( PROFILING ) - profile_stop_at ( profiler, profile_timestamp() ); + profile_excluded += profile_elapsed ( profiler ); } #endif /* _IPXE_PROFILE_H */ diff --git a/roms/ipxe/src/include/ipxe/scsi.h b/roms/ipxe/src/include/ipxe/scsi.h index 6dfb7f1ea..4428daac3 100644 --- a/roms/ipxe/src/include/ipxe/scsi.h +++ b/roms/ipxe/src/include/ipxe/scsi.h @@ -267,8 +267,8 @@ struct scsi_cmd { size_t data_in_len; }; -/** SCSI sense data */ -struct scsi_sns { +/** SCSI fixed-format sense data */ +struct scsi_sns_fixed { /** Response code */ uint8_t code; /** Reserved */ @@ -277,8 +277,44 @@ struct scsi_sns { uint8_t key; /** Information */ uint32_t info; + /** Additional sense length */ + uint8_t len; + /** Command-specific information */ + uint32_t cs_info; + /** Additional sense code and qualifier */ + uint16_t additional; +} __attribute__ (( packed )); + +/** SCSI descriptor-format sense data */ +struct scsi_sns_descriptor { + /** Response code */ + uint8_t code; + /** Sense key */ + uint8_t key; + /** Additional sense code and qualifier */ + uint16_t additional; +} __attribute__ (( packed )); + +/** SCSI sense data */ +union scsi_sns { + /** Response code */ + uint8_t code; + /** Fixed-format sense data */ + struct scsi_sns_fixed fixed; + /** Descriptor-format sense data */ + struct scsi_sns_descriptor desc; }; +/** SCSI sense response code mask */ +#define SCSI_SENSE_CODE_MASK 0x7f + +/** Test if SCSI sense data is in fixed format + * + * @v code Response code + * @ret is_fixed Sense data is in fixed format + */ +#define SCSI_SENSE_FIXED( code ) ( ( (code) & 0x7e ) == 0x70 ) + /** SCSI sense key mask */ #define SCSI_SENSE_KEY_MASK 0x0f @@ -288,11 +324,18 @@ struct scsi_rsp { uint8_t status; /** Data overrun (or negative underrun) */ ssize_t overrun; - /** Autosense data (if any) */ - struct scsi_sns sense; + /** Autosense data (if any) + * + * To minimise code size, this is stored as the first four + * bytes of a descriptor-format sense data block (even if the + * response code indicates fixed-format sense data). + */ + struct scsi_sns_descriptor sense; }; extern int scsi_parse_lun ( const char *lun_string, struct scsi_lun *lun ); +extern void scsi_parse_sense ( const void *data, size_t len, + struct scsi_sns_descriptor *sense ); extern int scsi_command ( struct interface *control, struct interface *data, struct scsi_cmd *command ); diff --git a/roms/ipxe/src/include/ipxe/smbios.h b/roms/ipxe/src/include/ipxe/smbios.h index 1a34ac04c..ef5892a21 100644 --- a/roms/ipxe/src/include/ipxe/smbios.h +++ b/roms/ipxe/src/include/ipxe/smbios.h @@ -116,6 +116,23 @@ struct smbios_system_information { /** SMBIOS system information structure type */ #define SMBIOS_TYPE_SYSTEM_INFORMATION 1 +/** SMBIOS base board information structure */ +struct smbios_base_board_information { + /** SMBIOS structure header */ + struct smbios_header header; + /** Manufacturer string */ + uint8_t manufacturer; + /** Product string */ + uint8_t product; + /** Version string */ + uint8_t version; + /** Serial number string */ + uint8_t serial; +} __attribute__ (( packed )); + +/** SMBIOS base board information structure type */ +#define SMBIOS_TYPE_BASE_BOARD_INFORMATION 2 + /** SMBIOS enclosure information structure */ struct smbios_enclosure_information { /** SMBIOS structure header */ diff --git a/roms/ipxe/src/include/ipxe/version.h b/roms/ipxe/src/include/ipxe/version.h index aa894d7e8..ae4275db1 100644 --- a/roms/ipxe/src/include/ipxe/version.h +++ b/roms/ipxe/src/include/ipxe/version.h @@ -9,8 +9,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include <wchar.h> + +extern unsigned long build_timestamp; +extern unsigned long build_id; extern const int product_major_version; extern const int product_minor_version; -extern const char *product_version; +extern const char product_version[]; +extern const char product_name[]; +extern const char product_short_name[]; +extern const char build_name[]; +extern const wchar_t product_wversion[]; +extern const wchar_t product_wname[]; +extern const wchar_t product_short_wname[]; +extern const wchar_t build_wname[]; #endif /* _IPXE_VERSION_H */ diff --git a/roms/ipxe/src/include/ipxe/virtio-ring.h b/roms/ipxe/src/include/ipxe/virtio-ring.h index 0afe8bab7..c687acab7 100644 --- a/roms/ipxe/src/include/ipxe/virtio-ring.h +++ b/roms/ipxe/src/include/ipxe/virtio-ring.h @@ -1,8 +1,5 @@ #ifndef _VIRTIO_RING_H_ # define _VIRTIO_RING_H_ -#define PAGE_SHIFT (12) -#define PAGE_SIZE (1<<PAGE_SHIFT) -#define PAGE_MASK (PAGE_SIZE-1) /* Status byte for guest to report progress, and synchronize features. */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ diff --git a/roms/ipxe/src/include/ipxe/x509.h b/roms/ipxe/src/include/ipxe/x509.h index 055a4460e..802480e54 100644 --- a/roms/ipxe/src/include/ipxe/x509.h +++ b/roms/ipxe/src/include/ipxe/x509.h @@ -146,6 +146,7 @@ struct x509_subject_alt_name { enum x509_general_name_types { X509_GENERAL_NAME_DNS = ASN1_IMPLICIT_TAG ( 2 ), X509_GENERAL_NAME_URI = ASN1_IMPLICIT_TAG ( 6 ), + X509_GENERAL_NAME_IP = ASN1_IMPLICIT_TAG ( 7 ), }; /** An X.509 certificate extensions set */ diff --git a/roms/ipxe/src/include/ipxe/xen.h b/roms/ipxe/src/include/ipxe/xen.h new file mode 100644 index 000000000..60aabe03e --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xen.h @@ -0,0 +1,75 @@ +#ifndef _IPXE_XEN_H +#define _IPXE_XEN_H + +/** @file + * + * Xen interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/* Define Xen interface version before including any Xen header files */ +#define __XEN_INTERFACE_VERSION__ 0x00040400 + +#include <stdint.h> +#include <ipxe/uaccess.h> +#include <xen/xen.h> +#include <xen/event_channel.h> + +/* Memory barrier macros used by ring.h */ +#define xen_mb() mb() +#define xen_rmb() rmb() +#define xen_wmb() wmb() + +struct xen_hypercall; + +/** A Xen grant table */ +struct xen_grant { + /** Grant table entries */ + struct grant_entry_v1 *table; + /** Total grant table length */ + size_t len; + /** Entry size shift (for later version tables) */ + unsigned int shift; + /** Number of grant table entries in use */ + unsigned int used; + /** Most recently used grant reference */ + unsigned int ref; +}; + +/** A XenStore */ +struct xen_store { + /** XenStore domain interface */ + struct xenstore_domain_interface *intf; + /** Event channel */ + evtchn_port_t port; +}; + +/** A Xen hypervisor */ +struct xen_hypervisor { + /** Hypercall table */ + struct xen_hypercall *hypercall; + /** Shared info page */ + struct shared_info *shared; + /** Grant table */ + struct xen_grant grant; + /** XenStore */ + struct xen_store store; +}; + +#include <bits/xen.h> + +/** + * Convert a Xen status code to an iPXE status code + * + * @v xenrc Xen status code (negated) + * @ret rc iPXE status code (before negation) + * + * Xen status codes are defined in the file include/xen/errno.h in the + * Xen repository. They happen to match the Linux error codes, some + * of which can be found in our include/ipxe/errno/linux.h. + */ +#define EXEN( xenrc ) EPLATFORM ( EINFO_EPLATFORM, -(xenrc) ) + +#endif /* _IPXE_XEN_H */ diff --git a/roms/ipxe/src/include/ipxe/xenbus.h b/roms/ipxe/src/include/ipxe/xenbus.h new file mode 100644 index 000000000..ef2b5496f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xenbus.h @@ -0,0 +1,86 @@ +#ifndef _IPXE_XENBUS_H +#define _IPXE_XENBUS_H + +/** @file + * + * Xen device bus + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/device.h> +#include <ipxe/tables.h> +#include <ipxe/xen.h> +#include <xen/io/xenbus.h> + +/** A Xen device */ +struct xen_device { + /** Generic iPXE device */ + struct device dev; + /** Xen hypervisor */ + struct xen_hypervisor *xen; + /** XenStore key */ + char *key; + /** Backend XenStore key */ + char *backend; + /** Backend domain ID */ + unsigned long backend_id; + /** Driver */ + struct xen_driver *driver; + /** Driver-private data */ + void *priv; +}; + +/** A Xen device driver */ +struct xen_driver { + /** Name */ + const char *name; + /** Device type */ + const char *type; + /** Probe device + * + * @v xendev Xen device + * @ret rc Return status code + */ + int ( * probe ) ( struct xen_device *xendev ); + /** Remove device + * + * @v xendev Xen device + */ + void ( * remove ) ( struct xen_device *xendev ); +}; + +/** Xen device driver table */ +#define XEN_DRIVERS __table ( struct xen_driver, "xen_drivers" ) + +/** Declare a Xen device driver */ +#define __xen_driver __table_entry ( XEN_DRIVERS, 01 ) + +/** + * Set Xen device driver-private data + * + * @v xendev Xen device + * @v priv Private data + */ +static inline void xen_set_drvdata ( struct xen_device *xendev, void *priv ) { + xendev->priv = priv; +} + +/** + * Get Xen device driver-private data + * + * @v xendev Xen device + * @ret priv Private data + */ +static inline void * xen_get_drvdata ( struct xen_device *xendev ) { + return xendev->priv; +} + +extern int xenbus_set_state ( struct xen_device *xendev, int state ); +extern int xenbus_backend_state ( struct xen_device *xendev ); +extern int xenbus_backend_wait ( struct xen_device *xendev, int state ); +extern int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent ); +extern void xenbus_remove ( struct xen_hypervisor *xen, struct device *parent ); + +#endif /* _IPXE_XENBUS_H */ diff --git a/roms/ipxe/src/include/ipxe/xenevent.h b/roms/ipxe/src/include/ipxe/xenevent.h new file mode 100644 index 000000000..1dd6a0c0b --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xenevent.h @@ -0,0 +1,59 @@ +#ifndef _IPXE_XENEVENT_H +#define _IPXE_XENEVENT_H + +/** @file + * + * Xen events + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/xen.h> +#include <xen/event_channel.h> + +/** + * Close event channel + * + * @v xen Xen hypervisor + * @v close Event descriptor + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xenevent_close ( struct xen_hypervisor *xen, struct evtchn_close *close ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_event_channel_op, + EVTCHNOP_close, virt_to_phys ( close ) ); +} + +/** + * Send event + * + * @v xen Xen hypervisor + * @v send Event descriptor + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xenevent_send ( struct xen_hypervisor *xen, struct evtchn_send *send ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_event_channel_op, + EVTCHNOP_send, virt_to_phys ( send ) ); +} + +/** + * Allocate an unbound event channel + * + * @v xen Xen hypervisor + * @v alloc_unbound Event descriptor + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xenevent_alloc_unbound ( struct xen_hypervisor *xen, + struct evtchn_alloc_unbound *alloc_unbound ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_event_channel_op, + EVTCHNOP_alloc_unbound, + virt_to_phys ( alloc_unbound ) ); +} + +#endif /* _IPXE_XENEVENT_H */ diff --git a/roms/ipxe/src/include/ipxe/xengrant.h b/roms/ipxe/src/include/ipxe/xengrant.h new file mode 100644 index 000000000..f9b3beb21 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xengrant.h @@ -0,0 +1,232 @@ +#ifndef _IPXE_XENGRANT_H +#define _IPXE_XENGRANT_H + +/** @file + * + * Xen grant tables + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <ipxe/io.h> +#include <ipxe/xen.h> +#include <xen/grant_table.h> + +/** Induced failure rate (for testing) */ +#define XENGRANT_FAIL_RATE 0 + +/** + * Query grant table size + * + * @v xen Xen hypervisor + * @v size Table size + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xengrant_query_size ( struct xen_hypervisor *xen, + struct gnttab_query_size *size ) { + + return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op, + GNTTABOP_query_size, + virt_to_phys ( size ), 1 ); +} + +/** + * Set grant table version + * + * @v xen Xen hypervisor + * @v version Version + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xengrant_set_version ( struct xen_hypervisor *xen, + struct gnttab_set_version *version ) { + + return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op, + GNTTABOP_set_version, + virt_to_phys ( version ), 1 ); +} + +/** + * Get grant table version + * + * @v xen Xen hypervisor + * @v version Version + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xengrant_get_version ( struct xen_hypervisor *xen, + struct gnttab_get_version *version ) { + + return xen_hypercall_3 ( xen, __HYPERVISOR_grant_table_op, + GNTTABOP_get_version, + virt_to_phys ( version ), 1 ); +} + +/** + * Get number of grant table entries + * + * @v xen Xen hypervisor + * @ret entries Number of grant table entries + */ +static inline __attribute__ (( always_inline )) unsigned int +xengrant_entries ( struct xen_hypervisor *xen ) { + + return ( ( xen->grant.len / sizeof ( xen->grant.table[0] ) ) + >> xen->grant.shift ); +} + +/** + * Get grant table entry header + * + * @v xen Xen hypervisor + * @v ref Grant reference + * @ret hdr Grant table entry header + */ +static inline __attribute__ (( always_inline )) struct grant_entry_header * +xengrant_header ( struct xen_hypervisor *xen, grant_ref_t ref ) { + struct grant_entry_v1 *v1; + + v1 = &xen->grant.table[ ref << xen->grant.shift ]; + return ( container_of ( &v1->flags, struct grant_entry_header, flags )); +} + +/** + * Get version 1 grant table entry + * + * @v hdr Grant table entry header + * @ret v1 Version 1 grant table entry + */ +static inline __attribute__ (( always_inline )) struct grant_entry_v1 * +xengrant_v1 ( struct grant_entry_header *hdr ) { + + return ( container_of ( &hdr->flags, struct grant_entry_v1, flags ) ); +} + +/** + * Get version 2 grant table entry + * + * @v hdr Grant table entry header + * @ret v2 Version 2 grant table entry + */ +static inline __attribute__ (( always_inline )) union grant_entry_v2 * +xengrant_v2 ( struct grant_entry_header *hdr ) { + + return ( container_of ( &hdr->flags, union grant_entry_v2, hdr.flags )); +} + +/** + * Zero grant table entry + * + * @v xen Xen hypervisor + * @v hdr Grant table entry header + */ +static inline void xengrant_zero ( struct xen_hypervisor *xen, + struct grant_entry_header *hdr ) { + uint32_t *dword = ( ( uint32_t * ) hdr ); + unsigned int i = ( ( sizeof ( xen->grant.table[0] ) / sizeof ( *dword )) + << xen->grant.shift ); + + while ( i-- ) + writel ( 0, dword++ ); +} + +/** + * Invalidate access to a page + * + * @v xen Xen hypervisor + * @v ref Grant reference + */ +static inline __attribute__ (( always_inline )) void +xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) { + struct grant_entry_header *hdr = xengrant_header ( xen, ref ); + + /* Sanity check */ + assert ( ( readw ( &hdr->flags ) & + ( GTF_reading | GTF_writing ) ) == 0 ); + + /* This should apparently be done using a cmpxchg instruction. + * We omit this: partly in the interests of simplicity, but + * mainly since our control flow generally does not permit + * failure paths to themselves fail. + */ + writew ( 0, &hdr->flags ); + + /* Leave reference marked as in-use (see xengrant_alloc()) */ + writew ( DOMID_SELF, &hdr->domid ); +} + +/** + * Permit access to a page + * + * @v xen Xen hypervisor + * @v ref Grant reference + * @v domid Domain ID + * @v subflags Additional flags + * @v page Page start + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +xengrant_permit_access ( struct xen_hypervisor *xen, grant_ref_t ref, + domid_t domid, unsigned int subflags, void *page ) { + struct grant_entry_header *hdr = xengrant_header ( xen, ref ); + struct grant_entry_v1 *v1 = xengrant_v1 ( hdr ); + union grant_entry_v2 *v2 = xengrant_v2 ( hdr ); + unsigned long frame = ( virt_to_phys ( page ) / PAGE_SIZE ); + + /* Fail (for test purposes) if applicable */ + if ( ( XENGRANT_FAIL_RATE > 0 ) && + ( random() % XENGRANT_FAIL_RATE ) == 0 ) { + return -EAGAIN; + } + + /* Record frame number. This may fail on a 64-bit system if + * we are using v1 grant tables. On a 32-bit system, there is + * no way for this code path to fail (with either v1 or v2 + * grant tables); we allow the compiler to optimise the + * failure paths away to save space. + */ + if ( sizeof ( physaddr_t ) == sizeof ( uint64_t ) ) { + + /* 64-bit system */ + if ( xen->grant.shift ) { + /* Version 2 table: no possible failure */ + writeq ( frame, &v2->full_page.frame ); + } else { + /* Version 1 table: may fail if address above 16TB */ + if ( frame > 0xffffffffUL ) + return -ERANGE; + writel ( frame, &v1->frame ); + } + + } else { + + /* 32-bit system */ + if ( xen->grant.shift ) { + /* Version 2 table: no possible failure */ + writel ( frame, &v2->full_page.frame ); + } else { + /* Version 1 table: no possible failure */ + writel ( frame, &v1->frame ); + } + } + + /* Record domain ID and flags */ + writew ( domid, &hdr->domid ); + wmb(); + writew ( ( GTF_permit_access | subflags ), &hdr->flags ); + wmb(); + + return 0; +} + +extern int xengrant_init ( struct xen_hypervisor *xen ); +extern int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs, + unsigned int count ); +extern void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs, + unsigned int count ); + +#endif /* _IPXE_XENGRANT_H */ diff --git a/roms/ipxe/src/include/ipxe/xenmem.h b/roms/ipxe/src/include/ipxe/xenmem.h new file mode 100644 index 000000000..9b9aeda9c --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xenmem.h @@ -0,0 +1,46 @@ +#ifndef _IPXE_XENMEM_H +#define _IPXE_XENMEM_H + +/** @file + * + * Xen memory operations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/xen.h> +#include <xen/memory.h> + +/** + * Add page to physical address space + * + * @v xen Xen hypervisor + * @v add Page mapping descriptor + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xenmem_add_to_physmap ( struct xen_hypervisor *xen, + struct xen_add_to_physmap *add ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_memory_op, + XENMEM_add_to_physmap, virt_to_phys ( add ) ); +} + +/** + * Remove page from physical address space + * + * @v xen Xen hypervisor + * @v remove Page mapping descriptor + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xenmem_remove_from_physmap ( struct xen_hypervisor *xen, + struct xen_remove_from_physmap *remove ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_memory_op, + XENMEM_remove_from_physmap, + virt_to_phys ( remove ) ); +} + +#endif /* _IPXE_XENMEM_H */ diff --git a/roms/ipxe/src/include/ipxe/xenstore.h b/roms/ipxe/src/include/ipxe/xenstore.h new file mode 100644 index 000000000..f25f15704 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xenstore.h @@ -0,0 +1,29 @@ +#ifndef _IPXE_XENSTORE_H +#define _IPXE_XENSTORE_H + +/** @file + * + * XenStore interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/xen.h> + +extern __attribute__ (( sentinel )) int +xenstore_read ( struct xen_hypervisor *xen, char **value, ... ); +extern __attribute__ (( sentinel )) int +xenstore_read_num ( struct xen_hypervisor *xen, unsigned long *num, ... ); +extern __attribute__ (( sentinel )) int +xenstore_write ( struct xen_hypervisor *xen, const char *value, ... ); +extern __attribute__ (( sentinel )) int +xenstore_write_num ( struct xen_hypervisor *xen, unsigned long num, ... ); +extern __attribute__ (( sentinel )) int +xenstore_rm ( struct xen_hypervisor *xen, ... ); +extern __attribute__ (( sentinel )) int +xenstore_directory ( struct xen_hypervisor *xen, char **children, size_t *len, + ... ); +extern void xenstore_dump ( struct xen_hypervisor *xen, const char *key ); + +#endif /* _IPXE_XENSTORE_H */ diff --git a/roms/ipxe/src/include/ipxe/xenver.h b/roms/ipxe/src/include/ipxe/xenver.h new file mode 100644 index 000000000..5d678c5a3 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/xenver.h @@ -0,0 +1,44 @@ +#ifndef _IPXE_XENVER_H +#define _IPXE_VENVER_H + +/** @file + * + * Xen version + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/xen.h> +#include <xen/version.h> + +/** + * Get Xen version + * + * @v xen Xen hypervisor + * @ret version Version (major.minor: 16 bits each) + */ +static inline __attribute__ (( always_inline )) uint32 +xenver_version ( struct xen_hypervisor *xen ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_xen_version, + XENVER_version, 0 ); +} + +/** + * Get Xen extra version string + * + * @v xen Xen hypervisor + * @v extraversion Extra version string to fill in + * @ret xenrc Xen status code + */ +static inline __attribute__ (( always_inline )) int +xenver_extraversion ( struct xen_hypervisor *xen, + xen_extraversion_t *extraversion ) { + + return xen_hypercall_2 ( xen, __HYPERVISOR_xen_version, + XENVER_extraversion, + virt_to_phys ( extraversion ) ); +} + +#endif /* _IPXE_XENVER_H */ diff --git a/roms/ipxe/src/include/usr/autoboot.h b/roms/ipxe/src/include/usr/autoboot.h index f562b2b12..bc51aae79 100644 --- a/roms/ipxe/src/include/usr/autoboot.h +++ b/roms/ipxe/src/include/usr/autoboot.h @@ -9,8 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#include <ipxe/in.h> #include <ipxe/device.h> + struct net_device; struct uri; struct settings; @@ -26,7 +26,9 @@ enum uriboot_flags { URIBOOT_NO_SAN_BOOT | \ URIBOOT_NO_SAN_UNHOOK ) -extern struct device_description autoboot_device; +extern void set_autoboot_busloc ( unsigned int bus_type, + unsigned int location ); +extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len ); extern int uriboot ( struct uri *filename, struct uri *root_path, int drive, unsigned int flags ); diff --git a/roms/ipxe/src/include/usr/pingmgmt.h b/roms/ipxe/src/include/usr/pingmgmt.h index 45ad5d394..d4c2d6cd5 100644 --- a/roms/ipxe/src/include/usr/pingmgmt.h +++ b/roms/ipxe/src/include/usr/pingmgmt.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> -extern int ping ( const char *hostname, unsigned long timeout, size_t len ); +extern int ping ( const char *hostname, unsigned long timeout, size_t len, + unsigned int count, int quiet ); #endif /* _USR_PINGMGMT_H */ diff --git a/roms/ipxe/src/include/xen/arch-arm.h b/roms/ipxe/src/include/xen/arch-arm.h new file mode 100644 index 000000000..ebc3aa2f1 --- /dev/null +++ b/roms/ipxe/src/include/xen/arch-arm.h @@ -0,0 +1,422 @@ +/****************************************************************************** + * arch-arm.h + * + * Guest OS interface to ARM Xen. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright 2011 (C) Citrix Systems + */ + +#ifndef __XEN_PUBLIC_ARCH_ARM_H__ +#define __XEN_PUBLIC_ARCH_ARM_H__ + +FILE_LICENCE ( MIT ); + +/* + * `incontents 50 arm_abi Hypercall Calling Convention + * + * A hypercall is issued using the ARM HVC instruction. + * + * A hypercall can take up to 5 arguments. These are passed in + * registers, the first argument in x0/r0 (for arm64/arm32 guests + * respectively irrespective of whether the underlying hypervisor is + * 32- or 64-bit), the second argument in x1/r1, the third in x2/r2, + * the forth in x3/r3 and the fifth in x4/r4. + * + * The hypercall number is passed in r12 (arm) or x16 (arm64). In both + * cases the relevant ARM procedure calling convention specifies this + * is an inter-procedure-call scratch register (e.g. for use in linker + * stubs). This use does not conflict with use during a hypercall. + * + * The HVC ISS must contain a Xen specific TAG: XEN_HYPERCALL_TAG. + * + * The return value is in x0/r0. + * + * The hypercall will clobber x16/r12 and the argument registers used + * by that hypercall (except r0 which is the return value) i.e. in + * addition to x16/r12 a 2 argument hypercall will clobber x1/r1 and a + * 4 argument hypercall will clobber x1/r1, x2/r2 and x3/r3. + * + * Parameter structs passed to hypercalls are laid out according to + * the Procedure Call Standard for the ARM Architecture (AAPCS, AKA + * EABI) and Procedure Call Standard for the ARM 64-bit Architecture + * (AAPCS64). Where there is a conflict the 64-bit standard should be + * used regardless of guest type. Structures which are passed as + * hypercall arguments are always little endian. + * + * All memory which is shared with other entities in the system + * (including the hypervisor and other guests) must reside in memory + * which is mapped as Normal Inner-cacheable. This applies to: + * - hypercall arguments passed via a pointer to guest memory. + * - memory shared via the grant table mechanism (including PV I/O + * rings etc). + * - memory shared with the hypervisor (struct shared_info, struct + * vcpu_info, the grant table, etc). + * + * Any Inner cache allocation strategy (Write-Back, Write-Through etc) + * is acceptable. There is no restriction on the Outer-cacheability. + */ + +/* + * `incontents 55 arm_hcall Supported Hypercalls + * + * Xen on ARM makes extensive use of hardware facilities and therefore + * only a subset of the potential hypercalls are required. + * + * Since ARM uses second stage paging any machine/physical addresses + * passed to hypercalls are Guest Physical Addresses (Intermediate + * Physical Addresses) unless otherwise noted. + * + * The following hypercalls (and sub operations) are supported on the + * ARM platform. Other hypercalls should be considered + * unavailable/unsupported. + * + * HYPERVISOR_memory_op + * All generic sub-operations. + * + * In addition the following arch specific sub-ops: + * * XENMEM_add_to_physmap + * * XENMEM_add_to_physmap_batch + * + * HYPERVISOR_domctl + * All generic sub-operations, with the exception of: + * * XEN_DOMCTL_iomem_permission (not yet implemented) + * * XEN_DOMCTL_irq_permission (not yet implemented) + * + * HYPERVISOR_sched_op + * All generic sub-operations, with the exception of: + * * SCHEDOP_block -- prefer wfi hardware instruction + * + * HYPERVISOR_console_io + * All generic sub-operations + * + * HYPERVISOR_xen_version + * All generic sub-operations + * + * HYPERVISOR_event_channel_op + * All generic sub-operations + * + * HYPERVISOR_physdev_op + * No sub-operations are currenty supported + * + * HYPERVISOR_sysctl + * All generic sub-operations, with the exception of: + * * XEN_SYSCTL_page_offline_op + * * XEN_SYSCTL_get_pmstat + * * XEN_SYSCTL_pm_op + * + * HYPERVISOR_hvm_op + * Exactly these sub-operations are supported: + * * HVMOP_set_param + * * HVMOP_get_param + * + * HYPERVISOR_grant_table_op + * All generic sub-operations + * + * HYPERVISOR_vcpu_op + * Exactly these sub-operations are supported: + * * VCPUOP_register_vcpu_info + * * VCPUOP_register_runstate_memory_area + * + * + * Other notes on the ARM ABI: + * + * - struct start_info is not exported to ARM guests. + * + * - struct shared_info is mapped by ARM guests using the + * HYPERVISOR_memory_op sub-op XENMEM_add_to_physmap, passing + * XENMAPSPACE_shared_info as space parameter. + * + * - All the per-cpu struct vcpu_info are mapped by ARM guests using the + * HYPERVISOR_vcpu_op sub-op VCPUOP_register_vcpu_info, including cpu0 + * struct vcpu_info. + * + * - The grant table is mapped using the HYPERVISOR_memory_op sub-op + * XENMEM_add_to_physmap, passing XENMAPSPACE_grant_table as space + * parameter. The memory range specified under the Xen compatible + * hypervisor node on device tree can be used as target gpfn for the + * mapping. + * + * - Xenstore is initialized by using the two hvm_params + * HVM_PARAM_STORE_PFN and HVM_PARAM_STORE_EVTCHN. They can be read + * with the HYPERVISOR_hvm_op sub-op HVMOP_get_param. + * + * - The paravirtualized console is initialized by using the two + * hvm_params HVM_PARAM_CONSOLE_PFN and HVM_PARAM_CONSOLE_EVTCHN. They + * can be read with the HYPERVISOR_hvm_op sub-op HVMOP_get_param. + * + * - Event channel notifications are delivered using the percpu GIC + * interrupt specified under the Xen compatible hypervisor node on + * device tree. + * + * - The device tree Xen compatible node is fully described under Linux + * at Documentation/devicetree/bindings/arm/xen.txt. + */ + +#define XEN_HYPERCALL_TAG 0XEA1 + +#define uint64_aligned_t uint64_t __attribute__((aligned(8))) + +#ifndef __ASSEMBLY__ +#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef union { type *p; unsigned long q; } \ + __guest_handle_ ## name; \ + typedef union { type *p; uint64_aligned_t q; } \ + __guest_handle_64_ ## name; + +/* + * XEN_GUEST_HANDLE represents a guest pointer, when passed as a field + * in a struct in memory. On ARM is always 8 bytes sizes and 8 bytes + * aligned. + * XEN_GUEST_HANDLE_PARAM represent a guest pointer, when passed as an + * hypercall argument. It is 4 bytes on aarch and 8 bytes on aarch64. + */ +#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ + ___DEFINE_XEN_GUEST_HANDLE(name, type); \ + ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type) +#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) +#define __XEN_GUEST_HANDLE(name) __guest_handle_64_ ## name +#define XEN_GUEST_HANDLE(name) __XEN_GUEST_HANDLE(name) +/* this is going to be changed on 64 bit */ +#define XEN_GUEST_HANDLE_PARAM(name) __guest_handle_ ## name +#define set_xen_guest_handle_raw(hnd, val) \ + do { \ + typeof(&(hnd)) _sxghr_tmp = &(hnd); \ + _sxghr_tmp->q = 0; \ + _sxghr_tmp->p = val; \ + } while ( 0 ) +#ifdef __XEN_TOOLS__ +#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) +#endif +#define set_xen_guest_handle(hnd, val) set_xen_guest_handle_raw(hnd, val) + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +/* Anonymous union includes both 32- and 64-bit names (e.g., r0/x0). */ +# define __DECL_REG(n64, n32) union { \ + uint64_t n64; \ + uint32_t n32; \ + } +#else +/* Non-gcc sources must always use the proper 64-bit name (e.g., x0). */ +#define __DECL_REG(n64, n32) uint64_t n64 +#endif + +struct vcpu_guest_core_regs +{ + /* Aarch64 Aarch32 */ + __DECL_REG(x0, r0_usr); + __DECL_REG(x1, r1_usr); + __DECL_REG(x2, r2_usr); + __DECL_REG(x3, r3_usr); + __DECL_REG(x4, r4_usr); + __DECL_REG(x5, r5_usr); + __DECL_REG(x6, r6_usr); + __DECL_REG(x7, r7_usr); + __DECL_REG(x8, r8_usr); + __DECL_REG(x9, r9_usr); + __DECL_REG(x10, r10_usr); + __DECL_REG(x11, r11_usr); + __DECL_REG(x12, r12_usr); + + __DECL_REG(x13, sp_usr); + __DECL_REG(x14, lr_usr); + + __DECL_REG(x15, __unused_sp_hyp); + + __DECL_REG(x16, lr_irq); + __DECL_REG(x17, sp_irq); + + __DECL_REG(x18, lr_svc); + __DECL_REG(x19, sp_svc); + + __DECL_REG(x20, lr_abt); + __DECL_REG(x21, sp_abt); + + __DECL_REG(x22, lr_und); + __DECL_REG(x23, sp_und); + + __DECL_REG(x24, r8_fiq); + __DECL_REG(x25, r9_fiq); + __DECL_REG(x26, r10_fiq); + __DECL_REG(x27, r11_fiq); + __DECL_REG(x28, r12_fiq); + + __DECL_REG(x29, sp_fiq); + __DECL_REG(x30, lr_fiq); + + /* Return address and mode */ + __DECL_REG(pc64, pc32); /* ELR_EL2 */ + uint32_t cpsr; /* SPSR_EL2 */ + + union { + uint32_t spsr_el1; /* AArch64 */ + uint32_t spsr_svc; /* AArch32 */ + }; + + /* AArch32 guests only */ + uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; + + /* AArch64 guests only */ + uint64_t sp_el0; + uint64_t sp_el1, elr_el1; +}; +typedef struct vcpu_guest_core_regs vcpu_guest_core_regs_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_guest_core_regs_t); + +#undef __DECL_REG + +typedef uint64_t xen_pfn_t; +#define PRI_xen_pfn PRIx64 + +/* Maximum number of virtual CPUs in legacy multi-processor guests. */ +/* Only one. All other VCPUS must use VCPUOP_register_vcpu_info */ +#define XEN_LEGACY_MAX_VCPUS 1 + +typedef uint64_t xen_ulong_t; +#define PRI_xen_ulong PRIx64 + +#if defined(__XEN__) || defined(__XEN_TOOLS__) +struct vcpu_guest_context { +#define _VGCF_online 0 +#define VGCF_online (1<<_VGCF_online) + uint32_t flags; /* VGCF_* */ + + struct vcpu_guest_core_regs user_regs; /* Core CPU registers */ + + uint32_t sctlr; + uint64_t ttbcr, ttbr0, ttbr1; +}; +typedef struct vcpu_guest_context vcpu_guest_context_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); +#endif + +struct arch_vcpu_info { +}; +typedef struct arch_vcpu_info arch_vcpu_info_t; + +struct arch_shared_info { +}; +typedef struct arch_shared_info arch_shared_info_t; +typedef uint64_t xen_callback_t; + +#endif + +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +/* PSR bits (CPSR, SPSR)*/ + +#define PSR_THUMB (1<<5) /* Thumb Mode enable */ +#define PSR_FIQ_MASK (1<<6) /* Fast Interrupt mask */ +#define PSR_IRQ_MASK (1<<7) /* Interrupt mask */ +#define PSR_ABT_MASK (1<<8) /* Asynchronous Abort mask */ +#define PSR_BIG_ENDIAN (1<<9) /* arm32: Big Endian Mode */ +#define PSR_DBG_MASK (1<<9) /* arm64: Debug Exception mask */ +#define PSR_IT_MASK (0x0600fc00) /* Thumb If-Then Mask */ +#define PSR_JAZELLE (1<<24) /* Jazelle Mode */ + +/* 32 bit modes */ +#define PSR_MODE_USR 0x10 +#define PSR_MODE_FIQ 0x11 +#define PSR_MODE_IRQ 0x12 +#define PSR_MODE_SVC 0x13 +#define PSR_MODE_MON 0x16 +#define PSR_MODE_ABT 0x17 +#define PSR_MODE_HYP 0x1a +#define PSR_MODE_UND 0x1b +#define PSR_MODE_SYS 0x1f + +/* 64 bit modes */ +#define PSR_MODE_BIT 0x10 /* Set iff AArch32 */ +#define PSR_MODE_EL3h 0x0d +#define PSR_MODE_EL3t 0x0c +#define PSR_MODE_EL2h 0x09 +#define PSR_MODE_EL2t 0x08 +#define PSR_MODE_EL1h 0x05 +#define PSR_MODE_EL1t 0x04 +#define PSR_MODE_EL0t 0x00 + +#define PSR_GUEST32_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC) +#define PSR_GUEST64_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h) + +#define SCTLR_GUEST_INIT 0x00c50078 + +/* + * Virtual machine platform (memory layout, interrupts) + * + * These are defined for consistency between the tools and the + * hypervisor. Guests must not rely on these hardcoded values but + * should instead use the FDT. + */ + +/* Physical Address Space */ +#define GUEST_GICD_BASE 0x03001000ULL +#define GUEST_GICD_SIZE 0x00001000ULL +#define GUEST_GICC_BASE 0x03002000ULL +#define GUEST_GICC_SIZE 0x00000100ULL + +/* 16MB == 4096 pages reserved for guest to use as a region to map its + * grant table in. + */ +#define GUEST_GNTTAB_BASE 0x38000000ULL +#define GUEST_GNTTAB_SIZE 0x01000000ULL + +#define GUEST_MAGIC_BASE 0x39000000ULL +#define GUEST_MAGIC_SIZE 0x01000000ULL + +#define GUEST_RAM_BANKS 2 + +#define GUEST_RAM0_BASE 0x40000000ULL /* 3GB of low RAM @ 1GB */ +#define GUEST_RAM0_SIZE 0xc0000000ULL + +#define GUEST_RAM1_BASE 0x0200000000ULL /* 1016GB of RAM @ 8GB */ +#define GUEST_RAM1_SIZE 0xfe00000000ULL + +#define GUEST_RAM_BASE GUEST_RAM0_BASE /* Lowest RAM address */ +/* Largest amount of actual RAM, not including holes */ +#define GUEST_RAM_MAX (GUEST_RAM0_SIZE + GUEST_RAM1_SIZE) +/* Suitable for e.g. const uint64_t ramfoo[] = GUEST_RAM_BANK_FOOS; */ +#define GUEST_RAM_BANK_BASES { GUEST_RAM0_BASE, GUEST_RAM1_BASE } +#define GUEST_RAM_BANK_SIZES { GUEST_RAM0_SIZE, GUEST_RAM1_SIZE } + +/* Interrupts */ +#define GUEST_TIMER_VIRT_PPI 27 +#define GUEST_TIMER_PHYS_S_PPI 29 +#define GUEST_TIMER_PHYS_NS_PPI 30 +#define GUEST_EVTCHN_PPI 31 + +/* PSCI functions */ +#define PSCI_cpu_suspend 0 +#define PSCI_cpu_off 1 +#define PSCI_cpu_on 2 +#define PSCI_migrate 3 + +#endif + +#endif /* __XEN_PUBLIC_ARCH_ARM_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/arch-x86/xen-x86_32.h b/roms/ipxe/src/include/xen/arch-x86/xen-x86_32.h new file mode 100644 index 000000000..96c8f4897 --- /dev/null +++ b/roms/ipxe/src/include/xen/arch-x86/xen-x86_32.h @@ -0,0 +1,173 @@ +/****************************************************************************** + * xen-x86_32.h + * + * Guest OS interface to x86 32-bit Xen. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2004-2007, K A Fraser + */ + +#ifndef __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ +#define __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ + +FILE_LICENCE ( MIT ); + +/* + * Hypercall interface: + * Input: %ebx, %ecx, %edx, %esi, %edi, %ebp (arguments 1-6) + * Output: %eax + * Access is via hypercall page (set up by guest loader or via a Xen MSR): + * call hypercall_page + hypercall-number * 32 + * Clobbered: Argument registers (e.g., 2-arg hypercall clobbers %ebx,%ecx) + */ + +/* + * These flat segments are in the Xen-private section of every GDT. Since these + * are also present in the initial GDT, many OSes will be able to avoid + * installing their own GDT. + */ +#define FLAT_RING1_CS 0xe019 /* GDT index 259 */ +#define FLAT_RING1_DS 0xe021 /* GDT index 260 */ +#define FLAT_RING1_SS 0xe021 /* GDT index 260 */ +#define FLAT_RING3_CS 0xe02b /* GDT index 261 */ +#define FLAT_RING3_DS 0xe033 /* GDT index 262 */ +#define FLAT_RING3_SS 0xe033 /* GDT index 262 */ + +#define FLAT_KERNEL_CS FLAT_RING1_CS +#define FLAT_KERNEL_DS FLAT_RING1_DS +#define FLAT_KERNEL_SS FLAT_RING1_SS +#define FLAT_USER_CS FLAT_RING3_CS +#define FLAT_USER_DS FLAT_RING3_DS +#define FLAT_USER_SS FLAT_RING3_SS + +#define __HYPERVISOR_VIRT_START_PAE 0xF5800000 +#define __MACH2PHYS_VIRT_START_PAE 0xF5800000 +#define __MACH2PHYS_VIRT_END_PAE 0xF6800000 +#define HYPERVISOR_VIRT_START_PAE \ + mk_unsigned_long(__HYPERVISOR_VIRT_START_PAE) +#define MACH2PHYS_VIRT_START_PAE \ + mk_unsigned_long(__MACH2PHYS_VIRT_START_PAE) +#define MACH2PHYS_VIRT_END_PAE \ + mk_unsigned_long(__MACH2PHYS_VIRT_END_PAE) + +/* Non-PAE bounds are obsolete. */ +#define __HYPERVISOR_VIRT_START_NONPAE 0xFC000000 +#define __MACH2PHYS_VIRT_START_NONPAE 0xFC000000 +#define __MACH2PHYS_VIRT_END_NONPAE 0xFC400000 +#define HYPERVISOR_VIRT_START_NONPAE \ + mk_unsigned_long(__HYPERVISOR_VIRT_START_NONPAE) +#define MACH2PHYS_VIRT_START_NONPAE \ + mk_unsigned_long(__MACH2PHYS_VIRT_START_NONPAE) +#define MACH2PHYS_VIRT_END_NONPAE \ + mk_unsigned_long(__MACH2PHYS_VIRT_END_NONPAE) + +#define __HYPERVISOR_VIRT_START __HYPERVISOR_VIRT_START_PAE +#define __MACH2PHYS_VIRT_START __MACH2PHYS_VIRT_START_PAE +#define __MACH2PHYS_VIRT_END __MACH2PHYS_VIRT_END_PAE + +#ifndef HYPERVISOR_VIRT_START +#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) +#endif + +#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) +#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) +#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>2) +#ifndef machine_to_phys_mapping +#define machine_to_phys_mapping ((unsigned long *)MACH2PHYS_VIRT_START) +#endif + +/* 32-/64-bit invariability for control interfaces (domctl/sysctl). */ +#if defined(__XEN__) || defined(__XEN_TOOLS__) +#undef ___DEFINE_XEN_GUEST_HANDLE +#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef struct { type *p; } \ + __guest_handle_ ## name; \ + typedef struct { union { type *p; uint64_aligned_t q; }; } \ + __guest_handle_64_ ## name +#undef set_xen_guest_handle_raw +#define set_xen_guest_handle_raw(hnd, val) \ + do { if ( sizeof(hnd) == 8 ) *(uint64_t *)&(hnd) = 0; \ + (hnd).p = val; \ + } while ( 0 ) +#define uint64_aligned_t uint64_t __attribute__((aligned(8))) +#define __XEN_GUEST_HANDLE_64(name) __guest_handle_64_ ## name +#define XEN_GUEST_HANDLE_64(name) __XEN_GUEST_HANDLE_64(name) +#endif + +#ifndef __ASSEMBLY__ + +struct cpu_user_regs { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint16_t error_code; /* private */ + uint16_t entry_vector; /* private */ + uint32_t eip; + uint16_t cs; + uint8_t saved_upcall_mask; + uint8_t _pad0; + uint32_t eflags; /* eflags.IF == !saved_upcall_mask */ + uint32_t esp; + uint16_t ss, _pad1; + uint16_t es, _pad2; + uint16_t ds, _pad3; + uint16_t fs, _pad4; + uint16_t gs, _pad5; +}; +typedef struct cpu_user_regs cpu_user_regs_t; +DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t); + +/* + * Page-directory addresses above 4GB do not fit into architectural %cr3. + * When accessing %cr3, or equivalent field in vcpu_guest_context, guests + * must use the following accessor macros to pack/unpack valid MFNs. + */ +#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20)) +#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20)) + +struct arch_vcpu_info { + unsigned long cr2; + unsigned long pad[5]; /* sizeof(vcpu_info_t) == 64 */ +}; +typedef struct arch_vcpu_info arch_vcpu_info_t; + +struct xen_callback { + unsigned long cs; + unsigned long eip; +}; +typedef struct xen_callback xen_callback_t; + +#endif /* !__ASSEMBLY__ */ + +#endif /* __XEN_PUBLIC_ARCH_X86_XEN_X86_32_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/arch-x86/xen-x86_64.h b/roms/ipxe/src/include/xen/arch-x86/xen-x86_64.h new file mode 100644 index 000000000..0e9270221 --- /dev/null +++ b/roms/ipxe/src/include/xen/arch-x86/xen-x86_64.h @@ -0,0 +1,204 @@ +/****************************************************************************** + * xen-x86_64.h + * + * Guest OS interface to x86 64-bit Xen. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2004-2006, K A Fraser + */ + +#ifndef __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ +#define __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ + +FILE_LICENCE ( MIT ); + +/* + * Hypercall interface: + * Input: %rdi, %rsi, %rdx, %r10, %r8, %r9 (arguments 1-6) + * Output: %rax + * Access is via hypercall page (set up by guest loader or via a Xen MSR): + * call hypercall_page + hypercall-number * 32 + * Clobbered: argument registers (e.g., 2-arg hypercall clobbers %rdi,%rsi) + */ + +/* + * 64-bit segment selectors + * These flat segments are in the Xen-private section of every GDT. Since these + * are also present in the initial GDT, many OSes will be able to avoid + * installing their own GDT. + */ + +#define FLAT_RING3_CS32 0xe023 /* GDT index 260 */ +#define FLAT_RING3_CS64 0xe033 /* GDT index 261 */ +#define FLAT_RING3_DS32 0xe02b /* GDT index 262 */ +#define FLAT_RING3_DS64 0x0000 /* NULL selector */ +#define FLAT_RING3_SS32 0xe02b /* GDT index 262 */ +#define FLAT_RING3_SS64 0xe02b /* GDT index 262 */ + +#define FLAT_KERNEL_DS64 FLAT_RING3_DS64 +#define FLAT_KERNEL_DS32 FLAT_RING3_DS32 +#define FLAT_KERNEL_DS FLAT_KERNEL_DS64 +#define FLAT_KERNEL_CS64 FLAT_RING3_CS64 +#define FLAT_KERNEL_CS32 FLAT_RING3_CS32 +#define FLAT_KERNEL_CS FLAT_KERNEL_CS64 +#define FLAT_KERNEL_SS64 FLAT_RING3_SS64 +#define FLAT_KERNEL_SS32 FLAT_RING3_SS32 +#define FLAT_KERNEL_SS FLAT_KERNEL_SS64 + +#define FLAT_USER_DS64 FLAT_RING3_DS64 +#define FLAT_USER_DS32 FLAT_RING3_DS32 +#define FLAT_USER_DS FLAT_USER_DS64 +#define FLAT_USER_CS64 FLAT_RING3_CS64 +#define FLAT_USER_CS32 FLAT_RING3_CS32 +#define FLAT_USER_CS FLAT_USER_CS64 +#define FLAT_USER_SS64 FLAT_RING3_SS64 +#define FLAT_USER_SS32 FLAT_RING3_SS32 +#define FLAT_USER_SS FLAT_USER_SS64 + +#define __HYPERVISOR_VIRT_START 0xFFFF800000000000 +#define __HYPERVISOR_VIRT_END 0xFFFF880000000000 +#define __MACH2PHYS_VIRT_START 0xFFFF800000000000 +#define __MACH2PHYS_VIRT_END 0xFFFF804000000000 + +#ifndef HYPERVISOR_VIRT_START +#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START) +#define HYPERVISOR_VIRT_END mk_unsigned_long(__HYPERVISOR_VIRT_END) +#endif + +#define MACH2PHYS_VIRT_START mk_unsigned_long(__MACH2PHYS_VIRT_START) +#define MACH2PHYS_VIRT_END mk_unsigned_long(__MACH2PHYS_VIRT_END) +#define MACH2PHYS_NR_ENTRIES ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3) +#ifndef machine_to_phys_mapping +#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START) +#endif + +/* + * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base) + * @which == SEGBASE_* ; @base == 64-bit base address + * Returns 0 on success. + */ +#define SEGBASE_FS 0 +#define SEGBASE_GS_USER 1 +#define SEGBASE_GS_KERNEL 2 +#define SEGBASE_GS_USER_SEL 3 /* Set user %gs specified in base[15:0] */ + +/* + * int HYPERVISOR_iret(void) + * All arguments are on the kernel stack, in the following format. + * Never returns if successful. Current kernel context is lost. + * The saved CS is mapped as follows: + * RING0 -> RING3 kernel mode. + * RING1 -> RING3 kernel mode. + * RING2 -> RING3 kernel mode. + * RING3 -> RING3 user mode. + * However RING0 indicates that the guest kernel should return to iteself + * directly with + * orb $3,1*8(%rsp) + * iretq + * If flags contains VGCF_in_syscall: + * Restore RAX, RIP, RFLAGS, RSP. + * Discard R11, RCX, CS, SS. + * Otherwise: + * Restore RAX, R11, RCX, CS:RIP, RFLAGS, SS:RSP. + * All other registers are saved on hypercall entry and restored to user. + */ +/* Guest exited in SYSCALL context? Return to guest with SYSRET? */ +#define _VGCF_in_syscall 8 +#define VGCF_in_syscall (1<<_VGCF_in_syscall) +#define VGCF_IN_SYSCALL VGCF_in_syscall + +#ifndef __ASSEMBLY__ + +struct iret_context { + /* Top of stack (%rsp at point of hypercall). */ + uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss; + /* Bottom of iret stack frame. */ +}; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */ +#define __DECL_REG(name) union { \ + uint64_t r ## name, e ## name; \ + uint32_t _e ## name; \ +} +#else +/* Non-gcc sources must always use the proper 64-bit name (e.g., rax). */ +#define __DECL_REG(name) uint64_t r ## name +#endif + +struct cpu_user_regs { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + __DECL_REG(bp); + __DECL_REG(bx); + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + __DECL_REG(ax); + __DECL_REG(cx); + __DECL_REG(dx); + __DECL_REG(si); + __DECL_REG(di); + uint32_t error_code; /* private */ + uint32_t entry_vector; /* private */ + __DECL_REG(ip); + uint16_t cs, _pad0[1]; + uint8_t saved_upcall_mask; + uint8_t _pad1[3]; + __DECL_REG(flags); /* rflags.IF == !saved_upcall_mask */ + __DECL_REG(sp); + uint16_t ss, _pad2[3]; + uint16_t es, _pad3[3]; + uint16_t ds, _pad4[3]; + uint16_t fs, _pad5[3]; /* Non-zero => takes precedence over fs_base. */ + uint16_t gs, _pad6[3]; /* Non-zero => takes precedence over gs_base_usr. */ +}; +typedef struct cpu_user_regs cpu_user_regs_t; +DEFINE_XEN_GUEST_HANDLE(cpu_user_regs_t); + +#undef __DECL_REG + +#define xen_pfn_to_cr3(pfn) ((unsigned long)(pfn) << 12) +#define xen_cr3_to_pfn(cr3) ((unsigned long)(cr3) >> 12) + +struct arch_vcpu_info { + unsigned long cr2; + unsigned long pad; /* sizeof(vcpu_info_t) == 64 */ +}; +typedef struct arch_vcpu_info arch_vcpu_info_t; + +typedef unsigned long xen_callback_t; + +#endif /* !__ASSEMBLY__ */ + +#endif /* __XEN_PUBLIC_ARCH_X86_XEN_X86_64_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/arch-x86/xen.h b/roms/ipxe/src/include/xen/arch-x86/xen.h new file mode 100644 index 000000000..d75528f04 --- /dev/null +++ b/roms/ipxe/src/include/xen/arch-x86/xen.h @@ -0,0 +1,275 @@ +/****************************************************************************** + * arch-x86/xen.h + * + * Guest OS interface to x86 Xen. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2004-2006, K A Fraser + */ + +#include "../xen.h" + +#ifndef __XEN_PUBLIC_ARCH_X86_XEN_H__ +#define __XEN_PUBLIC_ARCH_X86_XEN_H__ + +FILE_LICENCE ( MIT ); + +/* Structural guest handles introduced in 0x00030201. */ +#if __XEN_INTERFACE_VERSION__ >= 0x00030201 +#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef struct { type *p; } __guest_handle_ ## name +#else +#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef type * __guest_handle_ ## name +#endif + +/* + * XEN_GUEST_HANDLE represents a guest pointer, when passed as a field + * in a struct in memory. + * XEN_GUEST_HANDLE_PARAM represent a guest pointer, when passed as an + * hypercall argument. + * XEN_GUEST_HANDLE_PARAM and XEN_GUEST_HANDLE are the same on X86 but + * they might not be on other architectures. + */ +#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ + ___DEFINE_XEN_GUEST_HANDLE(name, type); \ + ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type) +#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) +#define __XEN_GUEST_HANDLE(name) __guest_handle_ ## name +#define XEN_GUEST_HANDLE(name) __XEN_GUEST_HANDLE(name) +#define XEN_GUEST_HANDLE_PARAM(name) XEN_GUEST_HANDLE(name) +#define set_xen_guest_handle_raw(hnd, val) do { (hnd).p = val; } while (0) +#ifdef __XEN_TOOLS__ +#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) +#endif +#define set_xen_guest_handle(hnd, val) set_xen_guest_handle_raw(hnd, val) + +#if defined(__i386__) +#include "xen-x86_32.h" +#elif defined(__x86_64__) +#include "xen-x86_64.h" +#endif + +#ifndef __ASSEMBLY__ +typedef unsigned long xen_pfn_t; +#define PRI_xen_pfn "lx" +#endif + +#define XEN_HAVE_PV_GUEST_ENTRY 1 + +#define XEN_HAVE_PV_UPCALL_MASK 1 + +/* + * `incontents 200 segdesc Segment Descriptor Tables + */ +/* + * ` enum neg_errnoval + * ` HYPERVISOR_set_gdt(const xen_pfn_t frames[], unsigned int entries); + * ` + */ +/* + * A number of GDT entries are reserved by Xen. These are not situated at the + * start of the GDT because some stupid OSes export hard-coded selector values + * in their ABI. These hard-coded values are always near the start of the GDT, + * so Xen places itself out of the way, at the far end of the GDT. + * + * NB The LDT is set using the MMUEXT_SET_LDT op of HYPERVISOR_mmuext_op + */ +#define FIRST_RESERVED_GDT_PAGE 14 +#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096) +#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8) + + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_update_descriptor(u64 pa, u64 desc); + * ` + * ` @pa The machine physical address of the descriptor to + * ` update. Must be either a descriptor page or writable. + * ` @desc The descriptor value to update, in the same format as a + * ` native descriptor table entry. + */ + +/* Maximum number of virtual CPUs in legacy multi-processor guests. */ +#define XEN_LEGACY_MAX_VCPUS 32 + +#ifndef __ASSEMBLY__ + +typedef unsigned long xen_ulong_t; +#define PRI_xen_ulong "lx" + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp); + * ` + * Sets the stack segment and pointer for the current vcpu. + */ + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_set_trap_table(const struct trap_info traps[]); + * ` + */ +/* + * Send an array of these to HYPERVISOR_set_trap_table(). + * Terminate the array with a sentinel entry, with traps[].address==0. + * The privilege level specifies which modes may enter a trap via a software + * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate + * privilege levels as follows: + * Level == 0: Noone may enter + * Level == 1: Kernel may enter + * Level == 2: Kernel may enter + * Level == 3: Everyone may enter + */ +#define TI_GET_DPL(_ti) ((_ti)->flags & 3) +#define TI_GET_IF(_ti) ((_ti)->flags & 4) +#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl)) +#define TI_SET_IF(_ti,_if) ((_ti)->flags |= ((!!(_if))<<2)) +struct trap_info { + uint8_t vector; /* exception vector */ + uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */ + uint16_t cs; /* code selector */ + unsigned long address; /* code offset */ +}; +typedef struct trap_info trap_info_t; +DEFINE_XEN_GUEST_HANDLE(trap_info_t); + +typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */ + +/* + * The following is all CPU context. Note that the fpu_ctxt block is filled + * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used. + * + * Also note that when calling DOMCTL_setvcpucontext and VCPU_initialise + * for HVM and PVH guests, not all information in this structure is updated: + * + * - For HVM guests, the structures read include: fpu_ctxt (if + * VGCT_I387_VALID is set), flags, user_regs, debugreg[*] + * + * - PVH guests are the same as HVM guests, but additionally use ctrlreg[3] to + * set cr3. All other fields not used should be set to 0. + */ +struct vcpu_guest_context { + /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */ + struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */ +#define VGCF_I387_VALID (1<<0) +#define VGCF_IN_KERNEL (1<<2) +#define _VGCF_i387_valid 0 +#define VGCF_i387_valid (1<<_VGCF_i387_valid) +#define _VGCF_in_kernel 2 +#define VGCF_in_kernel (1<<_VGCF_in_kernel) +#define _VGCF_failsafe_disables_events 3 +#define VGCF_failsafe_disables_events (1<<_VGCF_failsafe_disables_events) +#define _VGCF_syscall_disables_events 4 +#define VGCF_syscall_disables_events (1<<_VGCF_syscall_disables_events) +#define _VGCF_online 5 +#define VGCF_online (1<<_VGCF_online) + unsigned long flags; /* VGCF_* flags */ + struct cpu_user_regs user_regs; /* User-level CPU registers */ + struct trap_info trap_ctxt[256]; /* Virtual IDT */ + unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */ + unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */ + unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */ + /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */ + unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */ + unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */ +#ifdef __i386__ + unsigned long event_callback_cs; /* CS:EIP of event callback */ + unsigned long event_callback_eip; + unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */ + unsigned long failsafe_callback_eip; +#else + unsigned long event_callback_eip; + unsigned long failsafe_callback_eip; +#ifdef __XEN__ + union { + unsigned long syscall_callback_eip; + struct { + unsigned int event_callback_cs; /* compat CS of event cb */ + unsigned int failsafe_callback_cs; /* compat CS of failsafe cb */ + }; + }; +#else + unsigned long syscall_callback_eip; +#endif +#endif + unsigned long vm_assist; /* VMASST_TYPE_* bitmap */ +#ifdef __x86_64__ + /* Segment base addresses. */ + uint64_t fs_base; + uint64_t gs_base_kernel; + uint64_t gs_base_user; +#endif +}; +typedef struct vcpu_guest_context vcpu_guest_context_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); + +struct arch_shared_info { + unsigned long max_pfn; /* max pfn that appears in table */ + /* Frame containing list of mfns containing list of mfns containing p2m. */ + xen_pfn_t pfn_to_mfn_frame_list_list; + unsigned long nmi_reason; + uint64_t pad[32]; +}; +typedef struct arch_shared_info arch_shared_info_t; + +#endif /* !__ASSEMBLY__ */ + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_fpu_taskswitch(int set); + * ` + * Sets (if set!=0) or clears (if set==0) CR0.TS. + */ + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_set_debugreg(int regno, unsigned long value); + * + * ` unsigned long + * ` HYPERVISOR_get_debugreg(int regno); + * For 0<=reg<=7, returns the debug register value. + * For other values of reg, returns ((unsigned long)-EINVAL). + * (Unfortunately, this interface is defective.) + */ + +/* + * Prefix forces emulation of some non-trapping instructions. + * Currently only CPUID. + */ +#ifdef __ASSEMBLY__ +#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ; +#define XEN_CPUID XEN_EMULATE_PREFIX cpuid +#else +#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; " +#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid" +#endif + +#endif /* __XEN_PUBLIC_ARCH_X86_XEN_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/event_channel.h b/roms/ipxe/src/include/xen/event_channel.h new file mode 100644 index 000000000..356e946d7 --- /dev/null +++ b/roms/ipxe/src/include/xen/event_channel.h @@ -0,0 +1,383 @@ +/****************************************************************************** + * event_channel.h + * + * Event channels between domains. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2003-2004, K A Fraser. + */ + +#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__ +#define __XEN_PUBLIC_EVENT_CHANNEL_H__ + +FILE_LICENCE ( MIT ); + +#include "xen.h" + +/* + * `incontents 150 evtchn Event Channels + * + * Event channels are the basic primitive provided by Xen for event + * notifications. An event is the Xen equivalent of a hardware + * interrupt. They essentially store one bit of information, the event + * of interest is signalled by transitioning this bit from 0 to 1. + * + * Notifications are received by a guest via an upcall from Xen, + * indicating when an event arrives (setting the bit). Further + * notifications are masked until the bit is cleared again (therefore, + * guests must check the value of the bit after re-enabling event + * delivery to ensure no missed notifications). + * + * Event notifications can be masked by setting a flag; this is + * equivalent to disabling interrupts and can be used to ensure + * atomicity of certain operations in the guest kernel. + * + * Event channels are represented by the evtchn_* fields in + * struct shared_info and struct vcpu_info. + */ + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_event_channel_op(enum event_channel_op cmd, void *args) + * ` + * @cmd == EVTCHNOP_* (event-channel operation). + * @args == struct evtchn_* Operation-specific extra arguments (NULL if none). + */ + +/* ` enum event_channel_op { // EVTCHNOP_* => struct evtchn_* */ +#define EVTCHNOP_bind_interdomain 0 +#define EVTCHNOP_bind_virq 1 +#define EVTCHNOP_bind_pirq 2 +#define EVTCHNOP_close 3 +#define EVTCHNOP_send 4 +#define EVTCHNOP_status 5 +#define EVTCHNOP_alloc_unbound 6 +#define EVTCHNOP_bind_ipi 7 +#define EVTCHNOP_bind_vcpu 8 +#define EVTCHNOP_unmask 9 +#define EVTCHNOP_reset 10 +#define EVTCHNOP_init_control 11 +#define EVTCHNOP_expand_array 12 +#define EVTCHNOP_set_priority 13 +/* ` } */ + +typedef uint32_t evtchn_port_t; +DEFINE_XEN_GUEST_HANDLE(evtchn_port_t); + +/* + * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as + * accepting interdomain bindings from domain <remote_dom>. A fresh port + * is allocated in <dom> and returned as <port>. + * NOTES: + * 1. If the caller is unprivileged then <dom> must be DOMID_SELF. + * 2. <rdom> may be DOMID_SELF, allowing loopback connections. + */ +struct evtchn_alloc_unbound { + /* IN parameters */ + domid_t dom, remote_dom; + /* OUT parameters */ + evtchn_port_t port; +}; +typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t; + +/* + * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between + * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify + * a port that is unbound and marked as accepting bindings from the calling + * domain. A fresh port is allocated in the calling domain and returned as + * <local_port>. + * + * In case the peer domain has already tried to set our event channel + * pending, before it was bound, EVTCHNOP_bind_interdomain always sets + * the local event channel pending. + * + * The usual pattern of use, in the guest's upcall (or subsequent + * handler) is as follows: (Re-enable the event channel for subsequent + * signalling and then) check for the existence of whatever condition + * is being waited for by other means, and take whatever action is + * needed (if any). + * + * NOTES: + * 1. <remote_dom> may be DOMID_SELF, allowing loopback connections. + */ +struct evtchn_bind_interdomain { + /* IN parameters. */ + domid_t remote_dom; + evtchn_port_t remote_port; + /* OUT parameters. */ + evtchn_port_t local_port; +}; +typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t; + +/* + * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified + * vcpu. + * NOTES: + * 1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list + * in xen.h for the classification of each VIRQ. + * 2. Global VIRQs must be allocated on VCPU0 but can subsequently be + * re-bound via EVTCHNOP_bind_vcpu. + * 3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu. + * The allocated event channel is bound to the specified vcpu and the + * binding cannot be changed. + */ +struct evtchn_bind_virq { + /* IN parameters. */ + uint32_t virq; /* enum virq */ + uint32_t vcpu; + /* OUT parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_bind_virq evtchn_bind_virq_t; + +/* + * EVTCHNOP_bind_pirq: Bind a local event channel to a real IRQ (PIRQ <irq>). + * NOTES: + * 1. A physical IRQ may be bound to at most one event channel per domain. + * 2. Only a sufficiently-privileged domain may bind to a physical IRQ. + */ +struct evtchn_bind_pirq { + /* IN parameters. */ + uint32_t pirq; +#define BIND_PIRQ__WILL_SHARE 1 + uint32_t flags; /* BIND_PIRQ__* */ + /* OUT parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_bind_pirq evtchn_bind_pirq_t; + +/* + * EVTCHNOP_bind_ipi: Bind a local event channel to receive events. + * NOTES: + * 1. The allocated event channel is bound to the specified vcpu. The binding + * may not be changed. + */ +struct evtchn_bind_ipi { + uint32_t vcpu; + /* OUT parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_bind_ipi evtchn_bind_ipi_t; + +/* + * EVTCHNOP_close: Close a local event channel <port>. If the channel is + * interdomain then the remote end is placed in the unbound state + * (EVTCHNSTAT_unbound), awaiting a new connection. + */ +struct evtchn_close { + /* IN parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_close evtchn_close_t; + +/* + * EVTCHNOP_send: Send an event to the remote end of the channel whose local + * endpoint is <port>. + */ +struct evtchn_send { + /* IN parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_send evtchn_send_t; + +/* + * EVTCHNOP_status: Get the current status of the communication channel which + * has an endpoint at <dom, port>. + * NOTES: + * 1. <dom> may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may obtain the status of an event + * channel for which <dom> is not DOMID_SELF. + */ +struct evtchn_status { + /* IN parameters */ + domid_t dom; + evtchn_port_t port; + /* OUT parameters */ +#define EVTCHNSTAT_closed 0 /* Channel is not in use. */ +#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/ +#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ +#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ +#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ +#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */ + uint32_t status; + uint32_t vcpu; /* VCPU to which this channel is bound. */ + union { + struct { + domid_t dom; + } unbound; /* EVTCHNSTAT_unbound */ + struct { + domid_t dom; + evtchn_port_t port; + } interdomain; /* EVTCHNSTAT_interdomain */ + uint32_t pirq; /* EVTCHNSTAT_pirq */ + uint32_t virq; /* EVTCHNSTAT_virq */ + } u; +}; +typedef struct evtchn_status evtchn_status_t; + +/* + * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an + * event is pending. + * NOTES: + * 1. IPI-bound channels always notify the vcpu specified at bind time. + * This binding cannot be changed. + * 2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time. + * This binding cannot be changed. + * 3. All other channels notify vcpu0 by default. This default is set when + * the channel is allocated (a port that is freed and subsequently reused + * has its binding reset to vcpu0). + */ +struct evtchn_bind_vcpu { + /* IN parameters. */ + evtchn_port_t port; + uint32_t vcpu; +}; +typedef struct evtchn_bind_vcpu evtchn_bind_vcpu_t; + +/* + * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver + * a notification to the appropriate VCPU if an event is pending. + */ +struct evtchn_unmask { + /* IN parameters. */ + evtchn_port_t port; +}; +typedef struct evtchn_unmask evtchn_unmask_t; + +/* + * EVTCHNOP_reset: Close all event channels associated with specified domain. + * NOTES: + * 1. <dom> may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may specify other than DOMID_SELF. + */ +struct evtchn_reset { + /* IN parameters. */ + domid_t dom; +}; +typedef struct evtchn_reset evtchn_reset_t; + +/* + * EVTCHNOP_init_control: initialize the control block for the FIFO ABI. + * + * Note: any events that are currently pending will not be resent and + * will be lost. Guests should call this before binding any event to + * avoid losing any events. + */ +struct evtchn_init_control { + /* IN parameters. */ + uint64_t control_gfn; + uint32_t offset; + uint32_t vcpu; + /* OUT parameters. */ + uint8_t link_bits; + uint8_t _pad[7]; +}; +typedef struct evtchn_init_control evtchn_init_control_t; + +/* + * EVTCHNOP_expand_array: add an additional page to the event array. + */ +struct evtchn_expand_array { + /* IN parameters. */ + uint64_t array_gfn; +}; +typedef struct evtchn_expand_array evtchn_expand_array_t; + +/* + * EVTCHNOP_set_priority: set the priority for an event channel. + */ +struct evtchn_set_priority { + /* IN parameters. */ + uint32_t port; + uint32_t priority; +}; +typedef struct evtchn_set_priority evtchn_set_priority_t; + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_event_channel_op_compat(struct evtchn_op *op) + * ` + * Superceded by new event_channel_op() hypercall since 0x00030202. + */ +struct evtchn_op { + uint32_t cmd; /* enum event_channel_op */ + union { + struct evtchn_alloc_unbound alloc_unbound; + struct evtchn_bind_interdomain bind_interdomain; + struct evtchn_bind_virq bind_virq; + struct evtchn_bind_pirq bind_pirq; + struct evtchn_bind_ipi bind_ipi; + struct evtchn_close close; + struct evtchn_send send; + struct evtchn_status status; + struct evtchn_bind_vcpu bind_vcpu; + struct evtchn_unmask unmask; + } u; +}; +typedef struct evtchn_op evtchn_op_t; +DEFINE_XEN_GUEST_HANDLE(evtchn_op_t); + +/* + * 2-level ABI + */ + +#define EVTCHN_2L_NR_CHANNELS (sizeof(xen_ulong_t) * sizeof(xen_ulong_t) * 64) + +/* + * FIFO ABI + */ + +/* Events may have priorities from 0 (highest) to 15 (lowest). */ +#define EVTCHN_FIFO_PRIORITY_MAX 0 +#define EVTCHN_FIFO_PRIORITY_DEFAULT 7 +#define EVTCHN_FIFO_PRIORITY_MIN 15 + +#define EVTCHN_FIFO_MAX_QUEUES (EVTCHN_FIFO_PRIORITY_MIN + 1) + +typedef uint32_t event_word_t; + +#define EVTCHN_FIFO_PENDING 31 +#define EVTCHN_FIFO_MASKED 30 +#define EVTCHN_FIFO_LINKED 29 +#define EVTCHN_FIFO_BUSY 28 + +#define EVTCHN_FIFO_LINK_BITS 17 +#define EVTCHN_FIFO_LINK_MASK ((1 << EVTCHN_FIFO_LINK_BITS) - 1) + +#define EVTCHN_FIFO_NR_CHANNELS (1 << EVTCHN_FIFO_LINK_BITS) + +struct evtchn_fifo_control_block { + uint32_t ready; + uint32_t _rsvd; + uint32_t head[EVTCHN_FIFO_MAX_QUEUES]; +}; +typedef struct evtchn_fifo_control_block evtchn_fifo_control_block_t; + +#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/features.h b/roms/ipxe/src/include/xen/features.h new file mode 100644 index 000000000..130265819 --- /dev/null +++ b/roms/ipxe/src/include/xen/features.h @@ -0,0 +1,111 @@ +/****************************************************************************** + * features.h + * + * Feature flags, reported by XENVER_get_features. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2006, Keir Fraser <keir@xensource.com> + */ + +#ifndef __XEN_PUBLIC_FEATURES_H__ +#define __XEN_PUBLIC_FEATURES_H__ + +FILE_LICENCE ( MIT ); + +/* + * `incontents 200 elfnotes_features XEN_ELFNOTE_FEATURES + * + * The list of all the features the guest supports. They are set by + * parsing the XEN_ELFNOTE_FEATURES and XEN_ELFNOTE_SUPPORTED_FEATURES + * string. The format is the feature names (as given here without the + * "XENFEAT_" prefix) separated by '|' characters. + * If a feature is required for the kernel to function then the feature name + * must be preceded by a '!' character. + * + * Note that if XEN_ELFNOTE_SUPPORTED_FEATURES is used, then in the + * XENFEAT_dom0 MUST be set if the guest is to be booted as dom0, + */ + +/* + * If set, the guest does not need to write-protect its pagetables, and can + * update them via direct writes. + */ +#define XENFEAT_writable_page_tables 0 + +/* + * If set, the guest does not need to write-protect its segment descriptor + * tables, and can update them via direct writes. + */ +#define XENFEAT_writable_descriptor_tables 1 + +/* + * If set, translation between the guest's 'pseudo-physical' address space + * and the host's machine address space are handled by the hypervisor. In this + * mode the guest does not need to perform phys-to/from-machine translations + * when performing page table operations. + */ +#define XENFEAT_auto_translated_physmap 2 + +/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */ +#define XENFEAT_supervisor_mode_kernel 3 + +/* + * If set, the guest does not need to allocate x86 PAE page directories + * below 4GB. This flag is usually implied by auto_translated_physmap. + */ +#define XENFEAT_pae_pgdir_above_4gb 4 + +/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ +#define XENFEAT_mmu_pt_update_preserve_ad 5 + +/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */ +#define XENFEAT_highmem_assist 6 + +/* + * If set, GNTTABOP_map_grant_ref honors flags to be placed into guest kernel + * available pte bits. + */ +#define XENFEAT_gnttab_map_avail_bits 7 + +/* x86: Does this Xen host support the HVM callback vector type? */ +#define XENFEAT_hvm_callback_vector 8 + +/* x86: pvclock algorithm is safe to use on HVM */ +#define XENFEAT_hvm_safe_pvclock 9 + +/* x86: pirq can be used by HVM guests */ +#define XENFEAT_hvm_pirqs 10 + +/* operation as Dom0 is supported */ +#define XENFEAT_dom0 11 + +#define XENFEAT_NR_SUBMAPS 1 + +#endif /* __XEN_PUBLIC_FEATURES_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/grant_table.h b/roms/ipxe/src/include/xen/grant_table.h new file mode 100644 index 000000000..137939e70 --- /dev/null +++ b/roms/ipxe/src/include/xen/grant_table.h @@ -0,0 +1,664 @@ +/****************************************************************************** + * grant_table.h + * + * Interface for granting foreign access to page frames, and receiving + * page-ownership transfers. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __XEN_PUBLIC_GRANT_TABLE_H__ +#define __XEN_PUBLIC_GRANT_TABLE_H__ + +FILE_LICENCE ( MIT ); + +#include "xen.h" + +/* + * `incontents 150 gnttab Grant Tables + * + * Xen's grant tables provide a generic mechanism to memory sharing + * between domains. This shared memory interface underpins the split + * device drivers for block and network IO. + * + * Each domain has its own grant table. This is a data structure that + * is shared with Xen; it allows the domain to tell Xen what kind of + * permissions other domains have on its pages. Entries in the grant + * table are identified by grant references. A grant reference is an + * integer, which indexes into the grant table. It acts as a + * capability which the grantee can use to perform operations on the + * granter’s memory. + * + * This capability-based system allows shared-memory communications + * between unprivileged domains. A grant reference also encapsulates + * the details of a shared page, removing the need for a domain to + * know the real machine address of a page it is sharing. This makes + * it possible to share memory correctly with domains running in + * fully virtualised memory. + */ + +/*********************************** + * GRANT TABLE REPRESENTATION + */ + +/* Some rough guidelines on accessing and updating grant-table entries + * in a concurrency-safe manner. For more information, Linux contains a + * reference implementation for guest OSes (drivers/xen/grant_table.c, see + * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=drivers/xen/grant-table.c;hb=HEAD + * + * NB. WMB is a no-op on current-generation x86 processors. However, a + * compiler barrier will still be required. + * + * Introducing a valid entry into the grant table: + * 1. Write ent->domid. + * 2. Write ent->frame: + * GTF_permit_access: Frame to which access is permitted. + * GTF_accept_transfer: Pseudo-phys frame slot being filled by new + * frame, or zero if none. + * 3. Write memory barrier (WMB). + * 4. Write ent->flags, inc. valid type. + * + * Invalidating an unused GTF_permit_access entry: + * 1. flags = ent->flags. + * 2. Observe that !(flags & (GTF_reading|GTF_writing)). + * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0). + * NB. No need for WMB as reuse of entry is control-dependent on success of + * step 3, and all architectures guarantee ordering of ctrl-dep writes. + * + * Invalidating an in-use GTF_permit_access entry: + * This cannot be done directly. Request assistance from the domain controller + * which can set a timeout on the use of a grant entry and take necessary + * action. (NB. This is not yet implemented!). + * + * Invalidating an unused GTF_accept_transfer entry: + * 1. flags = ent->flags. + * 2. Observe that !(flags & GTF_transfer_committed). [*] + * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0). + * NB. No need for WMB as reuse of entry is control-dependent on success of + * step 3, and all architectures guarantee ordering of ctrl-dep writes. + * [*] If GTF_transfer_committed is set then the grant entry is 'committed'. + * The guest must /not/ modify the grant entry until the address of the + * transferred frame is written. It is safe for the guest to spin waiting + * for this to occur (detect by observing GTF_transfer_completed in + * ent->flags). + * + * Invalidating a committed GTF_accept_transfer entry: + * 1. Wait for (ent->flags & GTF_transfer_completed). + * + * Changing a GTF_permit_access from writable to read-only: + * Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing. + * + * Changing a GTF_permit_access from read-only to writable: + * Use SMP-safe bit-setting instruction. + */ + +/* + * Reference to a grant entry in a specified domain's grant table. + */ +typedef uint32_t grant_ref_t; + +/* + * A grant table comprises a packed array of grant entries in one or more + * page frames shared between Xen and a guest. + * [XEN]: This field is written by Xen and read by the sharing guest. + * [GST]: This field is written by the guest and read by Xen. + */ + +/* + * Version 1 of the grant table entry structure is maintained purely + * for backwards compatibility. New guests should use version 2. + */ +#if __XEN_INTERFACE_VERSION__ < 0x0003020a +#define grant_entry_v1 grant_entry +#define grant_entry_v1_t grant_entry_t +#endif +struct grant_entry_v1 { + /* GTF_xxx: various type and flag information. [XEN,GST] */ + uint16_t flags; + /* The domain being granted foreign privileges. [GST] */ + domid_t domid; + /* + * GTF_permit_access: Frame that @domid is allowed to map and access. [GST] + * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN] + */ + uint32_t frame; +}; +typedef struct grant_entry_v1 grant_entry_v1_t; + +/* The first few grant table entries will be preserved across grant table + * version changes and may be pre-populated at domain creation by tools. + */ +#define GNTTAB_NR_RESERVED_ENTRIES 8 +#define GNTTAB_RESERVED_CONSOLE 0 +#define GNTTAB_RESERVED_XENSTORE 1 + +/* + * Type of grant entry. + * GTF_invalid: This grant entry grants no privileges. + * GTF_permit_access: Allow @domid to map/access @frame. + * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame + * to this guest. Xen writes the page number to @frame. + * GTF_transitive: Allow @domid to transitively access a subrange of + * @trans_grant in @trans_domid. No mappings are allowed. + */ +#define GTF_invalid (0U<<0) +#define GTF_permit_access (1U<<0) +#define GTF_accept_transfer (2U<<0) +#define GTF_transitive (3U<<0) +#define GTF_type_mask (3U<<0) + +/* + * Subflags for GTF_permit_access. + * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST] + * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN] + * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN] + * GTF_PAT, GTF_PWT, GTF_PCD: (x86) cache attribute flags for the grant [GST] + * GTF_sub_page: Grant access to only a subrange of the page. @domid + * will only be allowed to copy from the grant, and not + * map it. [GST] + */ +#define _GTF_readonly (2) +#define GTF_readonly (1U<<_GTF_readonly) +#define _GTF_reading (3) +#define GTF_reading (1U<<_GTF_reading) +#define _GTF_writing (4) +#define GTF_writing (1U<<_GTF_writing) +#define _GTF_PWT (5) +#define GTF_PWT (1U<<_GTF_PWT) +#define _GTF_PCD (6) +#define GTF_PCD (1U<<_GTF_PCD) +#define _GTF_PAT (7) +#define GTF_PAT (1U<<_GTF_PAT) +#define _GTF_sub_page (8) +#define GTF_sub_page (1U<<_GTF_sub_page) + +/* + * Subflags for GTF_accept_transfer: + * GTF_transfer_committed: Xen sets this flag to indicate that it is committed + * to transferring ownership of a page frame. When a guest sees this flag + * it must /not/ modify the grant entry until GTF_transfer_completed is + * set by Xen. + * GTF_transfer_completed: It is safe for the guest to spin-wait on this flag + * after reading GTF_transfer_committed. Xen will always write the frame + * address, followed by ORing this flag, in a timely manner. + */ +#define _GTF_transfer_committed (2) +#define GTF_transfer_committed (1U<<_GTF_transfer_committed) +#define _GTF_transfer_completed (3) +#define GTF_transfer_completed (1U<<_GTF_transfer_completed) + +/* + * Version 2 grant table entries. These fulfil the same role as + * version 1 entries, but can represent more complicated operations. + * Any given domain will have either a version 1 or a version 2 table, + * and every entry in the table will be the same version. + * + * The interface by which domains use grant references does not depend + * on the grant table version in use by the other domain. + */ +#if __XEN_INTERFACE_VERSION__ >= 0x0003020a +/* + * Version 1 and version 2 grant entries share a common prefix. The + * fields of the prefix are documented as part of struct + * grant_entry_v1. + */ +struct grant_entry_header { + uint16_t flags; + domid_t domid; +}; +typedef struct grant_entry_header grant_entry_header_t; + +/* + * Version 2 of the grant entry structure. + */ +union grant_entry_v2 { + grant_entry_header_t hdr; + + /* + * This member is used for V1-style full page grants, where either: + * + * -- hdr.type is GTF_accept_transfer, or + * -- hdr.type is GTF_permit_access and GTF_sub_page is not set. + * + * In that case, the frame field has the same semantics as the + * field of the same name in the V1 entry structure. + */ + struct { + grant_entry_header_t hdr; + uint32_t pad0; + uint64_t frame; + } full_page; + + /* + * If the grant type is GTF_grant_access and GTF_sub_page is set, + * @domid is allowed to access bytes [@page_off,@page_off+@length) + * in frame @frame. + */ + struct { + grant_entry_header_t hdr; + uint16_t page_off; + uint16_t length; + uint64_t frame; + } sub_page; + + /* + * If the grant is GTF_transitive, @domid is allowed to use the + * grant @gref in domain @trans_domid, as if it was the local + * domain. Obviously, the transitive access must be compatible + * with the original grant. + * + * The current version of Xen does not allow transitive grants + * to be mapped. + */ + struct { + grant_entry_header_t hdr; + domid_t trans_domid; + uint16_t pad0; + grant_ref_t gref; + } transitive; + + uint32_t __spacer[4]; /* Pad to a power of two */ +}; +typedef union grant_entry_v2 grant_entry_v2_t; + +typedef uint16_t grant_status_t; + +#endif /* __XEN_INTERFACE_VERSION__ */ + +/*********************************** + * GRANT TABLE QUERIES AND USES + */ + +/* ` enum neg_errnoval + * ` HYPERVISOR_grant_table_op(enum grant_table_op cmd, + * ` void *args, + * ` unsigned int count) + * ` + * + * @args points to an array of a per-command data structure. The array + * has @count members + */ + +/* ` enum grant_table_op { // GNTTABOP_* => struct gnttab_* */ +#define GNTTABOP_map_grant_ref 0 +#define GNTTABOP_unmap_grant_ref 1 +#define GNTTABOP_setup_table 2 +#define GNTTABOP_dump_table 3 +#define GNTTABOP_transfer 4 +#define GNTTABOP_copy 5 +#define GNTTABOP_query_size 6 +#define GNTTABOP_unmap_and_replace 7 +#if __XEN_INTERFACE_VERSION__ >= 0x0003020a +#define GNTTABOP_set_version 8 +#define GNTTABOP_get_status_frames 9 +#define GNTTABOP_get_version 10 +#define GNTTABOP_swap_grant_ref 11 +#endif /* __XEN_INTERFACE_VERSION__ */ +/* ` } */ + +/* + * Handle to track a mapping created via a grant reference. + */ +typedef uint32_t grant_handle_t; + +/* + * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access + * by devices and/or host CPUs. If successful, <handle> is a tracking number + * that must be presented later to destroy the mapping(s). On error, <handle> + * is a negative status code. + * NOTES: + * 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address + * via which I/O devices may access the granted frame. + * 2. If GNTMAP_host_map is specified then a mapping will be added at + * either a host virtual address in the current address space, or at + * a PTE at the specified machine address. The type of mapping to + * perform is selected through the GNTMAP_contains_pte flag, and the + * address is specified in <host_addr>. + * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a + * host mapping is destroyed by other means then it is *NOT* guaranteed + * to be accounted to the correct grant reference! + */ +struct gnttab_map_grant_ref { + /* IN parameters. */ + uint64_t host_addr; + uint32_t flags; /* GNTMAP_* */ + grant_ref_t ref; + domid_t dom; + /* OUT parameters. */ + int16_t status; /* => enum grant_status */ + grant_handle_t handle; + uint64_t dev_bus_addr; +}; +typedef struct gnttab_map_grant_ref gnttab_map_grant_ref_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_map_grant_ref_t); + +/* + * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings + * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that + * field is ignored. If non-zero, they must refer to a device/host mapping + * that is tracked by <handle> + * NOTES: + * 1. The call may fail in an undefined manner if either mapping is not + * tracked by <handle>. + * 3. After executing a batch of unmaps, it is guaranteed that no stale + * mappings will remain in the device or host TLBs. + */ +struct gnttab_unmap_grant_ref { + /* IN parameters. */ + uint64_t host_addr; + uint64_t dev_bus_addr; + grant_handle_t handle; + /* OUT parameters. */ + int16_t status; /* => enum grant_status */ +}; +typedef struct gnttab_unmap_grant_ref gnttab_unmap_grant_ref_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t); + +/* + * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least + * <nr_frames> pages. The frame addresses are written to the <frame_list>. + * Only <nr_frames> addresses are written, even if the table is larger. + * NOTES: + * 1. <dom> may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF. + * 3. Xen may not support more than a single grant-table page per domain. + */ +struct gnttab_setup_table { + /* IN parameters. */ + domid_t dom; + uint32_t nr_frames; + /* OUT parameters. */ + int16_t status; /* => enum grant_status */ +#if __XEN_INTERFACE_VERSION__ < 0x00040300 + XEN_GUEST_HANDLE(ulong) frame_list; +#else + XEN_GUEST_HANDLE(xen_pfn_t) frame_list; +#endif +}; +typedef struct gnttab_setup_table gnttab_setup_table_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_t); + +/* + * GNTTABOP_dump_table: Dump the contents of the grant table to the + * xen console. Debugging use only. + */ +struct gnttab_dump_table { + /* IN parameters. */ + domid_t dom; + /* OUT parameters. */ + int16_t status; /* => enum grant_status */ +}; +typedef struct gnttab_dump_table gnttab_dump_table_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_dump_table_t); + +/* + * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The + * foreign domain has previously registered its interest in the transfer via + * <domid, ref>. + * + * Note that, even if the transfer fails, the specified page no longer belongs + * to the calling domain *unless* the error is GNTST_bad_page. + */ +struct gnttab_transfer { + /* IN parameters. */ + xen_pfn_t mfn; + domid_t domid; + grant_ref_t ref; + /* OUT parameters. */ + int16_t status; +}; +typedef struct gnttab_transfer gnttab_transfer_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t); + + +/* + * GNTTABOP_copy: Hypervisor based copy + * source and destinations can be eithers MFNs or, for foreign domains, + * grant references. the foreign domain has to grant read/write access + * in its grant table. + * + * The flags specify what type source and destinations are (either MFN + * or grant reference). + * + * Note that this can also be used to copy data between two domains + * via a third party if the source and destination domains had previously + * grant appropriate access to their pages to the third party. + * + * source_offset specifies an offset in the source frame, dest_offset + * the offset in the target frame and len specifies the number of + * bytes to be copied. + */ + +#define _GNTCOPY_source_gref (0) +#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref) +#define _GNTCOPY_dest_gref (1) +#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref) + +struct gnttab_copy { + /* IN parameters. */ + struct { + union { + grant_ref_t ref; + xen_pfn_t gmfn; + } u; + domid_t domid; + uint16_t offset; + } source, dest; + uint16_t len; + uint16_t flags; /* GNTCOPY_* */ + /* OUT parameters. */ + int16_t status; +}; +typedef struct gnttab_copy gnttab_copy_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t); + +/* + * GNTTABOP_query_size: Query the current and maximum sizes of the shared + * grant table. + * NOTES: + * 1. <dom> may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF. + */ +struct gnttab_query_size { + /* IN parameters. */ + domid_t dom; + /* OUT parameters. */ + uint32_t nr_frames; + uint32_t max_nr_frames; + int16_t status; /* => enum grant_status */ +}; +typedef struct gnttab_query_size gnttab_query_size_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_query_size_t); + +/* + * GNTTABOP_unmap_and_replace: Destroy one or more grant-reference mappings + * tracked by <handle> but atomically replace the page table entry with one + * pointing to the machine address under <new_addr>. <new_addr> will be + * redirected to the null entry. + * NOTES: + * 1. The call may fail in an undefined manner if either mapping is not + * tracked by <handle>. + * 2. After executing a batch of unmaps, it is guaranteed that no stale + * mappings will remain in the device or host TLBs. + */ +struct gnttab_unmap_and_replace { + /* IN parameters. */ + uint64_t host_addr; + uint64_t new_addr; + grant_handle_t handle; + /* OUT parameters. */ + int16_t status; /* => enum grant_status */ +}; +typedef struct gnttab_unmap_and_replace gnttab_unmap_and_replace_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t); + +#if __XEN_INTERFACE_VERSION__ >= 0x0003020a +/* + * GNTTABOP_set_version: Request a particular version of the grant + * table shared table structure. This operation can only be performed + * once in any given domain. It must be performed before any grants + * are activated; otherwise, the domain will be stuck with version 1. + * The only defined versions are 1 and 2. + */ +struct gnttab_set_version { + /* IN/OUT parameters */ + uint32_t version; +}; +typedef struct gnttab_set_version gnttab_set_version_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_set_version_t); + + +/* + * GNTTABOP_get_status_frames: Get the list of frames used to store grant + * status for <dom>. In grant format version 2, the status is separated + * from the other shared grant fields to allow more efficient synchronization + * using barriers instead of atomic cmpexch operations. + * <nr_frames> specify the size of vector <frame_list>. + * The frame addresses are returned in the <frame_list>. + * Only <nr_frames> addresses are returned, even if the table is larger. + * NOTES: + * 1. <dom> may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF. + */ +struct gnttab_get_status_frames { + /* IN parameters. */ + uint32_t nr_frames; + domid_t dom; + /* OUT parameters. */ + int16_t status; /* => enum grant_status */ + XEN_GUEST_HANDLE(uint64_t) frame_list; +}; +typedef struct gnttab_get_status_frames gnttab_get_status_frames_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_t); + +/* + * GNTTABOP_get_version: Get the grant table version which is in + * effect for domain <dom>. + */ +struct gnttab_get_version { + /* IN parameters */ + domid_t dom; + uint16_t pad; + /* OUT parameters */ + uint32_t version; +}; +typedef struct gnttab_get_version gnttab_get_version_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t); + +/* + * GNTTABOP_swap_grant_ref: Swap the contents of two grant entries. + */ +struct gnttab_swap_grant_ref { + /* IN parameters */ + grant_ref_t ref_a; + grant_ref_t ref_b; + /* OUT parameters */ + int16_t status; /* => enum grant_status */ +}; +typedef struct gnttab_swap_grant_ref gnttab_swap_grant_ref_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_swap_grant_ref_t); + +#endif /* __XEN_INTERFACE_VERSION__ */ + +/* + * Bitfield values for gnttab_map_grant_ref.flags. + */ + /* Map the grant entry for access by I/O devices. */ +#define _GNTMAP_device_map (0) +#define GNTMAP_device_map (1<<_GNTMAP_device_map) + /* Map the grant entry for access by host CPUs. */ +#define _GNTMAP_host_map (1) +#define GNTMAP_host_map (1<<_GNTMAP_host_map) + /* Accesses to the granted frame will be restricted to read-only access. */ +#define _GNTMAP_readonly (2) +#define GNTMAP_readonly (1<<_GNTMAP_readonly) + /* + * GNTMAP_host_map subflag: + * 0 => The host mapping is usable only by the guest OS. + * 1 => The host mapping is usable by guest OS + current application. + */ +#define _GNTMAP_application_map (3) +#define GNTMAP_application_map (1<<_GNTMAP_application_map) + + /* + * GNTMAP_contains_pte subflag: + * 0 => This map request contains a host virtual address. + * 1 => This map request contains the machine addess of the PTE to update. + */ +#define _GNTMAP_contains_pte (4) +#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte) + +#define _GNTMAP_can_fail (5) +#define GNTMAP_can_fail (1<<_GNTMAP_can_fail) + +/* + * Bits to be placed in guest kernel available PTE bits (architecture + * dependent; only supported when XENFEAT_gnttab_map_avail_bits is set). + */ +#define _GNTMAP_guest_avail0 (16) +#define GNTMAP_guest_avail_mask ((uint32_t)~0 << _GNTMAP_guest_avail0) + +/* + * Values for error status returns. All errors are -ve. + */ +/* ` enum grant_status { */ +#define GNTST_okay (0) /* Normal return. */ +#define GNTST_general_error (-1) /* General undefined error. */ +#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */ +#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */ +#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */ +#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */ +#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/ +#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */ +#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */ +#define GNTST_bad_page (-9) /* Specified page was invalid for op. */ +#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary. */ +#define GNTST_address_too_big (-11) /* transfer page address too large. */ +#define GNTST_eagain (-12) /* Operation not done; try again. */ +/* ` } */ + +#define GNTTABOP_error_msgs { \ + "okay", \ + "undefined error", \ + "unrecognised domain id", \ + "invalid grant reference", \ + "invalid mapping handle", \ + "invalid virtual address", \ + "invalid device address", \ + "no spare translation slot in the I/O MMU", \ + "permission denied", \ + "bad page", \ + "copy arguments cross page boundary", \ + "page address size too large", \ + "operation not done; try again" \ +} + +#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/hvm/hvm_op.h b/roms/ipxe/src/include/xen/hvm/hvm_op.h new file mode 100644 index 000000000..469ad4fbc --- /dev/null +++ b/roms/ipxe/src/include/xen/hvm/hvm_op.h @@ -0,0 +1,384 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __XEN_PUBLIC_HVM_HVM_OP_H__ +#define __XEN_PUBLIC_HVM_HVM_OP_H__ + +FILE_LICENCE ( MIT ); + +#include "../xen.h" +#include "../trace.h" +#include "../event_channel.h" + +/* Get/set subcommands: extra argument == pointer to xen_hvm_param struct. */ +#define HVMOP_set_param 0 +#define HVMOP_get_param 1 +struct xen_hvm_param { + domid_t domid; /* IN */ + uint32_t index; /* IN */ + uint64_t value; /* IN/OUT */ +}; +typedef struct xen_hvm_param xen_hvm_param_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_param_t); + +/* Set the logical level of one of a domain's PCI INTx wires. */ +#define HVMOP_set_pci_intx_level 2 +struct xen_hvm_set_pci_intx_level { + /* Domain to be updated. */ + domid_t domid; + /* PCI INTx identification in PCI topology (domain:bus:device:intx). */ + uint8_t domain, bus, device, intx; + /* Assertion level (0 = unasserted, 1 = asserted). */ + uint8_t level; +}; +typedef struct xen_hvm_set_pci_intx_level xen_hvm_set_pci_intx_level_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_intx_level_t); + +/* Set the logical level of one of a domain's ISA IRQ wires. */ +#define HVMOP_set_isa_irq_level 3 +struct xen_hvm_set_isa_irq_level { + /* Domain to be updated. */ + domid_t domid; + /* ISA device identification, by ISA IRQ (0-15). */ + uint8_t isa_irq; + /* Assertion level (0 = unasserted, 1 = asserted). */ + uint8_t level; +}; +typedef struct xen_hvm_set_isa_irq_level xen_hvm_set_isa_irq_level_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_isa_irq_level_t); + +#define HVMOP_set_pci_link_route 4 +struct xen_hvm_set_pci_link_route { + /* Domain to be updated. */ + domid_t domid; + /* PCI link identifier (0-3). */ + uint8_t link; + /* ISA IRQ (1-15), or 0 (disable link). */ + uint8_t isa_irq; +}; +typedef struct xen_hvm_set_pci_link_route xen_hvm_set_pci_link_route_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_link_route_t); + +/* Flushes all VCPU TLBs: @arg must be NULL. */ +#define HVMOP_flush_tlbs 5 + +typedef enum { + HVMMEM_ram_rw, /* Normal read/write guest RAM */ + HVMMEM_ram_ro, /* Read-only; writes are discarded */ + HVMMEM_mmio_dm, /* Reads and write go to the device model */ +} hvmmem_type_t; + +/* Following tools-only interfaces may change in future. */ +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +/* Track dirty VRAM. */ +#define HVMOP_track_dirty_vram 6 +struct xen_hvm_track_dirty_vram { + /* Domain to be tracked. */ + domid_t domid; + /* Number of pages to track. */ + uint32_t nr; + /* First pfn to track. */ + uint64_aligned_t first_pfn; + /* OUT variable. */ + /* Dirty bitmap buffer. */ + XEN_GUEST_HANDLE_64(uint8) dirty_bitmap; +}; +typedef struct xen_hvm_track_dirty_vram xen_hvm_track_dirty_vram_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_track_dirty_vram_t); + +/* Notify that some pages got modified by the Device Model. */ +#define HVMOP_modified_memory 7 +struct xen_hvm_modified_memory { + /* Domain to be updated. */ + domid_t domid; + /* Number of pages. */ + uint32_t nr; + /* First pfn. */ + uint64_aligned_t first_pfn; +}; +typedef struct xen_hvm_modified_memory xen_hvm_modified_memory_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_modified_memory_t); + +#define HVMOP_set_mem_type 8 +/* Notify that a region of memory is to be treated in a specific way. */ +struct xen_hvm_set_mem_type { + /* Domain to be updated. */ + domid_t domid; + /* Memory type */ + uint16_t hvmmem_type; + /* Number of pages. */ + uint32_t nr; + /* First pfn. */ + uint64_aligned_t first_pfn; +}; +typedef struct xen_hvm_set_mem_type xen_hvm_set_mem_type_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_type_t); + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + +/* Hint from PV drivers for pagetable destruction. */ +#define HVMOP_pagetable_dying 9 +struct xen_hvm_pagetable_dying { + /* Domain with a pagetable about to be destroyed. */ + domid_t domid; + uint16_t pad[3]; /* align next field on 8-byte boundary */ + /* guest physical address of the toplevel pagetable dying */ + uint64_t gpa; +}; +typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_pagetable_dying_t); + +/* Get the current Xen time, in nanoseconds since system boot. */ +#define HVMOP_get_time 10 +struct xen_hvm_get_time { + uint64_t now; /* OUT */ +}; +typedef struct xen_hvm_get_time xen_hvm_get_time_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_time_t); + +#define HVMOP_xentrace 11 +struct xen_hvm_xentrace { + uint16_t event, extra_bytes; + uint8_t extra[TRACE_EXTRA_MAX * sizeof(uint32_t)]; +}; +typedef struct xen_hvm_xentrace xen_hvm_xentrace_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_xentrace_t); + +/* Following tools-only interfaces may change in future. */ +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +/* Deprecated by XENMEM_access_op_set_access */ +#define HVMOP_set_mem_access 12 + +/* Deprecated by XENMEM_access_op_get_access */ +#define HVMOP_get_mem_access 13 + +#define HVMOP_inject_trap 14 +/* Inject a trap into a VCPU, which will get taken up on the next + * scheduling of it. Note that the caller should know enough of the + * state of the CPU before injecting, to know what the effect of + * injecting the trap will be. + */ +struct xen_hvm_inject_trap { + /* Domain to be queried. */ + domid_t domid; + /* VCPU */ + uint32_t vcpuid; + /* Vector number */ + uint32_t vector; + /* Trap type (HVMOP_TRAP_*) */ + uint32_t type; +/* NB. This enumeration precisely matches hvm.h:X86_EVENTTYPE_* */ +# define HVMOP_TRAP_ext_int 0 /* external interrupt */ +# define HVMOP_TRAP_nmi 2 /* nmi */ +# define HVMOP_TRAP_hw_exc 3 /* hardware exception */ +# define HVMOP_TRAP_sw_int 4 /* software interrupt (CD nn) */ +# define HVMOP_TRAP_pri_sw_exc 5 /* ICEBP (F1) */ +# define HVMOP_TRAP_sw_exc 6 /* INT3 (CC), INTO (CE) */ + /* Error code, or ~0u to skip */ + uint32_t error_code; + /* Intruction length */ + uint32_t insn_len; + /* CR2 for page faults */ + uint64_aligned_t cr2; +}; +typedef struct xen_hvm_inject_trap xen_hvm_inject_trap_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_trap_t); + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + +#define HVMOP_get_mem_type 15 +/* Return hvmmem_type_t for the specified pfn. */ +struct xen_hvm_get_mem_type { + /* Domain to be queried. */ + domid_t domid; + /* OUT variable. */ + uint16_t mem_type; + uint16_t pad[2]; /* align next field on 8-byte boundary */ + /* IN variable. */ + uint64_t pfn; +}; +typedef struct xen_hvm_get_mem_type xen_hvm_get_mem_type_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_mem_type_t); + +/* Following tools-only interfaces may change in future. */ +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +/* MSI injection for emulated devices */ +#define HVMOP_inject_msi 16 +struct xen_hvm_inject_msi { + /* Domain to be injected */ + domid_t domid; + /* Data -- lower 32 bits */ + uint32_t data; + /* Address (0xfeexxxxx) */ + uint64_t addr; +}; +typedef struct xen_hvm_inject_msi xen_hvm_inject_msi_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_msi_t); + +/* + * IOREQ Servers + * + * The interface between an I/O emulator an Xen is called an IOREQ Server. + * A domain supports a single 'legacy' IOREQ Server which is instantiated if + * parameter... + * + * HVM_PARAM_IOREQ_PFN is read (to get the gmfn containing the synchronous + * ioreq structures), or... + * HVM_PARAM_BUFIOREQ_PFN is read (to get the gmfn containing the buffered + * ioreq ring), or... + * HVM_PARAM_BUFIOREQ_EVTCHN is read (to get the event channel that Xen uses + * to request buffered I/O emulation). + * + * The following hypercalls facilitate the creation of IOREQ Servers for + * 'secondary' emulators which are invoked to implement port I/O, memory, or + * PCI config space ranges which they explicitly register. + */ + +typedef uint16_t ioservid_t; + +/* + * HVMOP_create_ioreq_server: Instantiate a new IOREQ Server for a secondary + * emulator servicing domain <domid>. + * + * The <id> handed back is unique for <domid>. If <handle_bufioreq> is zero + * the buffered ioreq ring will not be allocated and hence all emulation + * requestes to this server will be synchronous. + */ +#define HVMOP_create_ioreq_server 17 +struct xen_hvm_create_ioreq_server { + domid_t domid; /* IN - domain to be serviced */ + uint8_t handle_bufioreq; /* IN - should server handle buffered ioreqs */ + ioservid_t id; /* OUT - server id */ +}; +typedef struct xen_hvm_create_ioreq_server xen_hvm_create_ioreq_server_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_create_ioreq_server_t); + +/* + * HVMOP_get_ioreq_server_info: Get all the information necessary to access + * IOREQ Server <id>. + * + * The emulator needs to map the synchronous ioreq structures and buffered + * ioreq ring (if it exists) that Xen uses to request emulation. These are + * hosted in domain <domid>'s gmfns <ioreq_pfn> and <bufioreq_pfn> + * respectively. In addition, if the IOREQ Server is handling buffered + * emulation requests, the emulator needs to bind to event channel + * <bufioreq_port> to listen for them. (The event channels used for + * synchronous emulation requests are specified in the per-CPU ioreq + * structures in <ioreq_pfn>). + * If the IOREQ Server is not handling buffered emulation requests then the + * values handed back in <bufioreq_pfn> and <bufioreq_port> will both be 0. + */ +#define HVMOP_get_ioreq_server_info 18 +struct xen_hvm_get_ioreq_server_info { + domid_t domid; /* IN - domain to be serviced */ + ioservid_t id; /* IN - server id */ + evtchn_port_t bufioreq_port; /* OUT - buffered ioreq port */ + uint64_aligned_t ioreq_pfn; /* OUT - sync ioreq pfn */ + uint64_aligned_t bufioreq_pfn; /* OUT - buffered ioreq pfn */ +}; +typedef struct xen_hvm_get_ioreq_server_info xen_hvm_get_ioreq_server_info_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_get_ioreq_server_info_t); + +/* + * HVM_map_io_range_to_ioreq_server: Register an I/O range of domain <domid> + * for emulation by the client of IOREQ + * Server <id> + * HVM_unmap_io_range_from_ioreq_server: Deregister an I/O range of <domid> + * for emulation by the client of IOREQ + * Server <id> + * + * There are three types of I/O that can be emulated: port I/O, memory accesses + * and PCI config space accesses. The <type> field denotes which type of range + * the <start> and <end> (inclusive) fields are specifying. + * PCI config space ranges are specified by segment/bus/device/function values + * which should be encoded using the HVMOP_PCI_SBDF helper macro below. + * + * NOTE: unless an emulation request falls entirely within a range mapped + * by a secondary emulator, it will not be passed to that emulator. + */ +#define HVMOP_map_io_range_to_ioreq_server 19 +#define HVMOP_unmap_io_range_from_ioreq_server 20 +struct xen_hvm_io_range { + domid_t domid; /* IN - domain to be serviced */ + ioservid_t id; /* IN - server id */ + uint32_t type; /* IN - type of range */ +# define HVMOP_IO_RANGE_PORT 0 /* I/O port range */ +# define HVMOP_IO_RANGE_MEMORY 1 /* MMIO range */ +# define HVMOP_IO_RANGE_PCI 2 /* PCI segment/bus/dev/func range */ + uint64_aligned_t start, end; /* IN - inclusive start and end of range */ +}; +typedef struct xen_hvm_io_range xen_hvm_io_range_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_io_range_t); + +#define HVMOP_PCI_SBDF(s,b,d,f) \ + ((((s) & 0xffff) << 16) | \ + (((b) & 0xff) << 8) | \ + (((d) & 0x1f) << 3) | \ + ((f) & 0x07)) + +/* + * HVMOP_destroy_ioreq_server: Destroy the IOREQ Server <id> servicing domain + * <domid>. + * + * Any registered I/O ranges will be automatically deregistered. + */ +#define HVMOP_destroy_ioreq_server 21 +struct xen_hvm_destroy_ioreq_server { + domid_t domid; /* IN - domain to be serviced */ + ioservid_t id; /* IN - server id */ +}; +typedef struct xen_hvm_destroy_ioreq_server xen_hvm_destroy_ioreq_server_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_destroy_ioreq_server_t); + +/* + * HVMOP_set_ioreq_server_state: Enable or disable the IOREQ Server <id> servicing + * domain <domid>. + * + * The IOREQ Server will not be passed any emulation requests until it is in the + * enabled state. + * Note that the contents of the ioreq_pfn and bufioreq_fn (see + * HVMOP_get_ioreq_server_info) are not meaningful until the IOREQ Server is in + * the enabled state. + */ +#define HVMOP_set_ioreq_server_state 22 +struct xen_hvm_set_ioreq_server_state { + domid_t domid; /* IN - domain to be serviced */ + ioservid_t id; /* IN - server id */ + uint8_t enabled; /* IN - enabled? */ +}; +typedef struct xen_hvm_set_ioreq_server_state xen_hvm_set_ioreq_server_state_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_ioreq_server_state_t); + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + +#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/hvm/params.h b/roms/ipxe/src/include/xen/hvm/params.h new file mode 100644 index 000000000..49e06586d --- /dev/null +++ b/roms/ipxe/src/include/xen/hvm/params.h @@ -0,0 +1,158 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __XEN_PUBLIC_HVM_PARAMS_H__ +#define __XEN_PUBLIC_HVM_PARAMS_H__ + +FILE_LICENCE ( MIT ); + +#include "hvm_op.h" + +/* + * Parameter space for HVMOP_{set,get}_param. + */ + +/* + * How should CPU0 event-channel notifications be delivered? + * val[63:56] == 0: val[55:0] is a delivery GSI (Global System Interrupt). + * val[63:56] == 1: val[55:0] is a delivery PCI INTx line, as follows: + * Domain = val[47:32], Bus = val[31:16], + * DevFn = val[15: 8], IntX = val[ 1: 0] + * val[63:56] == 2: val[7:0] is a vector number, check for + * XENFEAT_hvm_callback_vector to know if this delivery + * method is available. + * If val == 0 then CPU0 event-channel notifications are not delivered. + */ +#define HVM_PARAM_CALLBACK_IRQ 0 + +/* + * These are not used by Xen. They are here for convenience of HVM-guest + * xenbus implementations. + */ +#define HVM_PARAM_STORE_PFN 1 +#define HVM_PARAM_STORE_EVTCHN 2 + +#define HVM_PARAM_PAE_ENABLED 4 + +#define HVM_PARAM_IOREQ_PFN 5 + +#define HVM_PARAM_BUFIOREQ_PFN 6 +#define HVM_PARAM_BUFIOREQ_EVTCHN 26 + +#if defined(__i386__) || defined(__x86_64__) + +/* Expose Viridian interfaces to this HVM guest? */ +#define HVM_PARAM_VIRIDIAN 9 + +#endif + +/* + * Set mode for virtual timers (currently x86 only): + * delay_for_missed_ticks (default): + * Do not advance a vcpu's time beyond the correct delivery time for + * interrupts that have been missed due to preemption. Deliver missed + * interrupts when the vcpu is rescheduled and advance the vcpu's virtual + * time stepwise for each one. + * no_delay_for_missed_ticks: + * As above, missed interrupts are delivered, but guest time always tracks + * wallclock (i.e., real) time while doing so. + * no_missed_ticks_pending: + * No missed interrupts are held pending. Instead, to ensure ticks are + * delivered at some non-zero rate, if we detect missed ticks then the + * internal tick alarm is not disabled if the VCPU is preempted during the + * next tick period. + * one_missed_tick_pending: + * Missed interrupts are collapsed together and delivered as one 'late tick'. + * Guest time always tracks wallclock (i.e., real) time. + */ +#define HVM_PARAM_TIMER_MODE 10 +#define HVMPTM_delay_for_missed_ticks 0 +#define HVMPTM_no_delay_for_missed_ticks 1 +#define HVMPTM_no_missed_ticks_pending 2 +#define HVMPTM_one_missed_tick_pending 3 + +/* Boolean: Enable virtual HPET (high-precision event timer)? (x86-only) */ +#define HVM_PARAM_HPET_ENABLED 11 + +/* Identity-map page directory used by Intel EPT when CR0.PG=0. */ +#define HVM_PARAM_IDENT_PT 12 + +/* Device Model domain, defaults to 0. */ +#define HVM_PARAM_DM_DOMAIN 13 + +/* ACPI S state: currently support S0 and S3 on x86. */ +#define HVM_PARAM_ACPI_S_STATE 14 + +/* TSS used on Intel when CR0.PE=0. */ +#define HVM_PARAM_VM86_TSS 15 + +/* Boolean: Enable aligning all periodic vpts to reduce interrupts */ +#define HVM_PARAM_VPT_ALIGN 16 + +/* Console debug shared memory ring and event channel */ +#define HVM_PARAM_CONSOLE_PFN 17 +#define HVM_PARAM_CONSOLE_EVTCHN 18 + +/* + * Select location of ACPI PM1a and TMR control blocks. Currently two locations + * are supported, specified by version 0 or 1 in this parameter: + * - 0: default, use the old addresses + * PM1A_EVT == 0x1f40; PM1A_CNT == 0x1f44; PM_TMR == 0x1f48 + * - 1: use the new default qemu addresses + * PM1A_EVT == 0xb000; PM1A_CNT == 0xb004; PM_TMR == 0xb008 + * You can find these address definitions in <hvm/ioreq.h> + */ +#define HVM_PARAM_ACPI_IOPORTS_LOCATION 19 + +/* Enable blocking memory events, async or sync (pause vcpu until response) + * onchangeonly indicates messages only on a change of value */ +#define HVM_PARAM_MEMORY_EVENT_CR0 20 +#define HVM_PARAM_MEMORY_EVENT_CR3 21 +#define HVM_PARAM_MEMORY_EVENT_CR4 22 +#define HVM_PARAM_MEMORY_EVENT_INT3 23 +#define HVM_PARAM_MEMORY_EVENT_SINGLE_STEP 25 +#define HVM_PARAM_MEMORY_EVENT_MSR 30 + +#define HVMPME_MODE_MASK (3 << 0) +#define HVMPME_mode_disabled 0 +#define HVMPME_mode_async 1 +#define HVMPME_mode_sync 2 +#define HVMPME_onchangeonly (1 << 2) + +/* Boolean: Enable nestedhvm (hvm only) */ +#define HVM_PARAM_NESTEDHVM 24 + +/* Params for the mem event rings */ +#define HVM_PARAM_PAGING_RING_PFN 27 +#define HVM_PARAM_ACCESS_RING_PFN 28 +#define HVM_PARAM_SHARING_RING_PFN 29 + +/* SHUTDOWN_* action in case of a triple fault */ +#define HVM_PARAM_TRIPLE_FAULT_REASON 31 + +#define HVM_PARAM_IOREQ_SERVER_PFN 32 +#define HVM_PARAM_NR_IOREQ_SERVER_PAGES 33 + +/* Location of the VM Generation ID in guest physical address space. */ +#define HVM_PARAM_VM_GENERATION_ID_ADDR 34 + +#define HVM_NR_PARAMS 35 + +#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ diff --git a/roms/ipxe/src/include/xen/import.pl b/roms/ipxe/src/include/xen/import.pl new file mode 100755 index 000000000..9f09a77a4 --- /dev/null +++ b/roms/ipxe/src/include/xen/import.pl @@ -0,0 +1,116 @@ +#!/usr/bin/perl -w + +=head1 NAME + +import.pl + +=head1 SYNOPSIS + +import.pl [options] /path/to/xen + +Options: + + -h,--help Display brief help message + -v,--verbose Increase verbosity + -q,--quiet Decrease verbosity + +=cut + +use File::Spec::Functions qw ( :ALL ); +use File::Find; +use File::Path; +use Getopt::Long; +use Pod::Usage; +use FindBin; +use strict; +use warnings; + +my $verbosity = 0; + +sub try_import_file { + my $ipxedir = shift; + my $xendir = shift; + my $filename = shift; + + # Skip everything except headers + return unless $filename =~ /\.h$/; + + # Search for importable header + ( undef, my $subdir, undef ) = splitpath ( $filename ); + my $outfile = catfile ( $ipxedir, $filename ); + my $infile = catfile ( $xendir, "xen/include/public", $filename ); + die "$infile does not exist\n" unless -e $infile; + + # Import header file + print "$filename <- ".catfile ( $xendir, $filename )."\n" + if $verbosity >= 1; + open my $infh, "<", $infile or die "Could not open $infile: $!\n"; + mkpath ( catdir ( $xendir, $subdir ) ); + open my $outfh, ">", $outfile or die "Could not open $outfile: $!\n"; + my @dependencies = (); + my $maybe_guard; + my $guard; + while ( <$infh> ) { + # Strip CR and trailing whitespace + s/\r//g; + s/\s*$//g; + chomp; + # Update include lines, and record included files + if ( /^\#include\s+[<\"](\S+)[>\"]/ ) { + push @dependencies, catfile ( $subdir, $1 ); + } + # Write out line + print $outfh "$_\n"; + # Apply FILE_LICENCE() immediately after include guard + if ( defined $maybe_guard ) { + if ( /^\#define\s+_+${maybe_guard}_H_*$/ ) { + die "Duplicate header guard detected in $infile\n" if $guard; + $guard = $maybe_guard; + print $outfh "\nFILE_LICENCE ( MIT );\n"; + } + undef $maybe_guard; + } + if ( /^#ifndef\s+_+(\S+)_H_*$/ ) { + $maybe_guard = $1; + } + } + close $outfh; + close $infh; + # Warn if no header guard was detected + warn "Cannot detect header guard in $infile\n" unless $guard; + # Recurse to handle any included files that we don't already have + foreach my $dependency ( @dependencies ) { + if ( ! -e catfile ( $ipxedir, $dependency ) ) { + print "...following dependency on $dependency\n" if $verbosity >= 1; + try_import_file ( $ipxedir, $xendir, $dependency ); + } + } + return; +} + +# Parse command-line options +Getopt::Long::Configure ( 'bundling', 'auto_abbrev' ); +GetOptions ( + 'verbose|v+' => sub { $verbosity++; }, + 'quiet|q+' => sub { $verbosity--; }, + 'help|h' => sub { pod2usage ( 1 ); }, +) or die "Could not parse command-line options\n"; +pod2usage ( 1 ) unless @ARGV == 1; +my $xendir = shift; + +# Identify Xen import directory +die "Directory \"$xendir\" does not appear to contain the Xen source tree\n" + unless -e catfile ( $xendir, "xen/include/public/xen.h" ); + +# Identify iPXE Xen includes directory +my $ipxedir = $FindBin::Bin; +die "Directory \"$ipxedir\" does not appear to contain the iPXE Xen includes\n" + unless -e catfile ( $ipxedir, "../../include/ipxe" ); + +print "Importing Xen headers into $ipxedir\nfrom $xendir\n" + if $verbosity >= 1; + +# Import headers +find ( { wanted => sub { + try_import_file ( $ipxedir, $xendir, abs2rel ( $_, $ipxedir ) ); +}, no_chdir => 1 }, $ipxedir ); diff --git a/roms/ipxe/src/include/xen/io/netif.h b/roms/ipxe/src/include/xen/io/netif.h new file mode 100644 index 000000000..ae12eab73 --- /dev/null +++ b/roms/ipxe/src/include/xen/io/netif.h @@ -0,0 +1,307 @@ +/****************************************************************************** + * netif.h + * + * Unified network-device I/O interface for Xen guest OSes. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2003-2004, Keir Fraser + */ + +#ifndef __XEN_PUBLIC_IO_NETIF_H__ +#define __XEN_PUBLIC_IO_NETIF_H__ + +FILE_LICENCE ( MIT ); + +#include "ring.h" +#include "../grant_table.h" + +/* + * Older implementation of Xen network frontend / backend has an + * implicit dependency on the MAX_SKB_FRAGS as the maximum number of + * ring slots a skb can use. Netfront / netback may not work as + * expected when frontend and backend have different MAX_SKB_FRAGS. + * + * A better approach is to add mechanism for netfront / netback to + * negotiate this value. However we cannot fix all possible + * frontends, so we need to define a value which states the minimum + * slots backend must support. + * + * The minimum value derives from older Linux kernel's MAX_SKB_FRAGS + * (18), which is proved to work with most frontends. Any new backend + * which doesn't negotiate with frontend should expect frontend to + * send a valid packet using slots up to this value. + */ +#define XEN_NETIF_NR_SLOTS_MIN 18 + +/* + * Notifications after enqueuing any type of message should be conditional on + * the appropriate req_event or rsp_event field in the shared ring. + * If the client sends notification for rx requests then it should specify + * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume + * that it cannot safely queue packets (as it may not be kicked to send them). + */ + +/* + * "feature-split-event-channels" is introduced to separate guest TX + * and RX notification. Backend either doesn't support this feature or + * advertises it via xenstore as 0 (disabled) or 1 (enabled). + * + * To make use of this feature, frontend should allocate two event + * channels for TX and RX, advertise them to backend as + * "event-channel-tx" and "event-channel-rx" respectively. If frontend + * doesn't want to use this feature, it just writes "event-channel" + * node as before. + */ + +/* + * Multiple transmit and receive queues: + * If supported, the backend will write the key "multi-queue-max-queues" to + * the directory for that vif, and set its value to the maximum supported + * number of queues. + * Frontends that are aware of this feature and wish to use it can write the + * key "multi-queue-num-queues", set to the number they wish to use, which + * must be greater than zero, and no more than the value reported by the backend + * in "multi-queue-max-queues". + * + * Queues replicate the shared rings and event channels. + * "feature-split-event-channels" may optionally be used when using + * multiple queues, but is not mandatory. + * + * Each queue consists of one shared ring pair, i.e. there must be the same + * number of tx and rx rings. + * + * For frontends requesting just one queue, the usual event-channel and + * ring-ref keys are written as before, simplifying the backend processing + * to avoid distinguishing between a frontend that doesn't understand the + * multi-queue feature, and one that does, but requested only one queue. + * + * Frontends requesting two or more queues must not write the toplevel + * event-channel (or event-channel-{tx,rx}) and {tx,rx}-ring-ref keys, + * instead writing those keys under sub-keys having the name "queue-N" where + * N is the integer ID of the queue for which those keys belong. Queues + * are indexed from zero. For example, a frontend with two queues and split + * event channels must write the following set of queue-related keys: + * + * /local/domain/1/device/vif/0/multi-queue-num-queues = "2" + * /local/domain/1/device/vif/0/queue-0 = "" + * /local/domain/1/device/vif/0/queue-0/tx-ring-ref = "<ring-ref-tx0>" + * /local/domain/1/device/vif/0/queue-0/rx-ring-ref = "<ring-ref-rx0>" + * /local/domain/1/device/vif/0/queue-0/event-channel-tx = "<evtchn-tx0>" + * /local/domain/1/device/vif/0/queue-0/event-channel-rx = "<evtchn-rx0>" + * /local/domain/1/device/vif/0/queue-1 = "" + * /local/domain/1/device/vif/0/queue-1/tx-ring-ref = "<ring-ref-tx1>" + * /local/domain/1/device/vif/0/queue-1/rx-ring-ref = "<ring-ref-rx1" + * /local/domain/1/device/vif/0/queue-1/event-channel-tx = "<evtchn-tx1>" + * /local/domain/1/device/vif/0/queue-1/event-channel-rx = "<evtchn-rx1>" + * + * If there is any inconsistency in the XenStore data, the backend may + * choose not to connect any queues, instead treating the request as an + * error. This includes scenarios where more (or fewer) queues were + * requested than the frontend provided details for. + * + * Mapping of packets to queues is considered to be a function of the + * transmitting system (backend or frontend) and is not negotiated + * between the two. Guests are free to transmit packets on any queue + * they choose, provided it has been set up correctly. Guests must be + * prepared to receive packets on any queue they have requested be set up. + */ + +/* + * "feature-no-csum-offload" should be used to turn IPv4 TCP/UDP checksum + * offload off or on. If it is missing then the feature is assumed to be on. + * "feature-ipv6-csum-offload" should be used to turn IPv6 TCP/UDP checksum + * offload on or off. If it is missing then the feature is assumed to be off. + */ + +/* + * "feature-gso-tcpv4" and "feature-gso-tcpv6" advertise the capability to + * handle large TCP packets (in IPv4 or IPv6 form respectively). Neither + * frontends nor backends are assumed to be capable unless the flags are + * present. + */ + +/* + * This is the 'wire' format for packets: + * Request 1: netif_tx_request -- NETTXF_* (any flags) + * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info) + * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE) + * Request 4: netif_tx_request -- NETTXF_more_data + * Request 5: netif_tx_request -- NETTXF_more_data + * ... + * Request N: netif_tx_request -- 0 + */ + +/* Protocol checksum field is blank in the packet (hardware offload)? */ +#define _NETTXF_csum_blank (0) +#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank) + +/* Packet data has been validated against protocol checksum. */ +#define _NETTXF_data_validated (1) +#define NETTXF_data_validated (1U<<_NETTXF_data_validated) + +/* Packet continues in the next request descriptor. */ +#define _NETTXF_more_data (2) +#define NETTXF_more_data (1U<<_NETTXF_more_data) + +/* Packet to be followed by extra descriptor(s). */ +#define _NETTXF_extra_info (3) +#define NETTXF_extra_info (1U<<_NETTXF_extra_info) + +#define XEN_NETIF_MAX_TX_SIZE 0xFFFF +struct netif_tx_request { + grant_ref_t gref; /* Reference to buffer page */ + uint16_t offset; /* Offset within buffer page */ + uint16_t flags; /* NETTXF_* */ + uint16_t id; /* Echoed in response message. */ + uint16_t size; /* Packet size in bytes. */ +}; +typedef struct netif_tx_request netif_tx_request_t; + +/* Types of netif_extra_info descriptors. */ +#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */ +#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */ +#define XEN_NETIF_EXTRA_TYPE_MCAST_ADD (2) /* u.mcast */ +#define XEN_NETIF_EXTRA_TYPE_MCAST_DEL (3) /* u.mcast */ +#define XEN_NETIF_EXTRA_TYPE_MAX (4) + +/* netif_extra_info flags. */ +#define _XEN_NETIF_EXTRA_FLAG_MORE (0) +#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE) + +/* GSO types */ +#define XEN_NETIF_GSO_TYPE_NONE (0) +#define XEN_NETIF_GSO_TYPE_TCPV4 (1) +#define XEN_NETIF_GSO_TYPE_TCPV6 (2) + +/* + * This structure needs to fit within both netif_tx_request and + * netif_rx_response for compatibility. + */ +struct netif_extra_info { + uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */ + uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */ + + union { + /* + * XEN_NETIF_EXTRA_TYPE_GSO: + */ + struct { + /* + * Maximum payload size of each segment. For example, for TCP this + * is just the path MSS. + */ + uint16_t size; + + /* + * GSO type. This determines the protocol of the packet and any + * extra features required to segment the packet properly. + */ + uint8_t type; /* XEN_NETIF_GSO_TYPE_* */ + + /* Future expansion. */ + uint8_t pad; + + /* + * GSO features. This specifies any extra GSO features required + * to process this packet, such as ECN support for TCPv4. + */ + uint16_t features; /* XEN_NETIF_GSO_FEAT_* */ + } gso; + + /* + * XEN_NETIF_EXTRA_TYPE_MCAST_{ADD,DEL}: + * Backend advertises availability via 'feature-multicast-control' + * xenbus node containing value '1'. + * Frontend requests this feature by advertising + * 'request-multicast-control' xenbus node containing value '1'. + * If multicast control is requested then multicast flooding is + * disabled and the frontend must explicitly register its interest + * in multicast groups using dummy transmit requests containing + * MCAST_{ADD,DEL} extra-info fragments. + */ + struct { + uint8_t addr[6]; /* Address to add/remove. */ + } mcast; + + uint16_t pad[3]; + } u; +}; +typedef struct netif_extra_info netif_extra_info_t; + +struct netif_tx_response { + uint16_t id; + int16_t status; /* NETIF_RSP_* */ +}; +typedef struct netif_tx_response netif_tx_response_t; + +struct netif_rx_request { + uint16_t id; /* Echoed in response message. */ + grant_ref_t gref; /* Reference to incoming granted frame */ +}; +typedef struct netif_rx_request netif_rx_request_t; + +/* Packet data has been validated against protocol checksum. */ +#define _NETRXF_data_validated (0) +#define NETRXF_data_validated (1U<<_NETRXF_data_validated) + +/* Protocol checksum field is blank in the packet (hardware offload)? */ +#define _NETRXF_csum_blank (1) +#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank) + +/* Packet continues in the next request descriptor. */ +#define _NETRXF_more_data (2) +#define NETRXF_more_data (1U<<_NETRXF_more_data) + +/* Packet to be followed by extra descriptor(s). */ +#define _NETRXF_extra_info (3) +#define NETRXF_extra_info (1U<<_NETRXF_extra_info) + +struct netif_rx_response { + uint16_t id; + uint16_t offset; /* Offset in page of start of received packet */ + uint16_t flags; /* NETRXF_* */ + int16_t status; /* -ve: NETIF_RSP_* ; +ve: Rx'ed pkt size. */ +}; +typedef struct netif_rx_response netif_rx_response_t; + +/* + * Generate netif ring structures and types. + */ + +DEFINE_RING_TYPES(netif_tx, struct netif_tx_request, struct netif_tx_response); +DEFINE_RING_TYPES(netif_rx, struct netif_rx_request, struct netif_rx_response); + +#define NETIF_RSP_DROPPED -2 +#define NETIF_RSP_ERROR -1 +#define NETIF_RSP_OKAY 0 +/* No response: used for auxiliary requests (e.g., netif_tx_extra). */ +#define NETIF_RSP_NULL 1 + +#endif + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/io/ring.h b/roms/ipxe/src/include/xen/io/ring.h new file mode 100644 index 000000000..89d738691 --- /dev/null +++ b/roms/ipxe/src/include/xen/io/ring.h @@ -0,0 +1,314 @@ +/****************************************************************************** + * ring.h + * + * Shared producer-consumer ring macros. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Tim Deegan and Andrew Warfield November 2004. + */ + +#ifndef __XEN_PUBLIC_IO_RING_H__ +#define __XEN_PUBLIC_IO_RING_H__ + +FILE_LICENCE ( MIT ); + +#include "../xen-compat.h" + +#if __XEN_INTERFACE_VERSION__ < 0x00030208 +#define xen_mb() mb() +#define xen_rmb() rmb() +#define xen_wmb() wmb() +#endif + +typedef unsigned int RING_IDX; + +/* Round a 32-bit unsigned constant down to the nearest power of two. */ +#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1)) +#define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x)) +#define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x)) +#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x)) +#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x)) + +/* + * Calculate size of a shared ring, given the total available space for the + * ring and indexes (_sz), and the name tag of the request/response structure. + * A ring contains as many entries as will fit, rounded down to the nearest + * power of two (so we can mask with (size-1) to loop around). + */ +#define __CONST_RING_SIZE(_s, _sz) \ + (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \ + sizeof(((struct _s##_sring *)0)->ring[0]))) +/* + * The same for passing in an actual pointer instead of a name tag. + */ +#define __RING_SIZE(_s, _sz) \ + (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) + +/* + * Macros to make the correct C datatypes for a new kind of ring. + * + * To make a new ring datatype, you need to have two message structures, + * let's say request_t, and response_t already defined. + * + * In a header where you want the ring datatype declared, you then do: + * + * DEFINE_RING_TYPES(mytag, request_t, response_t); + * + * These expand out to give you a set of types, as you can see below. + * The most important of these are: + * + * mytag_sring_t - The shared ring. + * mytag_front_ring_t - The 'front' half of the ring. + * mytag_back_ring_t - The 'back' half of the ring. + * + * To initialize a ring in your code you need to know the location and size + * of the shared memory area (PAGE_SIZE, for instance). To initialise + * the front half: + * + * mytag_front_ring_t front_ring; + * SHARED_RING_INIT((mytag_sring_t *)shared_page); + * FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); + * + * Initializing the back follows similarly (note that only the front + * initializes the shared ring): + * + * mytag_back_ring_t back_ring; + * BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE); + */ + +#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \ + \ +/* Shared ring entry */ \ +union __name##_sring_entry { \ + __req_t req; \ + __rsp_t rsp; \ +}; \ + \ +/* Shared ring page */ \ +struct __name##_sring { \ + RING_IDX req_prod, req_event; \ + RING_IDX rsp_prod, rsp_event; \ + union { \ + struct { \ + uint8_t smartpoll_active; \ + } netif; \ + struct { \ + uint8_t msg; \ + } tapif_user; \ + uint8_t pvt_pad[4]; \ + } private; \ + uint8_t __pad[44]; \ + union __name##_sring_entry ring[1]; /* variable-length */ \ +}; \ + \ +/* "Front" end's private variables */ \ +struct __name##_front_ring { \ + RING_IDX req_prod_pvt; \ + RING_IDX rsp_cons; \ + unsigned int nr_ents; \ + struct __name##_sring *sring; \ +}; \ + \ +/* "Back" end's private variables */ \ +struct __name##_back_ring { \ + RING_IDX rsp_prod_pvt; \ + RING_IDX req_cons; \ + unsigned int nr_ents; \ + struct __name##_sring *sring; \ +}; \ + \ +/* Syntactic sugar */ \ +typedef struct __name##_sring __name##_sring_t; \ +typedef struct __name##_front_ring __name##_front_ring_t; \ +typedef struct __name##_back_ring __name##_back_ring_t + +/* + * Macros for manipulating rings. + * + * FRONT_RING_whatever works on the "front end" of a ring: here + * requests are pushed on to the ring and responses taken off it. + * + * BACK_RING_whatever works on the "back end" of a ring: here + * requests are taken off the ring and responses put on. + * + * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL. + * This is OK in 1-for-1 request-response situations where the + * requestor (front end) never has more than RING_SIZE()-1 + * outstanding requests. + */ + +/* Initialising empty rings */ +#define SHARED_RING_INIT(_s) do { \ + (_s)->req_prod = (_s)->rsp_prod = 0; \ + (_s)->req_event = (_s)->rsp_event = 1; \ + (void)memset((_s)->private.pvt_pad, 0, sizeof((_s)->private.pvt_pad)); \ + (void)memset((_s)->__pad, 0, sizeof((_s)->__pad)); \ +} while(0) + +#define FRONT_RING_INIT(_r, _s, __size) do { \ + (_r)->req_prod_pvt = 0; \ + (_r)->rsp_cons = 0; \ + (_r)->nr_ents = __RING_SIZE(_s, __size); \ + (_r)->sring = (_s); \ +} while (0) + +#define BACK_RING_INIT(_r, _s, __size) do { \ + (_r)->rsp_prod_pvt = 0; \ + (_r)->req_cons = 0; \ + (_r)->nr_ents = __RING_SIZE(_s, __size); \ + (_r)->sring = (_s); \ +} while (0) + +/* How big is this ring? */ +#define RING_SIZE(_r) \ + ((_r)->nr_ents) + +/* Number of free requests (for use on front side only). */ +#define RING_FREE_REQUESTS(_r) \ + (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons)) + +/* Test if there is an empty slot available on the front ring. + * (This is only meaningful from the front. ) + */ +#define RING_FULL(_r) \ + (RING_FREE_REQUESTS(_r) == 0) + +/* Test if there are outstanding messages to be processed on a ring. */ +#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ + ((_r)->sring->rsp_prod - (_r)->rsp_cons) + +#ifdef __GNUC__ +#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ + unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ + unsigned int rsp = RING_SIZE(_r) - \ + ((_r)->req_cons - (_r)->rsp_prod_pvt); \ + req < rsp ? req : rsp; \ +}) +#else +/* Same as above, but without the nice GCC ({ ... }) syntax. */ +#define RING_HAS_UNCONSUMED_REQUESTS(_r) \ + ((((_r)->sring->req_prod - (_r)->req_cons) < \ + (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) ? \ + ((_r)->sring->req_prod - (_r)->req_cons) : \ + (RING_SIZE(_r) - ((_r)->req_cons - (_r)->rsp_prod_pvt))) +#endif + +/* Direct access to individual ring elements, by index. */ +#define RING_GET_REQUEST(_r, _idx) \ + (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) + +#define RING_GET_RESPONSE(_r, _idx) \ + (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp)) + +/* Loop termination condition: Would the specified index overflow the ring? */ +#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \ + (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r)) + +/* Ill-behaved frontend determination: Can there be this many requests? */ +#define RING_REQUEST_PROD_OVERFLOW(_r, _prod) \ + (((_prod) - (_r)->rsp_prod_pvt) > RING_SIZE(_r)) + +#define RING_PUSH_REQUESTS(_r) do { \ + xen_wmb(); /* back sees requests /before/ updated producer index */ \ + (_r)->sring->req_prod = (_r)->req_prod_pvt; \ +} while (0) + +#define RING_PUSH_RESPONSES(_r) do { \ + xen_wmb(); /* front sees resps /before/ updated producer index */ \ + (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \ +} while (0) + +/* + * Notification hold-off (req_event and rsp_event): + * + * When queueing requests or responses on a shared ring, it may not always be + * necessary to notify the remote end. For example, if requests are in flight + * in a backend, the front may be able to queue further requests without + * notifying the back (if the back checks for new requests when it queues + * responses). + * + * When enqueuing requests or responses: + * + * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument + * is a boolean return value. True indicates that the receiver requires an + * asynchronous notification. + * + * After dequeuing requests or responses (before sleeping the connection): + * + * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES(). + * The second argument is a boolean return value. True indicates that there + * are pending messages on the ring (i.e., the connection should not be put + * to sleep). + * + * These macros will set the req_event/rsp_event field to trigger a + * notification on the very next message that is enqueued. If you want to + * create batches of work (i.e., only receive a notification after several + * messages have been enqueued) then you will need to create a customised + * version of the FINAL_CHECK macro in your own code, which sets the event + * field appropriately. + */ + +#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \ + RING_IDX __old = (_r)->sring->req_prod; \ + RING_IDX __new = (_r)->req_prod_pvt; \ + xen_wmb(); /* back sees requests /before/ updated producer index */ \ + (_r)->sring->req_prod = __new; \ + xen_mb(); /* back sees new requests /before/ we check req_event */ \ + (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \ + (RING_IDX)(__new - __old)); \ +} while (0) + +#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \ + RING_IDX __old = (_r)->sring->rsp_prod; \ + RING_IDX __new = (_r)->rsp_prod_pvt; \ + xen_wmb(); /* front sees resps /before/ updated producer index */ \ + (_r)->sring->rsp_prod = __new; \ + xen_mb(); /* front sees new resps /before/ we check rsp_event */ \ + (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \ + (RING_IDX)(__new - __old)); \ +} while (0) + +#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \ + (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ + if (_work_to_do) break; \ + (_r)->sring->req_event = (_r)->req_cons + 1; \ + xen_mb(); \ + (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \ +} while (0) + +#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \ + (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ + if (_work_to_do) break; \ + (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \ + xen_mb(); \ + (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \ +} while (0) + +#endif /* __XEN_PUBLIC_IO_RING_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/io/xenbus.h b/roms/ipxe/src/include/xen/io/xenbus.h new file mode 100644 index 000000000..182aeb9bc --- /dev/null +++ b/roms/ipxe/src/include/xen/io/xenbus.h @@ -0,0 +1,82 @@ +/***************************************************************************** + * xenbus.h + * + * Xenbus protocol details. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2005 XenSource Ltd. + */ + +#ifndef _XEN_PUBLIC_IO_XENBUS_H +#define _XEN_PUBLIC_IO_XENBUS_H + +FILE_LICENCE ( MIT ); + +/* + * The state of either end of the Xenbus, i.e. the current communication + * status of initialisation across the bus. States here imply nothing about + * the state of the connection between the driver and the kernel's device + * layers. + */ +enum xenbus_state { + XenbusStateUnknown = 0, + + XenbusStateInitialising = 1, + + /* + * InitWait: Finished early initialisation but waiting for information + * from the peer or hotplug scripts. + */ + XenbusStateInitWait = 2, + + /* + * Initialised: Waiting for a connection from the peer. + */ + XenbusStateInitialised = 3, + + XenbusStateConnected = 4, + + /* + * Closing: The device is being closed due to an error or an unplug event. + */ + XenbusStateClosing = 5, + + XenbusStateClosed = 6, + + /* + * Reconfiguring: The device is being reconfigured. + */ + XenbusStateReconfiguring = 7, + + XenbusStateReconfigured = 8 +}; +typedef enum xenbus_state XenbusState; + +#endif /* _XEN_PUBLIC_IO_XENBUS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/io/xs_wire.h b/roms/ipxe/src/include/xen/io/xs_wire.h new file mode 100644 index 000000000..50415f02f --- /dev/null +++ b/roms/ipxe/src/include/xen/io/xs_wire.h @@ -0,0 +1,140 @@ +/* + * Details of the "wire" protocol between Xen Store Daemon and client + * library or guest kernel. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2005 Rusty Russell IBM Corporation + */ + +#ifndef _XS_WIRE_H +#define _XS_WIRE_H + +FILE_LICENCE ( MIT ); + +enum xsd_sockmsg_type +{ + XS_DEBUG, + XS_DIRECTORY, + XS_READ, + XS_GET_PERMS, + XS_WATCH, + XS_UNWATCH, + XS_TRANSACTION_START, + XS_TRANSACTION_END, + XS_INTRODUCE, + XS_RELEASE, + XS_GET_DOMAIN_PATH, + XS_WRITE, + XS_MKDIR, + XS_RM, + XS_SET_PERMS, + XS_WATCH_EVENT, + XS_ERROR, + XS_IS_DOMAIN_INTRODUCED, + XS_RESUME, + XS_SET_TARGET, + XS_RESTRICT, + XS_RESET_WATCHES +}; + +#define XS_WRITE_NONE "NONE" +#define XS_WRITE_CREATE "CREATE" +#define XS_WRITE_CREATE_EXCL "CREATE|EXCL" + +/* We hand errors as strings, for portability. */ +struct xsd_errors +{ + int errnum; + const char *errstring; +}; +#ifdef EINVAL +#define XSD_ERROR(x) { x, #x } +/* LINTED: static unused */ +static struct xsd_errors xsd_errors[] +#if defined(__GNUC__) +__attribute__((unused)) +#endif + = { + XSD_ERROR(EINVAL), + XSD_ERROR(EACCES), + XSD_ERROR(EEXIST), + XSD_ERROR(EISDIR), + XSD_ERROR(ENOENT), + XSD_ERROR(ENOMEM), + XSD_ERROR(ENOSPC), + XSD_ERROR(EIO), + XSD_ERROR(ENOTEMPTY), + XSD_ERROR(ENOSYS), + XSD_ERROR(EROFS), + XSD_ERROR(EBUSY), + XSD_ERROR(EAGAIN), + XSD_ERROR(EISCONN), + XSD_ERROR(E2BIG) +}; +#endif + +struct xsd_sockmsg +{ + uint32_t type; /* XS_??? */ + uint32_t req_id;/* Request identifier, echoed in daemon's response. */ + uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */ + uint32_t len; /* Length of data following this. */ + + /* Generally followed by nul-terminated string(s). */ +}; + +enum xs_watch_type +{ + XS_WATCH_PATH = 0, + XS_WATCH_TOKEN +}; + +/* + * `incontents 150 xenstore_struct XenStore wire protocol. + * + * Inter-domain shared memory communications. */ +#define XENSTORE_RING_SIZE 1024 +typedef uint32_t XENSTORE_RING_IDX; +#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1)) +struct xenstore_domain_interface { + char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */ + char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */ + XENSTORE_RING_IDX req_cons, req_prod; + XENSTORE_RING_IDX rsp_cons, rsp_prod; +}; + +/* Violating this is very bad. See docs/misc/xenstore.txt. */ +#define XENSTORE_PAYLOAD_MAX 4096 + +/* Violating these just gets you an error back */ +#define XENSTORE_ABS_PATH_MAX 3072 +#define XENSTORE_REL_PATH_MAX 2048 + +#endif /* _XS_WIRE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/memory.h b/roms/ipxe/src/include/xen/memory.h new file mode 100644 index 000000000..0c76c0d64 --- /dev/null +++ b/roms/ipxe/src/include/xen/memory.h @@ -0,0 +1,540 @@ +/****************************************************************************** + * memory.h + * + * Memory reservation and information. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2005, Keir Fraser <keir@xensource.com> + */ + +#ifndef __XEN_PUBLIC_MEMORY_H__ +#define __XEN_PUBLIC_MEMORY_H__ + +FILE_LICENCE ( MIT ); + +#include "xen.h" + +/* + * Increase or decrease the specified domain's memory reservation. Returns the + * number of extents successfully allocated or freed. + * arg == addr of struct xen_memory_reservation. + */ +#define XENMEM_increase_reservation 0 +#define XENMEM_decrease_reservation 1 +#define XENMEM_populate_physmap 6 + +#if __XEN_INTERFACE_VERSION__ >= 0x00030209 +/* + * Maximum # bits addressable by the user of the allocated region (e.g., I/O + * devices often have a 32-bit limitation even in 64-bit systems). If zero + * then the user has no addressing restriction. This field is not used by + * XENMEM_decrease_reservation. + */ +#define XENMEMF_address_bits(x) (x) +#define XENMEMF_get_address_bits(x) ((x) & 0xffu) +/* NUMA node to allocate from. */ +#define XENMEMF_node(x) (((x) + 1) << 8) +#define XENMEMF_get_node(x) ((((x) >> 8) - 1) & 0xffu) +/* Flag to populate physmap with populate-on-demand entries */ +#define XENMEMF_populate_on_demand (1<<16) +/* Flag to request allocation only from the node specified */ +#define XENMEMF_exact_node_request (1<<17) +#define XENMEMF_exact_node(n) (XENMEMF_node(n) | XENMEMF_exact_node_request) +#endif + +struct xen_memory_reservation { + + /* + * XENMEM_increase_reservation: + * OUT: MFN (*not* GMFN) bases of extents that were allocated + * XENMEM_decrease_reservation: + * IN: GMFN bases of extents to free + * XENMEM_populate_physmap: + * IN: GPFN bases of extents to populate with memory + * OUT: GMFN bases of extents that were allocated + * (NB. This command also updates the mach_to_phys translation table) + * XENMEM_claim_pages: + * IN: must be zero + */ + XEN_GUEST_HANDLE(xen_pfn_t) extent_start; + + /* Number of extents, and size/alignment of each (2^extent_order pages). */ + xen_ulong_t nr_extents; + unsigned int extent_order; + +#if __XEN_INTERFACE_VERSION__ >= 0x00030209 + /* XENMEMF flags. */ + unsigned int mem_flags; +#else + unsigned int address_bits; +#endif + + /* + * Domain whose reservation is being changed. + * Unprivileged domains can specify only DOMID_SELF. + */ + domid_t domid; +}; +typedef struct xen_memory_reservation xen_memory_reservation_t; +DEFINE_XEN_GUEST_HANDLE(xen_memory_reservation_t); + +/* + * An atomic exchange of memory pages. If return code is zero then + * @out.extent_list provides GMFNs of the newly-allocated memory. + * Returns zero on complete success, otherwise a negative error code. + * On complete success then always @nr_exchanged == @in.nr_extents. + * On partial success @nr_exchanged indicates how much work was done. + */ +#define XENMEM_exchange 11 +struct xen_memory_exchange { + /* + * [IN] Details of memory extents to be exchanged (GMFN bases). + * Note that @in.address_bits is ignored and unused. + */ + struct xen_memory_reservation in; + + /* + * [IN/OUT] Details of new memory extents. + * We require that: + * 1. @in.domid == @out.domid + * 2. @in.nr_extents << @in.extent_order == + * @out.nr_extents << @out.extent_order + * 3. @in.extent_start and @out.extent_start lists must not overlap + * 4. @out.extent_start lists GPFN bases to be populated + * 5. @out.extent_start is overwritten with allocated GMFN bases + */ + struct xen_memory_reservation out; + + /* + * [OUT] Number of input extents that were successfully exchanged: + * 1. The first @nr_exchanged input extents were successfully + * deallocated. + * 2. The corresponding first entries in the output extent list correctly + * indicate the GMFNs that were successfully exchanged. + * 3. All other input and output extents are untouched. + * 4. If not all input exents are exchanged then the return code of this + * command will be non-zero. + * 5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER! + */ + xen_ulong_t nr_exchanged; +}; +typedef struct xen_memory_exchange xen_memory_exchange_t; +DEFINE_XEN_GUEST_HANDLE(xen_memory_exchange_t); + +/* + * Returns the maximum machine frame number of mapped RAM in this system. + * This command always succeeds (it never returns an error code). + * arg == NULL. + */ +#define XENMEM_maximum_ram_page 2 + +/* + * Returns the current or maximum memory reservation, in pages, of the + * specified domain (may be DOMID_SELF). Returns -ve errcode on failure. + * arg == addr of domid_t. + */ +#define XENMEM_current_reservation 3 +#define XENMEM_maximum_reservation 4 + +/* + * Returns the maximum GPFN in use by the guest, or -ve errcode on failure. + */ +#define XENMEM_maximum_gpfn 14 + +/* + * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys + * mapping table. Architectures which do not have a m2p table do not implement + * this command. + * arg == addr of xen_machphys_mfn_list_t. + */ +#define XENMEM_machphys_mfn_list 5 +struct xen_machphys_mfn_list { + /* + * Size of the 'extent_start' array. Fewer entries will be filled if the + * machphys table is smaller than max_extents * 2MB. + */ + unsigned int max_extents; + + /* + * Pointer to buffer to fill with list of extent starts. If there are + * any large discontiguities in the machine address space, 2MB gaps in + * the machphys table will be represented by an MFN base of zero. + */ + XEN_GUEST_HANDLE(xen_pfn_t) extent_start; + + /* + * Number of extents written to the above array. This will be smaller + * than 'max_extents' if the machphys table is smaller than max_e * 2MB. + */ + unsigned int nr_extents; +}; +typedef struct xen_machphys_mfn_list xen_machphys_mfn_list_t; +DEFINE_XEN_GUEST_HANDLE(xen_machphys_mfn_list_t); + +/* + * For a compat caller, this is identical to XENMEM_machphys_mfn_list. + * + * For a non compat caller, this functions similarly to + * XENMEM_machphys_mfn_list, but returns the mfns making up the compatibility + * m2p table. + */ +#define XENMEM_machphys_compat_mfn_list 25 + +/* + * Returns the location in virtual address space of the machine_to_phys + * mapping table. Architectures which do not have a m2p table, or which do not + * map it by default into guest address space, do not implement this command. + * arg == addr of xen_machphys_mapping_t. + */ +#define XENMEM_machphys_mapping 12 +struct xen_machphys_mapping { + xen_ulong_t v_start, v_end; /* Start and end virtual addresses. */ + xen_ulong_t max_mfn; /* Maximum MFN that can be looked up. */ +}; +typedef struct xen_machphys_mapping xen_machphys_mapping_t; +DEFINE_XEN_GUEST_HANDLE(xen_machphys_mapping_t); + +/* Source mapping space. */ +/* ` enum phys_map_space { */ +#define XENMAPSPACE_shared_info 0 /* shared info page */ +#define XENMAPSPACE_grant_table 1 /* grant table page */ +#define XENMAPSPACE_gmfn 2 /* GMFN */ +#define XENMAPSPACE_gmfn_range 3 /* GMFN range, XENMEM_add_to_physmap only. */ +#define XENMAPSPACE_gmfn_foreign 4 /* GMFN from another dom, + * XENMEM_add_to_physmap_batch only. */ +/* ` } */ + +/* + * Sets the GPFN at which a particular page appears in the specified guest's + * pseudophysical address space. + * arg == addr of xen_add_to_physmap_t. + */ +#define XENMEM_add_to_physmap 7 +struct xen_add_to_physmap { + /* Which domain to change the mapping for. */ + domid_t domid; + + /* Number of pages to go through for gmfn_range */ + uint16_t size; + + unsigned int space; /* => enum phys_map_space */ + +#define XENMAPIDX_grant_table_status 0x80000000 + + /* Index into space being mapped. */ + xen_ulong_t idx; + + /* GPFN in domid where the source mapping page should appear. */ + xen_pfn_t gpfn; +}; +typedef struct xen_add_to_physmap xen_add_to_physmap_t; +DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_t); + +/* A batched version of add_to_physmap. */ +#define XENMEM_add_to_physmap_batch 23 +struct xen_add_to_physmap_batch { + /* IN */ + /* Which domain to change the mapping for. */ + domid_t domid; + uint16_t space; /* => enum phys_map_space */ + + /* Number of pages to go through */ + uint16_t size; + domid_t foreign_domid; /* IFF gmfn_foreign */ + + /* Indexes into space being mapped. */ + XEN_GUEST_HANDLE(xen_ulong_t) idxs; + + /* GPFN in domid where the source mapping page should appear. */ + XEN_GUEST_HANDLE(xen_pfn_t) gpfns; + + /* OUT */ + + /* Per index error code. */ + XEN_GUEST_HANDLE(int) errs; +}; +typedef struct xen_add_to_physmap_batch xen_add_to_physmap_batch_t; +DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_batch_t); + +#if __XEN_INTERFACE_VERSION__ < 0x00040400 +#define XENMEM_add_to_physmap_range XENMEM_add_to_physmap_batch +#define xen_add_to_physmap_range xen_add_to_physmap_batch +typedef struct xen_add_to_physmap_batch xen_add_to_physmap_range_t; +DEFINE_XEN_GUEST_HANDLE(xen_add_to_physmap_range_t); +#endif + +/* + * Unmaps the page appearing at a particular GPFN from the specified guest's + * pseudophysical address space. + * arg == addr of xen_remove_from_physmap_t. + */ +#define XENMEM_remove_from_physmap 15 +struct xen_remove_from_physmap { + /* Which domain to change the mapping for. */ + domid_t domid; + + /* GPFN of the current mapping of the page. */ + xen_pfn_t gpfn; +}; +typedef struct xen_remove_from_physmap xen_remove_from_physmap_t; +DEFINE_XEN_GUEST_HANDLE(xen_remove_from_physmap_t); + +/*** REMOVED ***/ +/*#define XENMEM_translate_gpfn_list 8*/ + +/* + * Returns the pseudo-physical memory map as it was when the domain + * was started (specified by XENMEM_set_memory_map). + * arg == addr of xen_memory_map_t. + */ +#define XENMEM_memory_map 9 +struct xen_memory_map { + /* + * On call the number of entries which can be stored in buffer. On + * return the number of entries which have been stored in + * buffer. + */ + unsigned int nr_entries; + + /* + * Entries in the buffer are in the same format as returned by the + * BIOS INT 0x15 EAX=0xE820 call. + */ + XEN_GUEST_HANDLE(void) buffer; +}; +typedef struct xen_memory_map xen_memory_map_t; +DEFINE_XEN_GUEST_HANDLE(xen_memory_map_t); + +/* + * Returns the real physical memory map. Passes the same structure as + * XENMEM_memory_map. + * arg == addr of xen_memory_map_t. + */ +#define XENMEM_machine_memory_map 10 + +/* + * Set the pseudo-physical memory map of a domain, as returned by + * XENMEM_memory_map. + * arg == addr of xen_foreign_memory_map_t. + */ +#define XENMEM_set_memory_map 13 +struct xen_foreign_memory_map { + domid_t domid; + struct xen_memory_map map; +}; +typedef struct xen_foreign_memory_map xen_foreign_memory_map_t; +DEFINE_XEN_GUEST_HANDLE(xen_foreign_memory_map_t); + +#define XENMEM_set_pod_target 16 +#define XENMEM_get_pod_target 17 +struct xen_pod_target { + /* IN */ + uint64_t target_pages; + /* OUT */ + uint64_t tot_pages; + uint64_t pod_cache_pages; + uint64_t pod_entries; + /* IN */ + domid_t domid; +}; +typedef struct xen_pod_target xen_pod_target_t; + +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +#ifndef uint64_aligned_t +#define uint64_aligned_t uint64_t +#endif + +/* + * Get the number of MFNs saved through memory sharing. + * The call never fails. + */ +#define XENMEM_get_sharing_freed_pages 18 +#define XENMEM_get_sharing_shared_pages 19 + +#define XENMEM_paging_op 20 +#define XENMEM_paging_op_nominate 0 +#define XENMEM_paging_op_evict 1 +#define XENMEM_paging_op_prep 2 + +struct xen_mem_event_op { + uint8_t op; /* XENMEM_*_op_* */ + domid_t domain; + + + /* PAGING_PREP IN: buffer to immediately fill page in */ + uint64_aligned_t buffer; + /* Other OPs */ + uint64_aligned_t gfn; /* IN: gfn of page being operated on */ +}; +typedef struct xen_mem_event_op xen_mem_event_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_mem_event_op_t); + +#define XENMEM_access_op 21 +#define XENMEM_access_op_resume 0 +#define XENMEM_access_op_set_access 1 +#define XENMEM_access_op_get_access 2 + +typedef enum { + XENMEM_access_n, + XENMEM_access_r, + XENMEM_access_w, + XENMEM_access_rw, + XENMEM_access_x, + XENMEM_access_rx, + XENMEM_access_wx, + XENMEM_access_rwx, + /* + * Page starts off as r-x, but automatically + * change to r-w on a write + */ + XENMEM_access_rx2rw, + /* + * Log access: starts off as n, automatically + * goes to rwx, generating an event without + * pausing the vcpu + */ + XENMEM_access_n2rwx, + /* Take the domain default */ + XENMEM_access_default +} xenmem_access_t; + +struct xen_mem_access_op { + /* XENMEM_access_op_* */ + uint8_t op; + /* xenmem_access_t */ + uint8_t access; + domid_t domid; + /* + * Number of pages for set op + * Ignored on setting default access and other ops + */ + uint32_t nr; + /* + * First pfn for set op + * pfn for get op + * ~0ull is used to set and get the default access for pages + */ + uint64_aligned_t pfn; +}; +typedef struct xen_mem_access_op xen_mem_access_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_mem_access_op_t); + +#define XENMEM_sharing_op 22 +#define XENMEM_sharing_op_nominate_gfn 0 +#define XENMEM_sharing_op_nominate_gref 1 +#define XENMEM_sharing_op_share 2 +#define XENMEM_sharing_op_resume 3 +#define XENMEM_sharing_op_debug_gfn 4 +#define XENMEM_sharing_op_debug_mfn 5 +#define XENMEM_sharing_op_debug_gref 6 +#define XENMEM_sharing_op_add_physmap 7 +#define XENMEM_sharing_op_audit 8 + +#define XENMEM_SHARING_OP_S_HANDLE_INVALID (-10) +#define XENMEM_SHARING_OP_C_HANDLE_INVALID (-9) + +/* The following allows sharing of grant refs. This is useful + * for sharing utilities sitting as "filters" in IO backends + * (e.g. memshr + blktap(2)). The IO backend is only exposed + * to grant references, and this allows sharing of the grefs */ +#define XENMEM_SHARING_OP_FIELD_IS_GREF_FLAG (1ULL << 62) + +#define XENMEM_SHARING_OP_FIELD_MAKE_GREF(field, val) \ + (field) = (XENMEM_SHARING_OP_FIELD_IS_GREF_FLAG | val) +#define XENMEM_SHARING_OP_FIELD_IS_GREF(field) \ + ((field) & XENMEM_SHARING_OP_FIELD_IS_GREF_FLAG) +#define XENMEM_SHARING_OP_FIELD_GET_GREF(field) \ + ((field) & (~XENMEM_SHARING_OP_FIELD_IS_GREF_FLAG)) + +struct xen_mem_sharing_op { + uint8_t op; /* XENMEM_sharing_op_* */ + domid_t domain; + + union { + struct mem_sharing_op_nominate { /* OP_NOMINATE_xxx */ + union { + uint64_aligned_t gfn; /* IN: gfn to nominate */ + uint32_t grant_ref; /* IN: grant ref to nominate */ + } u; + uint64_aligned_t handle; /* OUT: the handle */ + } nominate; + struct mem_sharing_op_share { /* OP_SHARE/ADD_PHYSMAP */ + uint64_aligned_t source_gfn; /* IN: the gfn of the source page */ + uint64_aligned_t source_handle; /* IN: handle to the source page */ + uint64_aligned_t client_gfn; /* IN: the client gfn */ + uint64_aligned_t client_handle; /* IN: handle to the client page */ + domid_t client_domain; /* IN: the client domain id */ + } share; + struct mem_sharing_op_debug { /* OP_DEBUG_xxx */ + union { + uint64_aligned_t gfn; /* IN: gfn to debug */ + uint64_aligned_t mfn; /* IN: mfn to debug */ + uint32_t gref; /* IN: gref to debug */ + } u; + } debug; + } u; +}; +typedef struct xen_mem_sharing_op xen_mem_sharing_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_mem_sharing_op_t); + +/* + * Attempt to stake a claim for a domain on a quantity of pages + * of system RAM, but _not_ assign specific pageframes. Only + * arithmetic is performed so the hypercall is very fast and need + * not be preemptible, thus sidestepping time-of-check-time-of-use + * races for memory allocation. Returns 0 if the hypervisor page + * allocator has atomically and successfully claimed the requested + * number of pages, else non-zero. + * + * Any domain may have only one active claim. When sufficient memory + * has been allocated to resolve the claim, the claim silently expires. + * Claiming zero pages effectively resets any outstanding claim and + * is always successful. + * + * Note that a valid claim may be staked even after memory has been + * allocated for a domain. In this case, the claim is not incremental, + * i.e. if the domain's tot_pages is 3, and a claim is staked for 10, + * only 7 additional pages are claimed. + * + * Caller must be privileged or the hypercall fails. + */ +#define XENMEM_claim_pages 24 + +/* + * XENMEM_claim_pages flags - the are no flags at this time. + * The zero value is appropiate. + */ + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + +/* Next available subop number is 26 */ + +#endif /* __XEN_PUBLIC_MEMORY_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/trace.h b/roms/ipxe/src/include/xen/trace.h new file mode 100644 index 000000000..bf8bf65ac --- /dev/null +++ b/roms/ipxe/src/include/xen/trace.h @@ -0,0 +1,332 @@ +/****************************************************************************** + * include/public/trace.h + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Mark Williamson, (C) 2004 Intel Research Cambridge + * Copyright (C) 2005 Bin Ren + */ + +#ifndef __XEN_PUBLIC_TRACE_H__ +#define __XEN_PUBLIC_TRACE_H__ + +FILE_LICENCE ( MIT ); + +#define TRACE_EXTRA_MAX 7 +#define TRACE_EXTRA_SHIFT 28 + +/* Trace classes */ +#define TRC_CLS_SHIFT 16 +#define TRC_GEN 0x0001f000 /* General trace */ +#define TRC_SCHED 0x0002f000 /* Xen Scheduler trace */ +#define TRC_DOM0OP 0x0004f000 /* Xen DOM0 operation trace */ +#define TRC_HVM 0x0008f000 /* Xen HVM trace */ +#define TRC_MEM 0x0010f000 /* Xen memory trace */ +#define TRC_PV 0x0020f000 /* Xen PV traces */ +#define TRC_SHADOW 0x0040f000 /* Xen shadow tracing */ +#define TRC_HW 0x0080f000 /* Xen hardware-related traces */ +#define TRC_GUEST 0x0800f000 /* Guest-generated traces */ +#define TRC_ALL 0x0ffff000 +#define TRC_HD_TO_EVENT(x) ((x)&0x0fffffff) +#define TRC_HD_CYCLE_FLAG (1UL<<31) +#define TRC_HD_INCLUDES_CYCLE_COUNT(x) ( !!( (x) & TRC_HD_CYCLE_FLAG ) ) +#define TRC_HD_EXTRA(x) (((x)>>TRACE_EXTRA_SHIFT)&TRACE_EXTRA_MAX) + +/* Trace subclasses */ +#define TRC_SUBCLS_SHIFT 12 + +/* trace subclasses for SVM */ +#define TRC_HVM_ENTRYEXIT 0x00081000 /* VMENTRY and #VMEXIT */ +#define TRC_HVM_HANDLER 0x00082000 /* various HVM handlers */ +#define TRC_HVM_EMUL 0x00084000 /* emulated devices */ + +#define TRC_SCHED_MIN 0x00021000 /* Just runstate changes */ +#define TRC_SCHED_CLASS 0x00022000 /* Scheduler-specific */ +#define TRC_SCHED_VERBOSE 0x00028000 /* More inclusive scheduling */ + +/* + * The highest 3 bits of the last 12 bits of TRC_SCHED_CLASS above are + * reserved for encoding what scheduler produced the information. The + * actual event is encoded in the last 9 bits. + * + * This means we have 8 scheduling IDs available (which means at most 8 + * schedulers generating events) and, in each scheduler, up to 512 + * different events. + */ +#define TRC_SCHED_ID_BITS 3 +#define TRC_SCHED_ID_SHIFT (TRC_SUBCLS_SHIFT - TRC_SCHED_ID_BITS) +#define TRC_SCHED_ID_MASK (((1UL<<TRC_SCHED_ID_BITS) - 1) << TRC_SCHED_ID_SHIFT) +#define TRC_SCHED_EVT_MASK (~(TRC_SCHED_ID_MASK)) + +/* Per-scheduler IDs, to identify scheduler specific events */ +#define TRC_SCHED_CSCHED 0 +#define TRC_SCHED_CSCHED2 1 +#define TRC_SCHED_SEDF 2 +#define TRC_SCHED_ARINC653 3 + +/* Per-scheduler tracing */ +#define TRC_SCHED_CLASS_EVT(_c, _e) \ + ( ( TRC_SCHED_CLASS | \ + ((TRC_SCHED_##_c << TRC_SCHED_ID_SHIFT) & TRC_SCHED_ID_MASK) ) + \ + (_e & TRC_SCHED_EVT_MASK) ) + +/* Trace classes for Hardware */ +#define TRC_HW_PM 0x00801000 /* Power management traces */ +#define TRC_HW_IRQ 0x00802000 /* Traces relating to the handling of IRQs */ + +/* Trace events per class */ +#define TRC_LOST_RECORDS (TRC_GEN + 1) +#define TRC_TRACE_WRAP_BUFFER (TRC_GEN + 2) +#define TRC_TRACE_CPU_CHANGE (TRC_GEN + 3) + +#define TRC_SCHED_RUNSTATE_CHANGE (TRC_SCHED_MIN + 1) +#define TRC_SCHED_CONTINUE_RUNNING (TRC_SCHED_MIN + 2) +#define TRC_SCHED_DOM_ADD (TRC_SCHED_VERBOSE + 1) +#define TRC_SCHED_DOM_REM (TRC_SCHED_VERBOSE + 2) +#define TRC_SCHED_SLEEP (TRC_SCHED_VERBOSE + 3) +#define TRC_SCHED_WAKE (TRC_SCHED_VERBOSE + 4) +#define TRC_SCHED_YIELD (TRC_SCHED_VERBOSE + 5) +#define TRC_SCHED_BLOCK (TRC_SCHED_VERBOSE + 6) +#define TRC_SCHED_SHUTDOWN (TRC_SCHED_VERBOSE + 7) +#define TRC_SCHED_CTL (TRC_SCHED_VERBOSE + 8) +#define TRC_SCHED_ADJDOM (TRC_SCHED_VERBOSE + 9) +#define TRC_SCHED_SWITCH (TRC_SCHED_VERBOSE + 10) +#define TRC_SCHED_S_TIMER_FN (TRC_SCHED_VERBOSE + 11) +#define TRC_SCHED_T_TIMER_FN (TRC_SCHED_VERBOSE + 12) +#define TRC_SCHED_DOM_TIMER_FN (TRC_SCHED_VERBOSE + 13) +#define TRC_SCHED_SWITCH_INFPREV (TRC_SCHED_VERBOSE + 14) +#define TRC_SCHED_SWITCH_INFNEXT (TRC_SCHED_VERBOSE + 15) +#define TRC_SCHED_SHUTDOWN_CODE (TRC_SCHED_VERBOSE + 16) + +#define TRC_MEM_PAGE_GRANT_MAP (TRC_MEM + 1) +#define TRC_MEM_PAGE_GRANT_UNMAP (TRC_MEM + 2) +#define TRC_MEM_PAGE_GRANT_TRANSFER (TRC_MEM + 3) +#define TRC_MEM_SET_P2M_ENTRY (TRC_MEM + 4) +#define TRC_MEM_DECREASE_RESERVATION (TRC_MEM + 5) +#define TRC_MEM_POD_POPULATE (TRC_MEM + 16) +#define TRC_MEM_POD_ZERO_RECLAIM (TRC_MEM + 17) +#define TRC_MEM_POD_SUPERPAGE_SPLINTER (TRC_MEM + 18) + +#define TRC_PV_ENTRY 0x00201000 /* Hypervisor entry points for PV guests. */ +#define TRC_PV_SUBCALL 0x00202000 /* Sub-call in a multicall hypercall */ + +#define TRC_PV_HYPERCALL (TRC_PV_ENTRY + 1) +#define TRC_PV_TRAP (TRC_PV_ENTRY + 3) +#define TRC_PV_PAGE_FAULT (TRC_PV_ENTRY + 4) +#define TRC_PV_FORCED_INVALID_OP (TRC_PV_ENTRY + 5) +#define TRC_PV_EMULATE_PRIVOP (TRC_PV_ENTRY + 6) +#define TRC_PV_EMULATE_4GB (TRC_PV_ENTRY + 7) +#define TRC_PV_MATH_STATE_RESTORE (TRC_PV_ENTRY + 8) +#define TRC_PV_PAGING_FIXUP (TRC_PV_ENTRY + 9) +#define TRC_PV_GDT_LDT_MAPPING_FAULT (TRC_PV_ENTRY + 10) +#define TRC_PV_PTWR_EMULATION (TRC_PV_ENTRY + 11) +#define TRC_PV_PTWR_EMULATION_PAE (TRC_PV_ENTRY + 12) +#define TRC_PV_HYPERCALL_V2 (TRC_PV_ENTRY + 13) +#define TRC_PV_HYPERCALL_SUBCALL (TRC_PV_SUBCALL + 14) + +/* + * TRC_PV_HYPERCALL_V2 format + * + * Only some of the hypercall argument are recorded. Bit fields A0 to + * A5 in the first extra word are set if the argument is present and + * the arguments themselves are packed sequentially in the following + * words. + * + * The TRC_64_FLAG bit is not set for these events (even if there are + * 64-bit arguments in the record). + * + * Word + * 0 bit 31 30|29 28|27 26|25 24|23 22|21 20|19 ... 0 + * A5 |A4 |A3 |A2 |A1 |A0 |Hypercall op + * 1 First 32 bit (or low word of first 64 bit) arg in record + * 2 Second 32 bit (or high word of first 64 bit) arg in record + * ... + * + * A0-A5 bitfield values: + * + * 00b Argument not present + * 01b 32-bit argument present + * 10b 64-bit argument present + * 11b Reserved + */ +#define TRC_PV_HYPERCALL_V2_ARG_32(i) (0x1 << (20 + 2*(i))) +#define TRC_PV_HYPERCALL_V2_ARG_64(i) (0x2 << (20 + 2*(i))) +#define TRC_PV_HYPERCALL_V2_ARG_MASK (0xfff00000) + +#define TRC_SHADOW_NOT_SHADOW (TRC_SHADOW + 1) +#define TRC_SHADOW_FAST_PROPAGATE (TRC_SHADOW + 2) +#define TRC_SHADOW_FAST_MMIO (TRC_SHADOW + 3) +#define TRC_SHADOW_FALSE_FAST_PATH (TRC_SHADOW + 4) +#define TRC_SHADOW_MMIO (TRC_SHADOW + 5) +#define TRC_SHADOW_FIXUP (TRC_SHADOW + 6) +#define TRC_SHADOW_DOMF_DYING (TRC_SHADOW + 7) +#define TRC_SHADOW_EMULATE (TRC_SHADOW + 8) +#define TRC_SHADOW_EMULATE_UNSHADOW_USER (TRC_SHADOW + 9) +#define TRC_SHADOW_EMULATE_UNSHADOW_EVTINJ (TRC_SHADOW + 10) +#define TRC_SHADOW_EMULATE_UNSHADOW_UNHANDLED (TRC_SHADOW + 11) +#define TRC_SHADOW_WRMAP_BF (TRC_SHADOW + 12) +#define TRC_SHADOW_PREALLOC_UNPIN (TRC_SHADOW + 13) +#define TRC_SHADOW_RESYNC_FULL (TRC_SHADOW + 14) +#define TRC_SHADOW_RESYNC_ONLY (TRC_SHADOW + 15) + +/* trace events per subclass */ +#define TRC_HVM_NESTEDFLAG (0x400) +#define TRC_HVM_VMENTRY (TRC_HVM_ENTRYEXIT + 0x01) +#define TRC_HVM_VMEXIT (TRC_HVM_ENTRYEXIT + 0x02) +#define TRC_HVM_VMEXIT64 (TRC_HVM_ENTRYEXIT + TRC_64_FLAG + 0x02) +#define TRC_HVM_PF_XEN (TRC_HVM_HANDLER + 0x01) +#define TRC_HVM_PF_XEN64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x01) +#define TRC_HVM_PF_INJECT (TRC_HVM_HANDLER + 0x02) +#define TRC_HVM_PF_INJECT64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x02) +#define TRC_HVM_INJ_EXC (TRC_HVM_HANDLER + 0x03) +#define TRC_HVM_INJ_VIRQ (TRC_HVM_HANDLER + 0x04) +#define TRC_HVM_REINJ_VIRQ (TRC_HVM_HANDLER + 0x05) +#define TRC_HVM_IO_READ (TRC_HVM_HANDLER + 0x06) +#define TRC_HVM_IO_WRITE (TRC_HVM_HANDLER + 0x07) +#define TRC_HVM_CR_READ (TRC_HVM_HANDLER + 0x08) +#define TRC_HVM_CR_READ64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x08) +#define TRC_HVM_CR_WRITE (TRC_HVM_HANDLER + 0x09) +#define TRC_HVM_CR_WRITE64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x09) +#define TRC_HVM_DR_READ (TRC_HVM_HANDLER + 0x0A) +#define TRC_HVM_DR_WRITE (TRC_HVM_HANDLER + 0x0B) +#define TRC_HVM_MSR_READ (TRC_HVM_HANDLER + 0x0C) +#define TRC_HVM_MSR_WRITE (TRC_HVM_HANDLER + 0x0D) +#define TRC_HVM_CPUID (TRC_HVM_HANDLER + 0x0E) +#define TRC_HVM_INTR (TRC_HVM_HANDLER + 0x0F) +#define TRC_HVM_NMI (TRC_HVM_HANDLER + 0x10) +#define TRC_HVM_SMI (TRC_HVM_HANDLER + 0x11) +#define TRC_HVM_VMMCALL (TRC_HVM_HANDLER + 0x12) +#define TRC_HVM_HLT (TRC_HVM_HANDLER + 0x13) +#define TRC_HVM_INVLPG (TRC_HVM_HANDLER + 0x14) +#define TRC_HVM_INVLPG64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x14) +#define TRC_HVM_MCE (TRC_HVM_HANDLER + 0x15) +#define TRC_HVM_IOPORT_READ (TRC_HVM_HANDLER + 0x16) +#define TRC_HVM_IOMEM_READ (TRC_HVM_HANDLER + 0x17) +#define TRC_HVM_CLTS (TRC_HVM_HANDLER + 0x18) +#define TRC_HVM_LMSW (TRC_HVM_HANDLER + 0x19) +#define TRC_HVM_LMSW64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x19) +#define TRC_HVM_RDTSC (TRC_HVM_HANDLER + 0x1a) +#define TRC_HVM_INTR_WINDOW (TRC_HVM_HANDLER + 0x20) +#define TRC_HVM_NPF (TRC_HVM_HANDLER + 0x21) +#define TRC_HVM_REALMODE_EMULATE (TRC_HVM_HANDLER + 0x22) +#define TRC_HVM_TRAP (TRC_HVM_HANDLER + 0x23) +#define TRC_HVM_TRAP_DEBUG (TRC_HVM_HANDLER + 0x24) +#define TRC_HVM_VLAPIC (TRC_HVM_HANDLER + 0x25) + +#define TRC_HVM_IOPORT_WRITE (TRC_HVM_HANDLER + 0x216) +#define TRC_HVM_IOMEM_WRITE (TRC_HVM_HANDLER + 0x217) + +/* Trace events for emulated devices */ +#define TRC_HVM_EMUL_HPET_START_TIMER (TRC_HVM_EMUL + 0x1) +#define TRC_HVM_EMUL_PIT_START_TIMER (TRC_HVM_EMUL + 0x2) +#define TRC_HVM_EMUL_RTC_START_TIMER (TRC_HVM_EMUL + 0x3) +#define TRC_HVM_EMUL_LAPIC_START_TIMER (TRC_HVM_EMUL + 0x4) +#define TRC_HVM_EMUL_HPET_STOP_TIMER (TRC_HVM_EMUL + 0x5) +#define TRC_HVM_EMUL_PIT_STOP_TIMER (TRC_HVM_EMUL + 0x6) +#define TRC_HVM_EMUL_RTC_STOP_TIMER (TRC_HVM_EMUL + 0x7) +#define TRC_HVM_EMUL_LAPIC_STOP_TIMER (TRC_HVM_EMUL + 0x8) +#define TRC_HVM_EMUL_PIT_TIMER_CB (TRC_HVM_EMUL + 0x9) +#define TRC_HVM_EMUL_LAPIC_TIMER_CB (TRC_HVM_EMUL + 0xA) +#define TRC_HVM_EMUL_PIC_INT_OUTPUT (TRC_HVM_EMUL + 0xB) +#define TRC_HVM_EMUL_PIC_KICK (TRC_HVM_EMUL + 0xC) +#define TRC_HVM_EMUL_PIC_INTACK (TRC_HVM_EMUL + 0xD) +#define TRC_HVM_EMUL_PIC_POSEDGE (TRC_HVM_EMUL + 0xE) +#define TRC_HVM_EMUL_PIC_NEGEDGE (TRC_HVM_EMUL + 0xF) +#define TRC_HVM_EMUL_PIC_PEND_IRQ_CALL (TRC_HVM_EMUL + 0x10) +#define TRC_HVM_EMUL_LAPIC_PIC_INTR (TRC_HVM_EMUL + 0x11) + +/* trace events for per class */ +#define TRC_PM_FREQ_CHANGE (TRC_HW_PM + 0x01) +#define TRC_PM_IDLE_ENTRY (TRC_HW_PM + 0x02) +#define TRC_PM_IDLE_EXIT (TRC_HW_PM + 0x03) + +/* Trace events for IRQs */ +#define TRC_HW_IRQ_MOVE_CLEANUP_DELAY (TRC_HW_IRQ + 0x1) +#define TRC_HW_IRQ_MOVE_CLEANUP (TRC_HW_IRQ + 0x2) +#define TRC_HW_IRQ_BIND_VECTOR (TRC_HW_IRQ + 0x3) +#define TRC_HW_IRQ_CLEAR_VECTOR (TRC_HW_IRQ + 0x4) +#define TRC_HW_IRQ_MOVE_FINISH (TRC_HW_IRQ + 0x5) +#define TRC_HW_IRQ_ASSIGN_VECTOR (TRC_HW_IRQ + 0x6) +#define TRC_HW_IRQ_UNMAPPED_VECTOR (TRC_HW_IRQ + 0x7) +#define TRC_HW_IRQ_HANDLED (TRC_HW_IRQ + 0x8) + +/* + * Event Flags + * + * Some events (e.g, TRC_PV_TRAP and TRC_HVM_IOMEM_READ) have multiple + * record formats. These event flags distinguish between the + * different formats. + */ +#define TRC_64_FLAG 0x100 /* Addresses are 64 bits (instead of 32 bits) */ + +/* This structure represents a single trace buffer record. */ +struct t_rec { + uint32_t event:28; + uint32_t extra_u32:3; /* # entries in trailing extra_u32[] array */ + uint32_t cycles_included:1; /* u.cycles or u.no_cycles? */ + union { + struct { + uint32_t cycles_lo, cycles_hi; /* cycle counter timestamp */ + uint32_t extra_u32[7]; /* event data items */ + } cycles; + struct { + uint32_t extra_u32[7]; /* event data items */ + } nocycles; + } u; +}; + +/* + * This structure contains the metadata for a single trace buffer. The head + * field, indexes into an array of struct t_rec's. + */ +struct t_buf { + /* Assume the data buffer size is X. X is generally not a power of 2. + * CONS and PROD are incremented modulo (2*X): + * 0 <= cons < 2*X + * 0 <= prod < 2*X + * This is done because addition modulo X breaks at 2^32 when X is not a + * power of 2: + * (((2^32 - 1) % X) + 1) % X != (2^32) % X + */ + uint32_t cons; /* Offset of next item to be consumed by control tools. */ + uint32_t prod; /* Offset of next item to be produced by Xen. */ + /* Records follow immediately after the meta-data header. */ +}; + +/* Structure used to pass MFNs to the trace buffers back to trace consumers. + * Offset is an offset into the mapped structure where the mfn list will be held. + * MFNs will be at ((unsigned long *)(t_info))+(t_info->cpu_offset[cpu]). + */ +struct t_info { + uint16_t tbuf_size; /* Size in pages of each trace buffer */ + uint16_t mfn_offset[]; /* Offset within t_info structure of the page list per cpu */ + /* MFN lists immediately after the header */ +}; + +#endif /* __XEN_PUBLIC_TRACE_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/version.h b/roms/ipxe/src/include/xen/version.h new file mode 100644 index 000000000..4e81ca0f1 --- /dev/null +++ b/roms/ipxe/src/include/xen/version.h @@ -0,0 +1,98 @@ +/****************************************************************************** + * version.h + * + * Xen version, type, and compile information. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com> + * Copyright (c) 2005, Keir Fraser <keir@xensource.com> + */ + +#ifndef __XEN_PUBLIC_VERSION_H__ +#define __XEN_PUBLIC_VERSION_H__ + +FILE_LICENCE ( MIT ); + +#include "xen.h" + +/* NB. All ops return zero on success, except XENVER_{version,pagesize} */ + +/* arg == NULL; returns major:minor (16:16). */ +#define XENVER_version 0 + +/* arg == xen_extraversion_t. */ +#define XENVER_extraversion 1 +typedef char xen_extraversion_t[16]; +#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t)) + +/* arg == xen_compile_info_t. */ +#define XENVER_compile_info 2 +struct xen_compile_info { + char compiler[64]; + char compile_by[16]; + char compile_domain[32]; + char compile_date[32]; +}; +typedef struct xen_compile_info xen_compile_info_t; + +#define XENVER_capabilities 3 +typedef char xen_capabilities_info_t[1024]; +#define XEN_CAPABILITIES_INFO_LEN (sizeof(xen_capabilities_info_t)) + +#define XENVER_changeset 4 +typedef char xen_changeset_info_t[64]; +#define XEN_CHANGESET_INFO_LEN (sizeof(xen_changeset_info_t)) + +#define XENVER_platform_parameters 5 +struct xen_platform_parameters { + xen_ulong_t virt_start; +}; +typedef struct xen_platform_parameters xen_platform_parameters_t; + +#define XENVER_get_features 6 +struct xen_feature_info { + unsigned int submap_idx; /* IN: which 32-bit submap to return */ + uint32_t submap; /* OUT: 32-bit submap */ +}; +typedef struct xen_feature_info xen_feature_info_t; + +/* Declares the features reported by XENVER_get_features. */ +#include "features.h" + +/* arg == NULL; returns host memory page size. */ +#define XENVER_pagesize 7 + +/* arg == xen_domain_handle_t. */ +#define XENVER_guest_handle 8 + +#define XENVER_commandline 9 +typedef char xen_commandline_t[1024]; + +#endif /* __XEN_PUBLIC_VERSION_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/include/xen/xen-compat.h b/roms/ipxe/src/include/xen/xen-compat.h new file mode 100644 index 000000000..0ba6fca66 --- /dev/null +++ b/roms/ipxe/src/include/xen/xen-compat.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * xen-compat.h + * + * Guest OS interface to Xen. Compatibility layer. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2006, Christian Limpach + */ + +#ifndef __XEN_PUBLIC_XEN_COMPAT_H__ +#define __XEN_PUBLIC_XEN_COMPAT_H__ + +FILE_LICENCE ( MIT ); + +#define __XEN_LATEST_INTERFACE_VERSION__ 0x00040400 + +#if defined(__XEN__) || defined(__XEN_TOOLS__) +/* Xen is built with matching headers and implements the latest interface. */ +#define __XEN_INTERFACE_VERSION__ __XEN_LATEST_INTERFACE_VERSION__ +#elif !defined(__XEN_INTERFACE_VERSION__) +/* Guests which do not specify a version get the legacy interface. */ +#define __XEN_INTERFACE_VERSION__ 0x00000000 +#endif + +#if __XEN_INTERFACE_VERSION__ > __XEN_LATEST_INTERFACE_VERSION__ +#error "These header files do not support the requested interface version." +#endif + +#endif /* __XEN_PUBLIC_XEN_COMPAT_H__ */ diff --git a/roms/ipxe/src/include/xen/xen.h b/roms/ipxe/src/include/xen/xen.h new file mode 100644 index 000000000..2da521d23 --- /dev/null +++ b/roms/ipxe/src/include/xen/xen.h @@ -0,0 +1,901 @@ +/****************************************************************************** + * xen.h + * + * Guest OS interface to Xen. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (c) 2004, K A Fraser + */ + +#ifndef __XEN_PUBLIC_XEN_H__ +#define __XEN_PUBLIC_XEN_H__ + +FILE_LICENCE ( MIT ); + +#include "xen-compat.h" + +#if defined(__i386__) || defined(__x86_64__) +#include "arch-x86/xen.h" +#elif defined(__arm__) || defined (__aarch64__) +#include "arch-arm.h" +#else +#error "Unsupported architecture" +#endif + +#ifndef __ASSEMBLY__ +/* Guest handles for primitive C types. */ +DEFINE_XEN_GUEST_HANDLE(char); +__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char); +DEFINE_XEN_GUEST_HANDLE(int); +__DEFINE_XEN_GUEST_HANDLE(uint, unsigned int); +#if __XEN_INTERFACE_VERSION__ < 0x00040300 +DEFINE_XEN_GUEST_HANDLE(long); +__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); +#endif +DEFINE_XEN_GUEST_HANDLE(void); + +DEFINE_XEN_GUEST_HANDLE(uint64_t); +DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); +DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); +#endif + +/* + * HYPERCALLS + */ + +/* `incontents 100 hcalls List of hypercalls + * ` enum hypercall_num { // __HYPERVISOR_* => HYPERVISOR_*() + */ + +#define __HYPERVISOR_set_trap_table 0 +#define __HYPERVISOR_mmu_update 1 +#define __HYPERVISOR_set_gdt 2 +#define __HYPERVISOR_stack_switch 3 +#define __HYPERVISOR_set_callbacks 4 +#define __HYPERVISOR_fpu_taskswitch 5 +#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */ +#define __HYPERVISOR_platform_op 7 +#define __HYPERVISOR_set_debugreg 8 +#define __HYPERVISOR_get_debugreg 9 +#define __HYPERVISOR_update_descriptor 10 +#define __HYPERVISOR_memory_op 12 +#define __HYPERVISOR_multicall 13 +#define __HYPERVISOR_update_va_mapping 14 +#define __HYPERVISOR_set_timer_op 15 +#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */ +#define __HYPERVISOR_xen_version 17 +#define __HYPERVISOR_console_io 18 +#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */ +#define __HYPERVISOR_grant_table_op 20 +#define __HYPERVISOR_vm_assist 21 +#define __HYPERVISOR_update_va_mapping_otherdomain 22 +#define __HYPERVISOR_iret 23 /* x86 only */ +#define __HYPERVISOR_vcpu_op 24 +#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ +#define __HYPERVISOR_mmuext_op 26 +#define __HYPERVISOR_xsm_op 27 +#define __HYPERVISOR_nmi_op 28 +#define __HYPERVISOR_sched_op 29 +#define __HYPERVISOR_callback_op 30 +#define __HYPERVISOR_xenoprof_op 31 +#define __HYPERVISOR_event_channel_op 32 +#define __HYPERVISOR_physdev_op 33 +#define __HYPERVISOR_hvm_op 34 +#define __HYPERVISOR_sysctl 35 +#define __HYPERVISOR_domctl 36 +#define __HYPERVISOR_kexec_op 37 +#define __HYPERVISOR_tmem_op 38 +#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ + +/* Architecture-specific hypercall definitions. */ +#define __HYPERVISOR_arch_0 48 +#define __HYPERVISOR_arch_1 49 +#define __HYPERVISOR_arch_2 50 +#define __HYPERVISOR_arch_3 51 +#define __HYPERVISOR_arch_4 52 +#define __HYPERVISOR_arch_5 53 +#define __HYPERVISOR_arch_6 54 +#define __HYPERVISOR_arch_7 55 + +/* ` } */ + +/* + * HYPERCALL COMPATIBILITY. + */ + +/* New sched_op hypercall introduced in 0x00030101. */ +#if __XEN_INTERFACE_VERSION__ < 0x00030101 +#undef __HYPERVISOR_sched_op +#define __HYPERVISOR_sched_op __HYPERVISOR_sched_op_compat +#endif + +/* New event-channel and physdev hypercalls introduced in 0x00030202. */ +#if __XEN_INTERFACE_VERSION__ < 0x00030202 +#undef __HYPERVISOR_event_channel_op +#define __HYPERVISOR_event_channel_op __HYPERVISOR_event_channel_op_compat +#undef __HYPERVISOR_physdev_op +#define __HYPERVISOR_physdev_op __HYPERVISOR_physdev_op_compat +#endif + +/* New platform_op hypercall introduced in 0x00030204. */ +#if __XEN_INTERFACE_VERSION__ < 0x00030204 +#define __HYPERVISOR_dom0_op __HYPERVISOR_platform_op +#endif + +/* + * VIRTUAL INTERRUPTS + * + * Virtual interrupts that a guest OS may receive from Xen. + * + * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a + * global VIRQ. The former can be bound once per VCPU and cannot be re-bound. + * The latter can be allocated only once per guest: they must initially be + * allocated to VCPU0 but can subsequently be re-bound. + */ +/* ` enum virq { */ +#define VIRQ_TIMER 0 /* V. Timebase update, and/or requested timeout. */ +#define VIRQ_DEBUG 1 /* V. Request guest to dump debug info. */ +#define VIRQ_CONSOLE 2 /* G. (DOM0) Bytes received on emergency console. */ +#define VIRQ_DOM_EXC 3 /* G. (DOM0) Exceptional event for some domain. */ +#define VIRQ_TBUF 4 /* G. (DOM0) Trace buffer has records available. */ +#define VIRQ_DEBUGGER 6 /* G. (DOM0) A domain has paused for debugging. */ +#define VIRQ_XENOPROF 7 /* V. XenOprofile interrupt: new sample available */ +#define VIRQ_CON_RING 8 /* G. (DOM0) Bytes received on console */ +#define VIRQ_PCPU_STATE 9 /* G. (DOM0) PCPU state changed */ +#define VIRQ_MEM_EVENT 10 /* G. (DOM0) A memory event has occured */ +#define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient */ +#define VIRQ_ENOMEM 12 /* G. (DOM0) Low on heap memory */ + +/* Architecture-specific VIRQ definitions. */ +#define VIRQ_ARCH_0 16 +#define VIRQ_ARCH_1 17 +#define VIRQ_ARCH_2 18 +#define VIRQ_ARCH_3 19 +#define VIRQ_ARCH_4 20 +#define VIRQ_ARCH_5 21 +#define VIRQ_ARCH_6 22 +#define VIRQ_ARCH_7 23 +/* ` } */ + +#define NR_VIRQS 24 + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_mmu_update(const struct mmu_update reqs[], + * ` unsigned count, unsigned *done_out, + * ` unsigned foreigndom) + * ` + * @reqs is an array of mmu_update_t structures ((ptr, val) pairs). + * @count is the length of the above array. + * @pdone is an output parameter indicating number of completed operations + * @foreigndom[15:0]: FD, the expected owner of data pages referenced in this + * hypercall invocation. Can be DOMID_SELF. + * @foreigndom[31:16]: PFD, the expected owner of pagetable pages referenced + * in this hypercall invocation. The value of this field + * (x) encodes the PFD as follows: + * x == 0 => PFD == DOMID_SELF + * x != 0 => PFD == x - 1 + * + * Sub-commands: ptr[1:0] specifies the appropriate MMU_* command. + * ------------- + * ptr[1:0] == MMU_NORMAL_PT_UPDATE: + * Updates an entry in a page table belonging to PFD. If updating an L1 table, + * and the new table entry is valid/present, the mapped frame must belong to + * FD. If attempting to map an I/O page then the caller assumes the privilege + * of the FD. + * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller. + * FD == DOMID_XEN: Map restricted areas of Xen's heap space. + * ptr[:2] -- Machine address of the page-table entry to modify. + * val -- Value to write. + * + * There also certain implicit requirements when using this hypercall. The + * pages that make up a pagetable must be mapped read-only in the guest. + * This prevents uncontrolled guest updates to the pagetable. Xen strictly + * enforces this, and will disallow any pagetable update which will end up + * mapping pagetable page RW, and will disallow using any writable page as a + * pagetable. In practice it means that when constructing a page table for a + * process, thread, etc, we MUST be very dilligient in following these rules: + * 1). Start with top-level page (PGD or in Xen language: L4). Fill out + * the entries. + * 2). Keep on going, filling out the upper (PUD or L3), and middle (PMD + * or L2). + * 3). Start filling out the PTE table (L1) with the PTE entries. Once + * done, make sure to set each of those entries to RO (so writeable bit + * is unset). Once that has been completed, set the PMD (L2) for this + * PTE table as RO. + * 4). When completed with all of the PMD (L2) entries, and all of them have + * been set to RO, make sure to set RO the PUD (L3). Do the same + * operation on PGD (L4) pagetable entries that have a PUD (L3) entry. + * 5). Now before you can use those pages (so setting the cr3), you MUST also + * pin them so that the hypervisor can verify the entries. This is done + * via the HYPERVISOR_mmuext_op(MMUEXT_PIN_L4_TABLE, guest physical frame + * number of the PGD (L4)). And this point the HYPERVISOR_mmuext_op( + * MMUEXT_NEW_BASEPTR, guest physical frame number of the PGD (L4)) can be + * issued. + * For 32-bit guests, the L4 is not used (as there is less pagetables), so + * instead use L3. + * At this point the pagetables can be modified using the MMU_NORMAL_PT_UPDATE + * hypercall. Also if so desired the OS can also try to write to the PTE + * and be trapped by the hypervisor (as the PTE entry is RO). + * + * To deallocate the pages, the operations are the reverse of the steps + * mentioned above. The argument is MMUEXT_UNPIN_TABLE for all levels and the + * pagetable MUST not be in use (meaning that the cr3 is not set to it). + * + * ptr[1:0] == MMU_MACHPHYS_UPDATE: + * Updates an entry in the machine->pseudo-physical mapping table. + * ptr[:2] -- Machine address within the frame whose mapping to modify. + * The frame must belong to the FD, if one is specified. + * val -- Value to write into the mapping entry. + * + * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD: + * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed + * with those in @val. + * + * @val is usually the machine frame number along with some attributes. + * The attributes by default follow the architecture defined bits. Meaning that + * if this is a X86_64 machine and four page table layout is used, the layout + * of val is: + * - 63 if set means No execute (NX) + * - 46-13 the machine frame number + * - 12 available for guest + * - 11 available for guest + * - 10 available for guest + * - 9 available for guest + * - 8 global + * - 7 PAT (PSE is disabled, must use hypercall to make 4MB or 2MB pages) + * - 6 dirty + * - 5 accessed + * - 4 page cached disabled + * - 3 page write through + * - 2 userspace accessible + * - 1 writeable + * - 0 present + * + * The one bits that does not fit with the default layout is the PAGE_PSE + * also called PAGE_PAT). The MMUEXT_[UN]MARK_SUPER arguments to the + * HYPERVISOR_mmuext_op serve as mechanism to set a pagetable to be 4MB + * (or 2MB) instead of using the PAGE_PSE bit. + * + * The reason that the PAGE_PSE (bit 7) is not being utilized is due to Xen + * using it as the Page Attribute Table (PAT) bit - for details on it please + * refer to Intel SDM 10.12. The PAT allows to set the caching attributes of + * pages instead of using MTRRs. + * + * The PAT MSR is as follows (it is a 64-bit value, each entry is 8 bits): + * PAT4 PAT0 + * +-----+-----+----+----+----+-----+----+----+ + * | UC | UC- | WC | WB | UC | UC- | WC | WB | <= Linux + * +-----+-----+----+----+----+-----+----+----+ + * | UC | UC- | WT | WB | UC | UC- | WT | WB | <= BIOS (default when machine boots) + * +-----+-----+----+----+----+-----+----+----+ + * | rsv | rsv | WP | WC | UC | UC- | WT | WB | <= Xen + * +-----+-----+----+----+----+-----+----+----+ + * + * The lookup of this index table translates to looking up + * Bit 7, Bit 4, and Bit 3 of val entry: + * + * PAT/PSE (bit 7) ... PCD (bit 4) .. PWT (bit 3). + * + * If all bits are off, then we are using PAT0. If bit 3 turned on, + * then we are using PAT1, if bit 3 and bit 4, then PAT2.. + * + * As you can see, the Linux PAT1 translates to PAT4 under Xen. Which means + * that if a guest that follows Linux's PAT setup and would like to set Write + * Combined on pages it MUST use PAT4 entry. Meaning that Bit 7 (PAGE_PAT) is + * set. For example, under Linux it only uses PAT0, PAT1, and PAT2 for the + * caching as: + * + * WB = none (so PAT0) + * WC = PWT (bit 3 on) + * UC = PWT | PCD (bit 3 and 4 are on). + * + * To make it work with Xen, it needs to translate the WC bit as so: + * + * PWT (so bit 3 on) --> PAT (so bit 7 is on) and clear bit 3 + * + * And to translate back it would: + * + * PAT (bit 7 on) --> PWT (bit 3 on) and clear bit 7. + */ +#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */ +#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */ +#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */ + +/* + * MMU EXTENDED OPERATIONS + * + * ` enum neg_errnoval + * ` HYPERVISOR_mmuext_op(mmuext_op_t uops[], + * ` unsigned int count, + * ` unsigned int *pdone, + * ` unsigned int foreigndom) + */ +/* HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures. + * A foreigndom (FD) can be specified (or DOMID_SELF for none). + * Where the FD has some effect, it is described below. + * + * cmd: MMUEXT_(UN)PIN_*_TABLE + * mfn: Machine frame number to be (un)pinned as a p.t. page. + * The frame must belong to the FD, if one is specified. + * + * cmd: MMUEXT_NEW_BASEPTR + * mfn: Machine frame number of new page-table base to install in MMU. + * + * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only] + * mfn: Machine frame number of new page-table base to install in MMU + * when in user space. + * + * cmd: MMUEXT_TLB_FLUSH_LOCAL + * No additional arguments. Flushes local TLB. + * + * cmd: MMUEXT_INVLPG_LOCAL + * linear_addr: Linear address to be flushed from the local TLB. + * + * cmd: MMUEXT_TLB_FLUSH_MULTI + * vcpumask: Pointer to bitmap of VCPUs to be flushed. + * + * cmd: MMUEXT_INVLPG_MULTI + * linear_addr: Linear address to be flushed. + * vcpumask: Pointer to bitmap of VCPUs to be flushed. + * + * cmd: MMUEXT_TLB_FLUSH_ALL + * No additional arguments. Flushes all VCPUs' TLBs. + * + * cmd: MMUEXT_INVLPG_ALL + * linear_addr: Linear address to be flushed from all VCPUs' TLBs. + * + * cmd: MMUEXT_FLUSH_CACHE + * No additional arguments. Writes back and flushes cache contents. + * + * cmd: MMUEXT_FLUSH_CACHE_GLOBAL + * No additional arguments. Writes back and flushes cache contents + * on all CPUs in the system. + * + * cmd: MMUEXT_SET_LDT + * linear_addr: Linear address of LDT base (NB. must be page-aligned). + * nr_ents: Number of entries in LDT. + * + * cmd: MMUEXT_CLEAR_PAGE + * mfn: Machine frame number to be cleared. + * + * cmd: MMUEXT_COPY_PAGE + * mfn: Machine frame number of the destination page. + * src_mfn: Machine frame number of the source page. + * + * cmd: MMUEXT_[UN]MARK_SUPER + * mfn: Machine frame number of head of superpage to be [un]marked. + */ +/* ` enum mmuext_cmd { */ +#define MMUEXT_PIN_L1_TABLE 0 +#define MMUEXT_PIN_L2_TABLE 1 +#define MMUEXT_PIN_L3_TABLE 2 +#define MMUEXT_PIN_L4_TABLE 3 +#define MMUEXT_UNPIN_TABLE 4 +#define MMUEXT_NEW_BASEPTR 5 +#define MMUEXT_TLB_FLUSH_LOCAL 6 +#define MMUEXT_INVLPG_LOCAL 7 +#define MMUEXT_TLB_FLUSH_MULTI 8 +#define MMUEXT_INVLPG_MULTI 9 +#define MMUEXT_TLB_FLUSH_ALL 10 +#define MMUEXT_INVLPG_ALL 11 +#define MMUEXT_FLUSH_CACHE 12 +#define MMUEXT_SET_LDT 13 +#define MMUEXT_NEW_USER_BASEPTR 15 +#define MMUEXT_CLEAR_PAGE 16 +#define MMUEXT_COPY_PAGE 17 +#define MMUEXT_FLUSH_CACHE_GLOBAL 18 +#define MMUEXT_MARK_SUPER 19 +#define MMUEXT_UNMARK_SUPER 20 +/* ` } */ + +#ifndef __ASSEMBLY__ +struct mmuext_op { + unsigned int cmd; /* => enum mmuext_cmd */ + union { + /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR + * CLEAR_PAGE, COPY_PAGE, [UN]MARK_SUPER */ + xen_pfn_t mfn; + /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */ + unsigned long linear_addr; + } arg1; + union { + /* SET_LDT */ + unsigned int nr_ents; + /* TLB_FLUSH_MULTI, INVLPG_MULTI */ +#if __XEN_INTERFACE_VERSION__ >= 0x00030205 + XEN_GUEST_HANDLE(const_void) vcpumask; +#else + const void *vcpumask; +#endif + /* COPY_PAGE */ + xen_pfn_t src_mfn; + } arg2; +}; +typedef struct mmuext_op mmuext_op_t; +DEFINE_XEN_GUEST_HANDLE(mmuext_op_t); +#endif + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_update_va_mapping(unsigned long va, u64 val, + * ` enum uvm_flags flags) + * ` + * ` enum neg_errnoval + * ` HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, u64 val, + * ` enum uvm_flags flags, + * ` domid_t domid) + * ` + * ` @va: The virtual address whose mapping we want to change + * ` @val: The new page table entry, must contain a machine address + * ` @flags: Control TLB flushes + */ +/* These are passed as 'flags' to update_va_mapping. They can be ORed. */ +/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */ +/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */ +/* ` enum uvm_flags { */ +#define UVMF_NONE (0UL<<0) /* No flushing at all. */ +#define UVMF_TLB_FLUSH (1UL<<0) /* Flush entire TLB(s). */ +#define UVMF_INVLPG (2UL<<0) /* Flush only one entry. */ +#define UVMF_FLUSHTYPE_MASK (3UL<<0) +#define UVMF_MULTI (0UL<<2) /* Flush subset of TLBs. */ +#define UVMF_LOCAL (0UL<<2) /* Flush local TLB. */ +#define UVMF_ALL (1UL<<2) /* Flush all TLBs. */ +/* ` } */ + +/* + * Commands to HYPERVISOR_console_io(). + */ +#define CONSOLEIO_write 0 +#define CONSOLEIO_read 1 + +/* + * Commands to HYPERVISOR_vm_assist(). + */ +#define VMASST_CMD_enable 0 +#define VMASST_CMD_disable 1 + +/* x86/32 guests: simulate full 4GB segment limits. */ +#define VMASST_TYPE_4gb_segments 0 + +/* x86/32 guests: trap (vector 15) whenever above vmassist is used. */ +#define VMASST_TYPE_4gb_segments_notify 1 + +/* + * x86 guests: support writes to bottom-level PTEs. + * NB1. Page-directory entries cannot be written. + * NB2. Guest must continue to remove all writable mappings of PTEs. + */ +#define VMASST_TYPE_writable_pagetables 2 + +/* x86/PAE guests: support PDPTs above 4GB. */ +#define VMASST_TYPE_pae_extended_cr3 3 + +#define MAX_VMASST_TYPE 3 + +#ifndef __ASSEMBLY__ + +typedef uint16_t domid_t; + +/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */ +#define DOMID_FIRST_RESERVED (0x7FF0U) + +/* DOMID_SELF is used in certain contexts to refer to oneself. */ +#define DOMID_SELF (0x7FF0U) + +/* + * DOMID_IO is used to restrict page-table updates to mapping I/O memory. + * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO + * is useful to ensure that no mappings to the OS's own heap are accidentally + * installed. (e.g., in Linux this could cause havoc as reference counts + * aren't adjusted on the I/O-mapping code path). + * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can + * be specified by any calling domain. + */ +#define DOMID_IO (0x7FF1U) + +/* + * DOMID_XEN is used to allow privileged domains to map restricted parts of + * Xen's heap space (e.g., the machine_to_phys table). + * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if + * the caller is privileged. + */ +#define DOMID_XEN (0x7FF2U) + +/* + * DOMID_COW is used as the owner of sharable pages */ +#define DOMID_COW (0x7FF3U) + +/* DOMID_INVALID is used to identify pages with unknown owner. */ +#define DOMID_INVALID (0x7FF4U) + +/* Idle domain. */ +#define DOMID_IDLE (0x7FFFU) + +/* + * Send an array of these to HYPERVISOR_mmu_update(). + * NB. The fields are natural pointer/address size for this architecture. + */ +struct mmu_update { + uint64_t ptr; /* Machine address of PTE. */ + uint64_t val; /* New contents of PTE. */ +}; +typedef struct mmu_update mmu_update_t; +DEFINE_XEN_GUEST_HANDLE(mmu_update_t); + +/* + * ` enum neg_errnoval + * ` HYPERVISOR_multicall(multicall_entry_t call_list[], + * ` uint32_t nr_calls); + * + * NB. The fields are logically the natural register size for this + * architecture. In cases where xen_ulong_t is larger than this then + * any unused bits in the upper portion must be zero. + */ +struct multicall_entry { + xen_ulong_t op, result; + xen_ulong_t args[6]; +}; +typedef struct multicall_entry multicall_entry_t; +DEFINE_XEN_GUEST_HANDLE(multicall_entry_t); + +#if __XEN_INTERFACE_VERSION__ < 0x00040400 +/* + * Event channel endpoints per domain (when using the 2-level ABI): + * 1024 if a long is 32 bits; 4096 if a long is 64 bits. + */ +#define NR_EVENT_CHANNELS EVTCHN_2L_NR_CHANNELS +#endif + +struct vcpu_time_info { + /* + * Updates to the following values are preceded and followed by an + * increment of 'version'. The guest can therefore detect updates by + * looking for changes to 'version'. If the least-significant bit of + * the version number is set then an update is in progress and the guest + * must wait to read a consistent set of values. + * The correct way to interact with the version number is similar to + * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry. + */ + uint32_t version; + uint32_t pad0; + uint64_t tsc_timestamp; /* TSC at last update of time vals. */ + uint64_t system_time; /* Time, in nanosecs, since boot. */ + /* + * Current system time: + * system_time + + * ((((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul) >> 32) + * CPU frequency (Hz): + * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift + */ + uint32_t tsc_to_system_mul; + int8_t tsc_shift; + int8_t pad1[3]; +}; /* 32 bytes */ +typedef struct vcpu_time_info vcpu_time_info_t; + +struct vcpu_info { + /* + * 'evtchn_upcall_pending' is written non-zero by Xen to indicate + * a pending notification for a particular VCPU. It is then cleared + * by the guest OS /before/ checking for pending work, thus avoiding + * a set-and-check race. Note that the mask is only accessed by Xen + * on the CPU that is currently hosting the VCPU. This means that the + * pending and mask flags can be updated by the guest without special + * synchronisation (i.e., no need for the x86 LOCK prefix). + * This may seem suboptimal because if the pending flag is set by + * a different CPU then an IPI may be scheduled even when the mask + * is set. However, note: + * 1. The task of 'interrupt holdoff' is covered by the per-event- + * channel mask bits. A 'noisy' event that is continually being + * triggered can be masked at source at this very precise + * granularity. + * 2. The main purpose of the per-VCPU mask is therefore to restrict + * reentrant execution: whether for concurrency control, or to + * prevent unbounded stack usage. Whatever the purpose, we expect + * that the mask will be asserted only for short periods at a time, + * and so the likelihood of a 'spurious' IPI is suitably small. + * The mask is read before making an event upcall to the guest: a + * non-zero mask therefore guarantees that the VCPU will not receive + * an upcall activation. The mask is cleared when the VCPU requests + * to block: this avoids wakeup-waiting races. + */ + uint8_t evtchn_upcall_pending; +#ifdef XEN_HAVE_PV_UPCALL_MASK + uint8_t evtchn_upcall_mask; +#else /* XEN_HAVE_PV_UPCALL_MASK */ + uint8_t pad0; +#endif /* XEN_HAVE_PV_UPCALL_MASK */ + xen_ulong_t evtchn_pending_sel; + struct arch_vcpu_info arch; + struct vcpu_time_info time; +}; /* 64 bytes (x86) */ +#ifndef __XEN__ +typedef struct vcpu_info vcpu_info_t; +#endif + +/* + * `incontents 200 startofday_shared Start-of-day shared data structure + * Xen/kernel shared data -- pointer provided in start_info. + * + * This structure is defined to be both smaller than a page, and the + * only data on the shared page, but may vary in actual size even within + * compatible Xen versions; guests should not rely on the size + * of this structure remaining constant. + */ +struct shared_info { + struct vcpu_info vcpu_info[XEN_LEGACY_MAX_VCPUS]; + + /* + * A domain can create "event channels" on which it can send and receive + * asynchronous event notifications. There are three classes of event that + * are delivered by this mechanism: + * 1. Bi-directional inter- and intra-domain connections. Domains must + * arrange out-of-band to set up a connection (usually by allocating + * an unbound 'listener' port and avertising that via a storage service + * such as xenstore). + * 2. Physical interrupts. A domain with suitable hardware-access + * privileges can bind an event-channel port to a physical interrupt + * source. + * 3. Virtual interrupts ('events'). A domain can bind an event-channel + * port to a virtual interrupt source, such as the virtual-timer + * device or the emergency console. + * + * Event channels are addressed by a "port index". Each channel is + * associated with two bits of information: + * 1. PENDING -- notifies the domain that there is a pending notification + * to be processed. This bit is cleared by the guest. + * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING + * will cause an asynchronous upcall to be scheduled. This bit is only + * updated by the guest. It is read-only within Xen. If a channel + * becomes pending while the channel is masked then the 'edge' is lost + * (i.e., when the channel is unmasked, the guest must manually handle + * pending notifications as no upcall will be scheduled by Xen). + * + * To expedite scanning of pending notifications, any 0->1 pending + * transition on an unmasked channel causes a corresponding bit in a + * per-vcpu selector word to be set. Each bit in the selector covers a + * 'C long' in the PENDING bitfield array. + */ + xen_ulong_t evtchn_pending[sizeof(xen_ulong_t) * 8]; + xen_ulong_t evtchn_mask[sizeof(xen_ulong_t) * 8]; + + /* + * Wallclock time: updated only by control software. Guests should base + * their gettimeofday() syscall on this wallclock-base value. + */ + uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */ + uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */ + uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */ + + struct arch_shared_info arch; + +}; +#ifndef __XEN__ +typedef struct shared_info shared_info_t; +#endif + +/* + * `incontents 200 startofday Start-of-day memory layout + * + * 1. The domain is started within contiguous virtual-memory region. + * 2. The contiguous region ends on an aligned 4MB boundary. + * 3. This the order of bootstrap elements in the initial virtual region: + * a. relocated kernel image + * b. initial ram disk [mod_start, mod_len] + * c. list of allocated page frames [mfn_list, nr_pages] + * (unless relocated due to XEN_ELFNOTE_INIT_P2M) + * d. start_info_t structure [register ESI (x86)] + * e. bootstrap page tables [pt_base and CR3 (x86)] + * f. bootstrap stack [register ESP (x86)] + * 4. Bootstrap elements are packed together, but each is 4kB-aligned. + * 5. The initial ram disk may be omitted. + * 6. The list of page frames forms a contiguous 'pseudo-physical' memory + * layout for the domain. In particular, the bootstrap virtual-memory + * region is a 1:1 mapping to the first section of the pseudo-physical map. + * 7. All bootstrap elements are mapped read-writable for the guest OS. The + * only exception is the bootstrap page table, which is mapped read-only. + * 8. There is guaranteed to be at least 512kB padding after the final + * bootstrap element. If necessary, the bootstrap virtual region is + * extended by an extra 4MB to ensure this. + * + * Note: Prior to 25833:bb85bbccb1c9. ("x86/32-on-64 adjust Dom0 initial page + * table layout") a bug caused the pt_base (3.e above) and cr3 to not point + * to the start of the guest page tables (it was offset by two pages). + * This only manifested itself on 32-on-64 dom0 kernels and not 32-on-64 domU + * or 64-bit kernels of any colour. The page tables for a 32-on-64 dom0 got + * allocated in the order: 'first L1','first L2', 'first L3', so the offset + * to the page table base is by two pages back. The initial domain if it is + * 32-bit and runs under a 64-bit hypervisor should _NOT_ use two of the + * pages preceding pt_base and mark them as reserved/unused. + */ +#ifdef XEN_HAVE_PV_GUEST_ENTRY +struct start_info { + /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */ + char magic[32]; /* "xen-<version>-<platform>". */ + unsigned long nr_pages; /* Total pages allocated to this domain. */ + unsigned long shared_info; /* MACHINE address of shared info struct. */ + uint32_t flags; /* SIF_xxx flags. */ + xen_pfn_t store_mfn; /* MACHINE page number of shared page. */ + uint32_t store_evtchn; /* Event channel for store communication. */ + union { + struct { + xen_pfn_t mfn; /* MACHINE page number of console page. */ + uint32_t evtchn; /* Event channel for console page. */ + } domU; + struct { + uint32_t info_off; /* Offset of console_info struct. */ + uint32_t info_size; /* Size of console_info struct from start.*/ + } dom0; + } console; + /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */ + unsigned long pt_base; /* VIRTUAL address of page directory. */ + unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */ + unsigned long mfn_list; /* VIRTUAL address of page-frame list. */ + unsigned long mod_start; /* VIRTUAL address of pre-loaded module */ + /* (PFN of pre-loaded module if */ + /* SIF_MOD_START_PFN set in flags). */ + unsigned long mod_len; /* Size (bytes) of pre-loaded module. */ +#define MAX_GUEST_CMDLINE 1024 + int8_t cmd_line[MAX_GUEST_CMDLINE]; + /* The pfn range here covers both page table and p->m table frames. */ + unsigned long first_p2m_pfn;/* 1st pfn forming initial P->M table. */ + unsigned long nr_p2m_frames;/* # of pfns forming initial P->M table. */ +}; +typedef struct start_info start_info_t; + +/* New console union for dom0 introduced in 0x00030203. */ +#if __XEN_INTERFACE_VERSION__ < 0x00030203 +#define console_mfn console.domU.mfn +#define console_evtchn console.domU.evtchn +#endif +#endif /* XEN_HAVE_PV_GUEST_ENTRY */ + +/* These flags are passed in the 'flags' field of start_info_t. */ +#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */ +#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */ +#define SIF_MULTIBOOT_MOD (1<<2) /* Is mod_start a multiboot module? */ +#define SIF_MOD_START_PFN (1<<3) /* Is mod_start a PFN? */ +#define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */ + +/* + * A multiboot module is a package containing modules very similar to a + * multiboot module array. The only differences are: + * - the array of module descriptors is by convention simply at the beginning + * of the multiboot module, + * - addresses in the module descriptors are based on the beginning of the + * multiboot module, + * - the number of modules is determined by a termination descriptor that has + * mod_start == 0. + * + * This permits to both build it statically and reference it in a configuration + * file, and let the PV guest easily rebase the addresses to virtual addresses + * and at the same time count the number of modules. + */ +struct xen_multiboot_mod_list +{ + /* Address of first byte of the module */ + uint32_t mod_start; + /* Address of last byte of the module (inclusive) */ + uint32_t mod_end; + /* Address of zero-terminated command line */ + uint32_t cmdline; + /* Unused, must be zero */ + uint32_t pad; +}; +/* + * `incontents 200 startofday_dom0_console Dom0_console + * + * The console structure in start_info.console.dom0 + * + * This structure includes a variety of information required to + * have a working VGA/VESA console. + */ +typedef struct dom0_vga_console_info { + uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */ +#define XEN_VGATYPE_TEXT_MODE_3 0x03 +#define XEN_VGATYPE_VESA_LFB 0x23 +#define XEN_VGATYPE_EFI_LFB 0x70 + + union { + struct { + /* Font height, in pixels. */ + uint16_t font_height; + /* Cursor location (column, row). */ + uint16_t cursor_x, cursor_y; + /* Number of rows and columns (dimensions in characters). */ + uint16_t rows, columns; + } text_mode_3; + + struct { + /* Width and height, in pixels. */ + uint16_t width, height; + /* Bytes per scan line. */ + uint16_t bytes_per_line; + /* Bits per pixel. */ + uint16_t bits_per_pixel; + /* LFB physical address, and size (in units of 64kB). */ + uint32_t lfb_base; + uint32_t lfb_size; + /* RGB mask offsets and sizes, as defined by VBE 1.2+ */ + uint8_t red_pos, red_size; + uint8_t green_pos, green_size; + uint8_t blue_pos, blue_size; + uint8_t rsvd_pos, rsvd_size; +#if __XEN_INTERFACE_VERSION__ >= 0x00030206 + /* VESA capabilities (offset 0xa, VESA command 0x4f00). */ + uint32_t gbl_caps; + /* Mode attributes (offset 0x0, VESA command 0x4f01). */ + uint16_t mode_attrs; +#endif + } vesa_lfb; + } u; +} dom0_vga_console_info_t; +#define xen_vga_console_info dom0_vga_console_info +#define xen_vga_console_info_t dom0_vga_console_info_t + +typedef uint8_t xen_domain_handle_t[16]; + +/* Turn a plain number into a C unsigned long constant. */ +#define __mk_unsigned_long(x) x ## UL +#define mk_unsigned_long(x) __mk_unsigned_long(x) + +__DEFINE_XEN_GUEST_HANDLE(uint8, uint8_t); +__DEFINE_XEN_GUEST_HANDLE(uint16, uint16_t); +__DEFINE_XEN_GUEST_HANDLE(uint32, uint32_t); +__DEFINE_XEN_GUEST_HANDLE(uint64, uint64_t); + +#else /* __ASSEMBLY__ */ + +/* In assembly code we cannot use C numeric constant suffixes. */ +#define mk_unsigned_long(x) x + +#endif /* !__ASSEMBLY__ */ + +/* Default definitions for macros used by domctl/sysctl. */ +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +#ifndef uint64_aligned_t +#define uint64_aligned_t uint64_t +#endif +#ifndef XEN_GUEST_HANDLE_64 +#define XEN_GUEST_HANDLE_64(name) XEN_GUEST_HANDLE(name) +#endif + +#ifndef __ASSEMBLY__ +struct xenctl_bitmap { + XEN_GUEST_HANDLE_64(uint8) bitmap; + uint32_t nr_bits; +}; +#endif + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + +#endif /* __XEN_PUBLIC_XEN_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/roms/ipxe/src/interface/efi/efi_autoboot.c b/roms/ipxe/src/interface/efi/efi_autoboot.c new file mode 100644 index 000000000..ab0f36541 --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_autoboot.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_autoboot.h> +#include <ipxe/efi/Protocol/SimpleNetwork.h> +#include <usr/autoboot.h> + +/** @file + * + * EFI autoboot device + * + */ + +/** + * Identify autoboot device + * + */ +void efi_set_autoboot ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_SIMPLE_NETWORK_PROTOCOL *snp; + void *interface; + } snp; + EFI_SIMPLE_NETWORK_MODE *mode; + EFI_STATUS efirc; + + /* Look for an SNP instance on the image's device handle */ + if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle, + &efi_simple_network_protocol_guid, + &snp.interface, efi_image_handle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + DBGC ( efi_loaded_image, "EFI found no autoboot device\n" ); + return; + } + + /* Record autoboot device */ + mode = snp.snp->Mode; + set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize ); + DBGC ( efi_loaded_image, "EFI found autoboot link-layer address:\n" ); + DBGC_HDA ( efi_loaded_image, 0, &mode->CurrentAddress, + mode->HwAddressSize ); + + /* Close protocol */ + bs->CloseProtocol ( efi_loaded_image->DeviceHandle, + &efi_simple_network_protocol_guid, + efi_image_handle, NULL ); +} diff --git a/roms/ipxe/src/interface/efi/efi_bofm.c b/roms/ipxe/src/interface/efi/efi_bofm.c index 4982b22cc..bdb705196 100644 --- a/roms/ipxe/src/interface/efi/efi_bofm.c +++ b/roms/ipxe/src/interface/efi/efi_bofm.c @@ -21,7 +21,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> #include <ipxe/bofm.h> -#include <ipxe/init.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_pci.h> #include <ipxe/efi/efi_driver.h> @@ -156,49 +155,37 @@ static EFI_GUID bofm2_protocol_guid = /** * Check if device is supported * - * @v driver EFI driver - * @v device EFI device - * @v child Path to child device, if any - * @ret efirc EFI status code + * @v device EFI device handle + * @ret rc Return status code */ -static EFI_STATUS EFIAPI -efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, - EFI_HANDLE device, - EFI_DEVICE_PATH_PROTOCOL *child ) { - struct efi_driver *efidrv = - container_of ( driver, struct efi_driver, driver ); +static int efi_bofm_supported ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct pci_device pci; union { IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1; void *interface; } bofm1; - struct efi_pci_device *efipci; EFI_STATUS efirc; int rc; - DBGCP ( efidrv, "EFIBOFM DRIVER_SUPPORTED %p (%p)\n", device, child ); - - /* Create corresponding PCI device, if any */ - efipci = efipci_create ( efidrv, device ); - if ( ! efipci ) { - rc = -ENOTSUP; - goto err_not_pci; - } + /* Get PCI device information */ + if ( ( rc = efipci_info ( device, &pci ) ) != 0 ) + return rc; /* Look for a BOFM driver */ - if ( ( rc = bofm_find_driver ( &efipci->pci ) ) != 0 ) { - DBGCP ( efidrv, "EFIBOFM " PCI_FMT " has no driver\n", - PCI_ARGS ( &efipci->pci ) ); - goto err_no_driver; + if ( ( rc = bofm_find_driver ( &pci ) ) != 0 ) { + DBGCP ( device, "EFIBOFM %p %s has no driver\n", + device, efi_handle_name ( device ) ); + return rc; } /* Locate BOFM protocol */ if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL, &bofm1.interface ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM " - "protocol\n", PCI_ARGS ( &efipci->pci ) ); - goto err_not_bofm; + DBGC ( device, "EFIBOFM %p %s cannot find BOFM protocol\n", + device, efi_handle_name ( device ) ); + return rc; } /* Register support for this device */ @@ -207,42 +194,25 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, 0x00 /* No iSCSI */, 0x02 /* Version */ ))!=0){ rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not register " - "support: %s\n", PCI_ARGS ( &efipci->pci ), - strerror ( rc ) ); - goto err_cannot_register; + DBGC ( device, "EFIBOFM %p %s could not register support: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); + return rc; } - DBGC ( efidrv, "EFIBOFM " PCI_FMT " is supported by driver \"%s\"\n", - PCI_ARGS ( &efipci->pci ), efipci->pci.id->name ); - - /* Destroy temporary PCI device */ - efipci_destroy ( efidrv, efipci ); - + DBGC ( device, "EFIBOFM %p %s has driver \"%s\"\n", + device, efi_handle_name ( device ), pci.id->name ); return 0; - - err_cannot_register: - err_not_bofm: - err_no_driver: - efipci_destroy ( efidrv, efipci ); - err_not_pci: - return EFIRC ( rc ); } /** * Attach driver to device * - * @v driver EFI driver - * @v device EFI device - * @v child Path to child device, if any - * @ret efirc EFI status code + * @v efidev EFI device + * @ret rc Return status code */ -static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, - EFI_HANDLE device, - EFI_DEVICE_PATH_PROTOCOL *child ) { - struct efi_driver *efidrv = - container_of ( driver, struct efi_driver, driver ); +static int efi_bofm_start ( struct efi_device *efidev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efidev->device; union { IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1; void *interface; @@ -251,75 +221,66 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 *bofm2; void *interface; } bofm2; - struct efi_pci_device *efipci; + struct pci_device pci; IBM_BOFM_TABLE *bofmtab; IBM_BOFM_TABLE *bofmtab2; int bofmrc; EFI_STATUS efirc; int rc; - DBGCP ( efidrv, "EFIBOFM DRIVER_START %p (%p)\n", device, child ); - - /* Create corresponding PCI device */ - efipci = efipci_create ( efidrv, device ); - if ( ! efipci ) { - rc = -ENOMEM; - goto err_create; - } - - /* Enable PCI device */ - if ( ( rc = efipci_enable ( efipci ) ) != 0 ) - goto err_enable; + /* Open PCI device, if possible */ + if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL, + &pci ) ) != 0 ) + goto err_open; /* Locate BOFM protocol */ if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL, &bofm1.interface ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM " - "protocol\n", PCI_ARGS ( &efipci->pci ) ); + DBGC ( device, "EFIBOFM %p %s cannot find BOFM protocol\n", + device, efi_handle_name ( device ) ); goto err_locate_bofm; } bofmtab = &bofm1.bofm1->BofmTable; - DBGC ( efidrv, "EFIBOFM " PCI_FMT " found version 1 BOFM table at " - "%p+%04x\n", PCI_ARGS ( &efipci->pci ), bofmtab, + DBGC ( device, "EFIBOFM %p %s found version 1 BOFM table at %p+%04x\n", + device, efi_handle_name ( device ), bofmtab, bofmtab->Parameters.Length ); /* Locate BOFM2 protocol, if available */ if ( ( efirc = bs->LocateProtocol ( &bofm2_protocol_guid, NULL, &bofm2.interface ) ) == 0 ) { bofmtab2 = &bofm2.bofm2->BofmTable; - DBGC ( efidrv, "EFIBOFM " PCI_FMT " found version 2 BOFM table " - "at %p+%04x\n", PCI_ARGS ( &efipci->pci ), bofmtab2, - bofmtab2->Parameters.Length ); + DBGC ( device, "EFIBOFM %p %s found version 2 BOFM table at " + "%p+%04x\n", device, efi_handle_name ( device ), + bofmtab2, bofmtab2->Parameters.Length ); assert ( bofm2.bofm2->RegisterSupport == bofm1.bofm1->RegisterSupport ); } else { - DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM2 " - "protocol\n", PCI_ARGS ( &efipci->pci ) ); + DBGC ( device, "EFIBOFM %p %s cannot find BOFM2 protocol\n", + device, efi_handle_name ( device ) ); /* Not a fatal error; may be a BOFM1-only system */ bofmtab2 = NULL; } /* Process BOFM table */ - DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 1 before processing:\n", - PCI_ARGS ( &efipci->pci ) ); - DBGC2_HD ( efidrv, bofmtab, bofmtab->Parameters.Length ); + DBGC2 ( device, "EFIBOFM %p %s version 1 before processing:\n", + device, efi_handle_name ( device ) ); + DBGC2_HD ( device, bofmtab, bofmtab->Parameters.Length ); if ( bofmtab2 ) { - DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 2 before " - "processing:\n", PCI_ARGS ( &efipci->pci ) ); - DBGC2_HD ( efidrv, bofmtab2, bofmtab2->Parameters.Length ); + DBGC2 ( device, "EFIBOFM %p %s version 2 before processing:\n", + device, efi_handle_name ( device ) ); + DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length ); } - bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ), - &efipci->pci ); - DBGC ( efidrv, "EFIBOFM " PCI_FMT " status %08x\n", - PCI_ARGS ( &efipci->pci ), bofmrc ); - DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 1 after processing:\n", - PCI_ARGS ( &efipci->pci ) ); - DBGC2_HD ( efidrv, bofmtab, bofmtab->Parameters.Length ); + bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ), &pci ); + DBGC ( device, "EFIBOFM %p %s status %08x\n", + device, efi_handle_name ( device ), bofmrc ); + DBGC2 ( device, "EFIBOFM %p %s version 1 after processing:\n", + device, efi_handle_name ( device ) ); + DBGC2_HD ( device, bofmtab, bofmtab->Parameters.Length ); if ( bofmtab2 ) { - DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 2 after " - "processing:\n", PCI_ARGS ( &efipci->pci ) ); - DBGC2_HD ( efidrv, bofmtab2, bofmtab2->Parameters.Length ); + DBGC2 ( device, "EFIBOFM %p %s version 2 after processing:\n", + device, efi_handle_name ( device ) ); + DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length ); } /* Return BOFM status */ @@ -327,93 +288,47 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, if ( ( efirc = bofm2.bofm2->SetStatus ( bofm2.bofm2, device, FALSE, bofmrc ) ) != 0){ rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set " - "BOFM2 status: %s\n", PCI_ARGS ( &efipci->pci ), - strerror ( rc ) ); + DBGC ( device, "EFIBOFM %p %s could not set BOFM2 " + "status: %s\n", device, + efi_handle_name ( device ), strerror ( rc ) ); goto err_set_status; } } else { if ( ( efirc = bofm1.bofm1->SetStatus ( bofm1.bofm1, device, FALSE, bofmrc ) ) != 0){ rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set " - "BOFM status: %s\n", PCI_ARGS ( &efipci->pci ), - strerror ( rc ) ); + DBGC ( device, "EFIBOFM %p %s could not set BOFM " + "status: %s\n", device, + efi_handle_name ( device ), strerror ( rc ) ); goto err_set_status; } } - /* Destroy the PCI device anyway; we have no further use for it */ - efipci_destroy ( efidrv, efipci ); - /* BOFM (ab)uses the "start" method to mean "process and exit" */ - return EFI_NOT_READY; + rc = -EAGAIN; err_set_status: err_locate_bofm: - err_enable: - efipci_destroy ( efidrv, efipci ); - err_create: - return EFIRC ( rc ); + efipci_close ( device ); + err_open: + return rc; } /** * Detach driver from device * - * @v driver EFI driver * @v device EFI device - * @v num_children Number of child devices - * @v children List of child devices - * @ret efirc EFI status code */ -static EFI_STATUS EFIAPI efi_bofm_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, - EFI_HANDLE device, UINTN num_children, - EFI_HANDLE *children ) { - struct efi_driver *efidrv = - container_of ( driver, struct efi_driver, driver ); - - DBGCP ( efidrv, "EFIBOFM DRIVER_STOP %p (%ld %p)\n", - device, ( ( unsigned long ) num_children ), children ); +static void efi_bofm_stop ( struct efi_device *efidev __unused ) { - return 0; + /* Should never happen */ + assert ( 0 ); } /** EFI BOFM driver */ -static struct efi_driver efi_bofm_driver = - EFI_DRIVER_INIT ( "BOFM", - efi_bofm_supported, efi_bofm_start, efi_bofm_stop ); - -/** - * Install EFI BOFM driver - * - */ -static void efi_bofm_driver_startup ( void ) { - struct efi_driver *efidrv = &efi_bofm_driver; - int rc; - - /* Install driver */ - if ( ( rc = efi_driver_install ( efidrv ) ) != 0 ) { - DBGC ( efidrv, "EFIBOFM could not install driver: %s\n", - strerror ( rc ) ); - return; - } - - DBGC ( efidrv, "EFIBOFM driver installed\n" ); -} - -/** - * Shut down EFI BOFM driver - * - * @v booting System is shutting down for OS boot - */ -static void efi_bofm_driver_shutdown ( int booting __unused ) { - struct efi_driver *efidrv = &efi_bofm_driver; - - efi_driver_uninstall ( efidrv ); -} - -/** EFI BOFM startup function */ -struct startup_fn startup_bofm __startup_fn ( STARTUP_EARLY ) = { - .startup = efi_bofm_driver_startup, - .shutdown = efi_bofm_driver_shutdown, +struct efi_driver efi_bofm_driver __efi_driver ( EFI_DRIVER_EARLY ) = { + .name = "BOFM", + .supported = efi_bofm_supported, + .start = efi_bofm_start, + .stop = efi_bofm_stop, }; diff --git a/roms/ipxe/src/interface/efi/efi_console.c b/roms/ipxe/src/interface/efi/efi_console.c index af60d4f91..3b30f3097 100644 --- a/roms/ipxe/src/interface/efi/efi_console.c +++ b/roms/ipxe/src/interface/efi/efi_console.c @@ -24,8 +24,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> #include <assert.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/Protocol/ConsoleControl/ConsoleControl.h> #include <ipxe/ansiesc.h> #include <ipxe/console.h> +#include <ipxe/init.h> #include <config/console.h> #define ATTR_BOLD 0x08 @@ -61,6 +63,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Current character attribute */ static unsigned int efi_attr = ATTR_DEFAULT; +/** Console control protocol */ +static EFI_CONSOLE_CONTROL_PROTOCOL *conctrl; +EFI_REQUEST_PROTOCOL ( EFI_CONSOLE_CONTROL_PROTOCOL, &conctrl ); + /** * Handle ANSI CUP (cursor position) * @@ -146,11 +152,43 @@ static void efi_handle_sgr ( struct ansiesc_context *ctx __unused, conout->SetAttribute ( conout, efi_attr ); } +/** + * Handle ANSI DECTCEM set (show cursor) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void efi_handle_dectcem_set ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, + int params[] __unused ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + + conout->EnableCursor ( conout, TRUE ); +} + +/** + * Handle ANSI DECTCEM reset (hide cursor) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void efi_handle_dectcem_reset ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, + int params[] __unused ) { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; + + conout->EnableCursor ( conout, FALSE ); +} + /** EFI console ANSI escape sequence handlers */ static struct ansiesc_handler efi_ansiesc_handlers[] = { { ANSIESC_CUP, efi_handle_cup }, { ANSIESC_ED, efi_handle_ed }, { ANSIESC_SGR, efi_handle_sgr }, + { ANSIESC_DECTCEM_SET, efi_handle_dectcem_set }, + { ANSIESC_DECTCEM_RESET, efi_handle_dectcem_reset }, { 0, NULL } }; @@ -286,9 +324,37 @@ static int efi_iskey ( void ) { return 0; } +/** EFI console driver */ struct console_driver efi_console __console_driver = { .putchar = efi_putchar, .getchar = efi_getchar, .iskey = efi_iskey, .usage = CONSOLE_EFI, }; + +/** + * Initialise EFI console + * + */ +static void efi_console_init ( void ) { + EFI_CONSOLE_CONTROL_SCREEN_MODE mode; + + /* On some older EFI 1.10 implementations, we must use the + * (now obsolete) EFI_CONSOLE_CONTROL_PROTOCOL to switch the + * console into text mode. + */ + if ( conctrl ) { + conctrl->GetMode ( conctrl, &mode, NULL, NULL ); + if ( mode != EfiConsoleControlScreenText ) { + conctrl->SetMode ( conctrl, + EfiConsoleControlScreenText ); + } + } +} + +/** + * EFI console initialisation function + */ +struct init_fn efi_console_init_fn __init_fn ( INIT_EARLY ) = { + .initialise = efi_console_init, +}; diff --git a/roms/ipxe/src/interface/efi/efi_debug.c b/roms/ipxe/src/interface/efi/efi_debug.c index 4ed666077..d23960140 100644 --- a/roms/ipxe/src/interface/efi/efi_debug.c +++ b/roms/ipxe/src/interface/efi/efi_debug.c @@ -30,14 +30,119 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <string.h> #include <errno.h> #include <ipxe/uuid.h> +#include <ipxe/base16.h> #include <ipxe/efi/efi.h> -#include <ipxe/efi/efi_driver.h> -#include <ipxe/efi/Protocol/DevicePath.h> +#include <ipxe/efi/efi_utils.h> +#include <ipxe/efi/Protocol/ComponentName.h> +#include <ipxe/efi/Protocol/ComponentName2.h> #include <ipxe/efi/Protocol/DevicePathToText.h> +#include <ipxe/efi/IndustryStandard/PeImage.h> /** Device path to text protocol */ static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *efidpt; -EFI_REQUIRE_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt ); +EFI_REQUEST_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt ); + +/** Iscsi4Dxe module GUID */ +static EFI_GUID efi_iscsi4_dxe_guid = { + 0x4579b72d, 0x7ec4, 0x4dd4, + { 0x84, 0x86, 0x08, 0x3c, 0x86, 0xb1, 0x82, 0xa7 } +}; + +/** VlanConfigDxe module GUID */ +static EFI_GUID efi_vlan_config_dxe_guid = { + 0xe4f61863, 0xfe2c, 0x4b56, + { 0xa8, 0xf4, 0x08, 0x51, 0x9b, 0xc4, 0x39, 0xdf } +}; + +/** A well-known GUID */ +struct efi_well_known_guid { + /** GUID */ + EFI_GUID *guid; + /** Name */ + const char *name; +}; + +/** Well-known GUIDs */ +static struct efi_well_known_guid efi_well_known_guids[] = { + { &efi_arp_protocol_guid, + "Arp" }, + { &efi_arp_service_binding_protocol_guid, + "ArpSb" }, + { &efi_block_io_protocol_guid, + "BlockIo" }, + { &efi_bus_specific_driver_override_protocol_guid, + "BusSpecificDriverOverride" }, + { &efi_component_name_protocol_guid, + "ComponentName" }, + { &efi_component_name2_protocol_guid, + "ComponentName2" }, + { &efi_device_path_protocol_guid, + "DevicePath" }, + { &efi_driver_binding_protocol_guid, + "DriverBinding" }, + { &efi_dhcp4_protocol_guid, + "Dhcp4" }, + { &efi_dhcp4_service_binding_protocol_guid, + "Dhcp4Sb" }, + { &efi_disk_io_protocol_guid, + "DiskIo" }, + { &efi_graphics_output_protocol_guid, + "GraphicsOutput" }, + { &efi_hii_config_access_protocol_guid, + "HiiConfigAccess" }, + { &efi_ip4_protocol_guid, + "Ip4" }, + { &efi_ip4_config_protocol_guid, + "Ip4Config" }, + { &efi_ip4_service_binding_protocol_guid, + "Ip4Sb" }, + { &efi_iscsi4_dxe_guid, + "IScsi4Dxe" }, + { &efi_load_file_protocol_guid, + "LoadFile" }, + { &efi_load_file2_protocol_guid, + "LoadFile2" }, + { &efi_loaded_image_protocol_guid, + "LoadedImage" }, + { &efi_loaded_image_device_path_protocol_guid, + "LoadedImageDevicePath"}, + { &efi_managed_network_protocol_guid, + "ManagedNetwork" }, + { &efi_managed_network_service_binding_protocol_guid, + "ManagedNetworkSb" }, + { &efi_mtftp4_protocol_guid, + "Mtftp4" }, + { &efi_mtftp4_service_binding_protocol_guid, + "Mtftp4Sb" }, + { &efi_nii_protocol_guid, + "Nii" }, + { &efi_nii31_protocol_guid, + "Nii31" }, + { &efi_pci_io_protocol_guid, + "PciIo" }, + { &efi_pci_root_bridge_io_protocol_guid, + "PciRootBridgeIo" }, + { &efi_pxe_base_code_protocol_guid, + "PxeBaseCode" }, + { &efi_simple_file_system_protocol_guid, + "SimpleFileSystem" }, + { &efi_simple_network_protocol_guid, + "SimpleNetwork" }, + { &efi_tcg_protocol_guid, + "Tcg" }, + { &efi_tcp4_protocol_guid, + "Tcp4" }, + { &efi_tcp4_service_binding_protocol_guid, + "Tcp4Sb" }, + { &efi_udp4_protocol_guid, + "Udp4" }, + { &efi_udp4_service_binding_protocol_guid, + "Udp4Sb" }, + { &efi_vlan_config_protocol_guid, + "VlanConfig" }, + { &efi_vlan_config_dxe_guid, + "VlanConfigDxe" }, +}; /** * Convert GUID to a printable string @@ -50,6 +155,20 @@ const char * efi_guid_ntoa ( EFI_GUID *guid ) { union uuid uuid; EFI_GUID guid; } u; + unsigned int i; + + /* Sanity check */ + if ( ! guid ) + return NULL; + + /* Check for a match against well-known GUIDs */ + for ( i = 0 ; i < ( sizeof ( efi_well_known_guids ) / + sizeof ( efi_well_known_guids[0] ) ) ; i++ ) { + if ( memcmp ( guid, efi_well_known_guids[i].guid, + sizeof ( *guid ) ) == 0 ) { + return efi_well_known_guids[i].name; + } + } /* Convert GUID to standard endianness */ memcpy ( &u.guid, guid, sizeof ( u.guid ) ); @@ -58,18 +177,103 @@ const char * efi_guid_ntoa ( EFI_GUID *guid ) { } /** + * Name protocol open attributes + * + * @v attributes Protocol open attributes + * @ret name Protocol open attributes name + * + * Returns a (static) string with characters for each set bit + * corresponding to BY_(H)ANDLE_PROTOCOL, (G)ET_PROTOCOL, + * (T)EST_PROTOCOL, BY_(C)HILD_CONTROLLER, BY_(D)RIVER, and + * E(X)CLUSIVE. + */ +static const char * efi_open_attributes_name ( unsigned int attributes ) { + static char attribute_chars[] = "HGTCDX"; + static char name[ sizeof ( attribute_chars ) ]; + char *tmp = name; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( attribute_chars ) - 1 ) ; i++ ) { + if ( attributes & ( 1 << i ) ) + *(tmp++) = attribute_chars[i]; + } + *tmp = '\0'; + + return name; +} + +/** + * Print list of openers of a given protocol on a given handle + * + * @v handle EFI handle + * @v protocol Protocol GUID + */ +void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Sanity check */ + if ( ( ! handle ) || ( ! protocol ) ) { + printf ( "EFI could not retrieve openers for %s on %p\n", + efi_guid_ntoa ( protocol ), handle ); + return; + } + + /* Retrieve list of openers */ + if ( ( efirc = bs->OpenProtocolInformation ( handle, protocol, &openers, + &count ) ) != 0 ) { + rc = -EEFI ( efirc ); + printf ( "EFI could not retrieve openers for %s on %p: %s\n", + efi_guid_ntoa ( protocol ), handle, strerror ( rc ) ); + return; + } + + /* Dump list of openers */ + for ( i = 0 ; i < count ; i++ ) { + opener = &openers[i]; + printf ( "HANDLE %p %s %s opened %dx (%s)", + handle, efi_handle_name ( handle ), + efi_guid_ntoa ( protocol ), opener->OpenCount, + efi_open_attributes_name ( opener->Attributes ) ); + printf ( " by %p %s", opener->AgentHandle, + efi_handle_name ( opener->AgentHandle ) ); + if ( opener->ControllerHandle == handle ) { + printf ( "\n" ); + } else { + printf ( " for %p %s\n", opener->ControllerHandle, + efi_handle_name ( opener->ControllerHandle ) ); + } + } + + /* Free list */ + bs->FreePool ( openers ); +} + +/** * Print list of protocol handlers attached to a handle * * @v handle EFI handle */ void dbg_efi_protocols ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_GUID **protocols; + EFI_GUID **protocols; + EFI_GUID *protocol; UINTN count; unsigned int i; EFI_STATUS efirc; int rc; + /* Sanity check */ + if ( ! handle ) { + printf ( "EFI could not retrieve protocols for %p\n", handle ); + return; + } + /* Retrieve list of protocols */ if ( ( efirc = bs->ProtocolsPerHandle ( handle, &protocols, &count ) ) != 0 ) { @@ -80,38 +284,378 @@ void dbg_efi_protocols ( EFI_HANDLE handle ) { } /* Dump list of protocols */ - for ( i = 0 ; i < count ; i++ ) - printf ( "%s\n", efi_guid_ntoa ( protocols[i] ) ); + for ( i = 0 ; i < count ; i++ ) { + protocol = protocols[i]; + printf ( "HANDLE %p %s %s supported\n", + handle, efi_handle_name ( handle ), + efi_guid_ntoa ( protocol ) ); + dbg_efi_openers ( handle, protocol ); + } /* Free list */ bs->FreePool ( protocols ); } /** - * Print device path + * Get textual representation of device path * * @v path Device path + * @ret text Textual representation of device path, or NULL */ -void dbg_efi_devpath ( EFI_DEVICE_PATH_PROTOCOL *path ) { +const char * efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_DEVICE_PATH_PROTOCOL *end; - CHAR16 *text; + static char text[256]; + void *start; + void *end; + size_t max_len; size_t len; + CHAR16 *wtext; - /* Convert path to a textual representation */ - text = efidpt->ConvertDevicePathToText ( path, TRUE, FALSE ); - if ( ! text ) { - printf ( "<cannot convert>:\n" ); + /* Sanity checks */ + if ( ! path ) { + DBG ( "[NULL DevicePath]" ); + return NULL; + } + + /* If we have no DevicePathToText protocol then use a raw hex string */ + if ( ! efidpt ) { + DBG ( "[No DevicePathToText]" ); + start = path; end = efi_devpath_end ( path ); - len = ( ( ( void * ) end ) - ( ( void * ) path ) + - sizeof ( *end ) ); - dbg_hex_dump_da ( 0, path, len ); - return; + len = ( end - start ); + max_len = ( ( sizeof ( text ) - 1 /* NUL */ ) / 2 /* "xx" */ ); + if ( len > max_len ) + len = max_len; + base16_encode ( start, len, text ); + return text; } - /* Print path */ - printf ( "%ls", text ); + /* Convert path to a textual representation */ + wtext = efidpt->ConvertDevicePathToText ( path, TRUE, FALSE ); + if ( ! wtext ) + return NULL; + + /* Store path in buffer */ + snprintf ( text, sizeof ( text ), "%ls", wtext ); /* Free path */ - bs->FreePool ( text ); + bs->FreePool ( wtext ); + + return text; +} + +/** + * Get driver name + * + * @v wtf Component name protocol + * @ret name Driver name, or NULL + */ +static const char * efi_driver_name ( EFI_COMPONENT_NAME_PROTOCOL *wtf ) { + static char name[64]; + CHAR16 *driver_name; + EFI_STATUS efirc; + + /* Sanity check */ + if ( ! wtf ) { + DBG ( "[NULL ComponentName]" ); + return NULL; + } + + /* Try "eng" first; if that fails then try the first language */ + if ( ( ( efirc = wtf->GetDriverName ( wtf, "eng", + &driver_name ) ) != 0 ) && + ( ( efirc = wtf->GetDriverName ( wtf, wtf->SupportedLanguages, + &driver_name ) ) != 0 ) ) { + return NULL; + } + + /* Convert name from CHAR16 to char */ + snprintf ( name, sizeof ( name ), "%ls", driver_name ); + return name; +} + +/** + * Get driver name + * + * @v wtf Component name protocol + * @ret name Driver name, or NULL + */ +static const char * efi_driver_name2 ( EFI_COMPONENT_NAME2_PROTOCOL *wtf ) { + static char name[64]; + CHAR16 *driver_name; + EFI_STATUS efirc; + + /* Sanity check */ + if ( ! wtf ) { + DBG ( "[NULL ComponentName2]" ); + return NULL; + } + + /* Try "en" first; if that fails then try the first language */ + if ( ( ( efirc = wtf->GetDriverName ( wtf, "en", + &driver_name ) ) != 0 ) && + ( ( efirc = wtf->GetDriverName ( wtf, wtf->SupportedLanguages, + &driver_name ) ) != 0 ) ) { + return NULL; + } + + /* Convert name from CHAR16 to char */ + snprintf ( name, sizeof ( name ), "%ls", driver_name ); + return name; +} + +/** + * Get PE/COFF debug filename + * + * @v loaded Loaded image + * @ret name PE/COFF debug filename, or NULL + */ +static const char * +efi_pecoff_debug_name ( EFI_LOADED_IMAGE_PROTOCOL *loaded ) { + static char buf[32]; + EFI_IMAGE_DOS_HEADER *dos; + EFI_IMAGE_OPTIONAL_HEADER_UNION *pe; + EFI_IMAGE_OPTIONAL_HEADER32 *opt32; + EFI_IMAGE_OPTIONAL_HEADER64 *opt64; + EFI_IMAGE_DATA_DIRECTORY *datadir; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *debug; + EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *codeview_nb10; + EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY *codeview_rsds; + EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY *codeview_mtoc; + uint16_t dos_magic; + uint32_t pe_magic; + uint16_t opt_magic; + uint32_t codeview_magic; + size_t max_len; + char *name; + char *tmp; + + /* Sanity check */ + if ( ! loaded ) { + DBG ( "[NULL LoadedImage]" ); + return NULL; + } + + /* Parse DOS header */ + dos = loaded->ImageBase; + if ( ! dos ) { + DBG ( "[Missing DOS header]" ); + return NULL; + } + dos_magic = dos->e_magic; + if ( dos_magic != EFI_IMAGE_DOS_SIGNATURE ) { + DBG ( "[Bad DOS signature %#04x]", dos_magic ); + return NULL; + } + pe = ( loaded->ImageBase + dos->e_lfanew ); + + /* Parse PE header */ + pe_magic = pe->Pe32.Signature; + if ( pe_magic != EFI_IMAGE_NT_SIGNATURE ) { + DBG ( "[Bad PE signature %#08x]", pe_magic ); + return NULL; + } + opt32 = &pe->Pe32.OptionalHeader; + opt64 = &pe->Pe32Plus.OptionalHeader; + opt_magic = opt32->Magic; + if ( opt_magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ) { + datadir = opt32->DataDirectory; + } else if ( opt_magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC ) { + datadir = opt64->DataDirectory; + } else { + DBG ( "[Bad optional header signature %#04x]", opt_magic ); + return NULL; + } + + /* Parse data directory entry */ + if ( ! datadir[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress ) { + DBG ( "[Empty debug directory entry]" ); + return NULL; + } + debug = ( loaded->ImageBase + + datadir[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress ); + + /* Parse debug directory entry */ + if ( debug->Type != EFI_IMAGE_DEBUG_TYPE_CODEVIEW ) { + DBG ( "[Not a CodeView debug directory entry (type %d)]", + debug->Type ); + return NULL; + } + codeview_nb10 = ( loaded->ImageBase + debug->RVA ); + codeview_rsds = ( loaded->ImageBase + debug->RVA ); + codeview_mtoc = ( loaded->ImageBase + debug->RVA ); + codeview_magic = codeview_nb10->Signature; + + /* Parse CodeView entry */ + if ( codeview_magic == CODEVIEW_SIGNATURE_NB10 ) { + name = ( ( void * ) ( codeview_nb10 + 1 ) ); + } else if ( codeview_magic == CODEVIEW_SIGNATURE_RSDS ) { + name = ( ( void * ) ( codeview_rsds + 1 ) ); + } else if ( codeview_magic == CODEVIEW_SIGNATURE_MTOC ) { + name = ( ( void * ) ( codeview_mtoc + 1 ) ); + } else { + DBG ( "[Bad CodeView signature %#08x]", codeview_magic ); + return NULL; + } + + /* Sanity check - avoid scanning endlessly through memory */ + max_len = EFI_PAGE_SIZE; /* Reasonably sane */ + if ( strnlen ( name, max_len ) == max_len ) { + DBG ( "[Excessively long or invalid CodeView name]" ); + return NULL; + } + + /* Skip any directory components. We cannot modify this data + * or create a temporary buffer, so do not use basename(). + */ + while ( ( ( tmp = strchr ( name, '/' ) ) != NULL ) || + ( ( tmp = strchr ( name, '\\' ) ) != NULL ) ) { + name = ( tmp + 1 ); + } + + /* Copy base name to buffer */ + snprintf ( buf, sizeof ( buf ), "%s", name ); + + /* Strip file suffix, if present */ + if ( ( tmp = strrchr ( name, '.' ) ) != NULL ) + *tmp = '\0'; + + return name; +} + +/** + * Get initial loaded image name + * + * @v loaded Loaded image + * @ret name Initial loaded image name, or NULL + */ +static const char * +efi_first_loaded_image_name ( EFI_LOADED_IMAGE_PROTOCOL *loaded ) { + + /* Sanity check */ + if ( ! loaded ) { + DBG ( "[NULL LoadedImage]" ); + return NULL; + } + + return ( ( loaded->ParentHandle == NULL ) ? "DxeCore(?)" : NULL ); +} + +/** + * Get loaded image name from file path + * + * @v loaded Loaded image + * @ret name Loaded image name, or NULL + */ +static const char * +efi_loaded_image_filepath_name ( EFI_LOADED_IMAGE_PROTOCOL *loaded ) { + + /* Sanity check */ + if ( ! loaded ) { + DBG ( "[NULL LoadedImage]" ); + return NULL; + } + + return efi_devpath_text ( loaded->FilePath ); +} + +/** An EFI handle name type */ +struct efi_handle_name_type { + /** Protocol */ + EFI_GUID *protocol; + /** + * Get name + * + * @v interface Protocol interface + * @ret name Name of handle, or NULL on failure + */ + const char * ( * name ) ( void *interface ); +}; + +/** + * Define an EFI handle name type + * + * @v protocol Protocol interface + * @v name Method to get name + * @ret type EFI handle name type + */ +#define EFI_HANDLE_NAME_TYPE( protocol, name ) { \ + (protocol), \ + ( const char * ( * ) ( void * ) ) (name), \ + } + +/** EFI handle name types */ +static struct efi_handle_name_type efi_handle_name_types[] = { + /* Device path */ + EFI_HANDLE_NAME_TYPE ( &efi_device_path_protocol_guid, + efi_devpath_text ), + /* Driver name (for driver image handles) */ + EFI_HANDLE_NAME_TYPE ( &efi_component_name2_protocol_guid, + efi_driver_name2 ), + /* Driver name (via obsolete original ComponentName protocol) */ + EFI_HANDLE_NAME_TYPE ( &efi_component_name_protocol_guid, + efi_driver_name ), + /* PE/COFF debug filename (for image handles) */ + EFI_HANDLE_NAME_TYPE ( &efi_loaded_image_protocol_guid, + efi_pecoff_debug_name ), + /* Loaded image device path (for image handles) */ + EFI_HANDLE_NAME_TYPE ( &efi_loaded_image_device_path_protocol_guid, + efi_devpath_text ), + /* First loaded image name (for the DxeCore image) */ + EFI_HANDLE_NAME_TYPE ( &efi_loaded_image_protocol_guid, + efi_first_loaded_image_name ), + /* Handle's loaded image file path (for image handles) */ + EFI_HANDLE_NAME_TYPE ( &efi_loaded_image_protocol_guid, + efi_loaded_image_filepath_name ), +}; + +/** + * Get name of an EFI handle + * + * @v handle EFI handle + * @ret text Name of handle, or NULL + */ +const char * efi_handle_name ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_handle_name_type *type; + unsigned int i; + void *interface; + const char *name; + EFI_STATUS efirc; + + /* Fail immediately for NULL handles */ + if ( ! handle ) + return NULL; + + /* Try each name type in turn */ + for ( i = 0 ; i < ( sizeof ( efi_handle_name_types ) / + sizeof ( efi_handle_name_types[0] ) ) ; i++ ) { + type = &efi_handle_name_types[i]; + DBG2 ( "<%d", i ); + + /* Try to open the applicable protocol */ + efirc = bs->OpenProtocol ( handle, type->protocol, &interface, + efi_image_handle, handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ); + if ( efirc != 0 ) { + DBG2 ( ">" ); + continue; + } + + /* Try to get name from this protocol */ + DBG2 ( "-" ); + name = type->name ( interface ); + DBG2 ( "%c", ( name ? ( name[0] ? 'Y' : 'E' ) : 'N' ) ); + + /* Close protocol */ + bs->CloseProtocol ( handle, type->protocol, + efi_image_handle, handle ); + DBG2 ( ">" ); + + /* Use this name, if possible */ + if ( name && name[0] ) + return name; + } + + return "UNKNOWN"; } diff --git a/roms/ipxe/src/interface/efi/efi_download.c b/roms/ipxe/src/interface/efi/efi_download.c index 80279f7f9..1218852e2 100644 --- a/roms/ipxe/src/interface/efi/efi_download.c +++ b/roms/ipxe/src/interface/efi/efi_download.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/iobuf.h> #include <ipxe/xfer.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_snp.h> #include <ipxe/efi/efi_download.h> /** iPXE download protocol GUID */ @@ -63,6 +64,8 @@ static void efi_download_close ( struct efi_download_file *file, int rc ) { file->finish_callback ( file->context, EFIRC ( rc ) ); intf_shutdown ( &file->xfer, rc ); + + efi_snp_release(); } /** @@ -147,6 +150,7 @@ efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused, return EFIRC ( rc ); } + efi_snp_claim(); file->pos = 0; file->data_callback = DataCallback; file->finish_callback = FinishCallback; @@ -201,13 +205,13 @@ static IPXE_DOWNLOAD_PROTOCOL ipxe_download_protocol_interface = { * @v handle EFI handle * @ret rc Return status code */ -int efi_download_install ( EFI_HANDLE *handle ) { +int efi_download_install ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_STATUS efirc; int rc; efirc = bs->InstallMultipleProtocolInterfaces ( - handle, + &handle, &ipxe_download_protocol_guid, &ipxe_download_protocol_interface, NULL ); diff --git a/roms/ipxe/src/interface/efi/efi_driver.c b/roms/ipxe/src/interface/efi/efi_driver.c index 1bc28e7c3..ba7784cd7 100644 --- a/roms/ipxe/src/interface/efi/efi_driver.c +++ b/roms/ipxe/src/interface/efi/efi_driver.c @@ -20,15 +20,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> +#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> +#include <ipxe/version.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/DriverBinding.h> #include <ipxe/efi/Protocol/ComponentName2.h> +#include <ipxe/efi/Protocol/DevicePath.h> #include <ipxe/efi/efi_strings.h> #include <ipxe/efi/efi_driver.h> -#include <config/general.h> /** @file * @@ -36,33 +38,215 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** EFI driver binding protocol GUID */ -static EFI_GUID efi_driver_binding_protocol_guid - = EFI_DRIVER_BINDING_PROTOCOL_GUID; +static EFI_DRIVER_BINDING_PROTOCOL efi_driver_binding; -/** EFI component name protocol GUID */ -static EFI_GUID efi_component_name2_protocol_guid - = EFI_COMPONENT_NAME2_PROTOCOL_GUID; +/** List of controlled EFI devices */ +static LIST_HEAD ( efi_devices ); /** - * Find end of device path + * Find EFI device * - * @v path Path to device - * @ret path_end End of device path + * @v device EFI device handle + * @ret efidev EFI device, or NULL if not found */ -EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { +static struct efi_device * efidev_find ( EFI_HANDLE device ) { + struct efi_device *efidev; - while ( path->Type != END_DEVICE_PATH_TYPE ) { - path = ( ( ( void * ) path ) + - /* There's this amazing new-fangled thing known as - * a UINT16, but who wants to use one of those? */ - ( ( path->Length[1] << 8 ) | path->Length[0] ) ); + /* Look for an existing EFI device */ + list_for_each_entry ( efidev, &efi_devices, dev.siblings ) { + if ( efidev->device == device ) + return efidev; } - return path; + return NULL; } /** + * Get parent EFI device + * + * @v dev Generic device + * @ret efidev Parent EFI device, or NULL + */ +struct efi_device * efidev_parent ( struct device *dev ) { + struct device *parent = dev->parent; + struct efi_device *efidev; + + /* Check that parent exists and is an EFI device */ + if ( ! parent ) + return NULL; + if ( parent->desc.bus_type != BUS_TYPE_EFI ) + return NULL; + + /* Get containing EFI device */ + efidev = container_of ( parent, struct efi_device, dev ); + return efidev; +} + +/** + * Check to see if driver supports a device + * + * @v driver EFI driver + * @v device EFI device + * @v child Path to child device, if any + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, + EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) { + struct efi_driver *efidrv; + int rc; + + DBGCP ( device, "EFIDRV %p %s DRIVER_SUPPORTED", + device, efi_handle_name ( device ) ); + if ( child ) + DBGCP ( device, " (child %s)", efi_devpath_text ( child ) ); + DBGCP ( device, "\n" ); + + /* Do nothing if we are already driving this device */ + if ( efidev_find ( device ) != NULL ) { + DBGCP ( device, "EFIDRV %p %s is already started\n", + device, efi_handle_name ( device ) ); + return EFI_ALREADY_STARTED; + } + + /* Look for a driver claiming to support this device */ + for_each_table_entry ( efidrv, EFI_DRIVERS ) { + if ( ( rc = efidrv->supported ( device ) ) == 0 ) { + DBGC ( device, "EFIDRV %p %s has driver \"%s\"\n", + device, efi_handle_name ( device ), + efidrv->name ); + return 0; + } + } + DBGCP ( device, "EFIDRV %p %s has no driver\n", + device, efi_handle_name ( device ) ); + + return EFI_UNSUPPORTED; +} + +/** + * Attach driver to device + * + * @v driver EFI driver + * @v device EFI device + * @v child Path to child device, if any + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, + EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) { + struct efi_driver *efidrv; + struct efi_device *efidev; + EFI_STATUS efirc; + int rc; + + DBGC ( device, "EFIDRV %p %s DRIVER_START", + device, efi_handle_name ( device ) ); + if ( child ) + DBGC ( device, " (child %s)", efi_devpath_text ( child ) ); + DBGC ( device, "\n" ); + + /* Do nothing if we are already driving this device */ + efidev = efidev_find ( device ); + if ( efidev ) { + DBGCP ( device, "EFIDRV %p %s is already started\n", + device, efi_handle_name ( device ) ); + efirc = EFI_ALREADY_STARTED; + goto err_already_started; + } + + /* Allocate and initialise structure */ + efidev = zalloc ( sizeof ( *efidev ) ); + if ( ! efidev ) { + efirc = EFI_OUT_OF_RESOURCES; + goto err_alloc; + } + efidev->device = device; + efidev->dev.desc.bus_type = BUS_TYPE_EFI; + INIT_LIST_HEAD ( &efidev->dev.children ); + list_add ( &efidev->dev.siblings, &efi_devices ); + + /* Try to start this device */ + for_each_table_entry ( efidrv, EFI_DRIVERS ) { + if ( ( rc = efidrv->supported ( device ) ) != 0 ) { + DBGC ( device, "EFIDRV %p %s is not supported by " + "driver \"%s\": %s\n", device, + efi_handle_name ( device ), efidrv->name, + strerror ( rc ) ); + continue; + } + if ( ( rc = efidrv->start ( efidev ) ) == 0 ) { + efidev->driver = efidrv; + DBGC ( device, "EFIDRV %p %s using driver \"%s\"\n", + device, efi_handle_name ( device ), + efidev->driver->name ); + return 0; + } + DBGC ( device, "EFIDRV %p %s could not start driver \"%s\": " + "%s\n", device, efi_handle_name ( device ), + efidrv->name, strerror ( rc ) ); + } + efirc = EFI_UNSUPPORTED; + + list_del ( &efidev->dev.siblings ); + free ( efidev ); + err_alloc: + err_already_started: + return efirc; +} + +/** + * Detach driver from device + * + * @v driver EFI driver + * @v device EFI device + * @v pci PCI device + * @v num_children Number of child devices + * @v children List of child devices + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, + EFI_HANDLE device, UINTN num_children, + EFI_HANDLE *children ) { + struct efi_driver *efidrv; + struct efi_device *efidev; + UINTN i; + + DBGC ( device, "EFIDRV %p %s DRIVER_STOP", + device, efi_handle_name ( device ) ); + for ( i = 0 ; i < num_children ; i++ ) { + DBGC ( device, "%s%p %s", ( i ? ", " : " child " ), + children[i], efi_handle_name ( children[i] ) ); + } + DBGC ( device, "\n" ); + + /* Do nothing unless we are driving this device */ + efidev = efidev_find ( device ); + if ( ! efidev ) { + DBGCP ( device, "EFIDRV %p %s is not started\n", + device, efi_handle_name ( device ) ); + return 0; + } + + /* Stop this device */ + efidrv = efidev->driver; + assert ( efidrv != NULL ); + efidrv->stop ( efidev ); + list_del ( &efidev->dev.siblings ); + free ( efidev ); + + return 0; +} + +/** EFI driver binding protocol */ +static EFI_DRIVER_BINDING_PROTOCOL efi_driver_binding = { + .Supported = efi_driver_supported, + .Start = efi_driver_start, + .Stop = efi_driver_stop, +}; + +/** * Look up driver name * * @v wtf Component name protocol @@ -71,12 +255,12 @@ EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { * @ret efirc EFI status code */ static EFI_STATUS EFIAPI -efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf, - CHAR8 *language __unused, CHAR16 **driver_name ) { - struct efi_driver *efidrv = - container_of ( wtf, struct efi_driver, wtf ); +efi_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, + CHAR8 *language __unused, CHAR16 **driver_name ) { + const wchar_t *name; - *driver_name = efidrv->wname; + name = ( product_wname[0] ? product_wname : build_wname ); + *driver_name = ( ( wchar_t * ) name ); return 0; } @@ -91,9 +275,9 @@ efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf, * @ret efirc EFI status code */ static EFI_STATUS EFIAPI -efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, - EFI_HANDLE device, EFI_HANDLE child, - CHAR8 *language, CHAR16 **controller_name ) { +efi_driver_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, + EFI_HANDLE device, EFI_HANDLE child, + CHAR8 *language, CHAR16 **controller_name ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_COMPONENT_NAME2_PROTOCOL *name2; @@ -118,43 +302,155 @@ efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, return EFI_UNSUPPORTED; } +/** EFI component name protocol */ +static EFI_COMPONENT_NAME2_PROTOCOL efi_wtf = { + .GetDriverName = efi_driver_name, + .GetControllerName = efi_driver_controller_name, + .SupportedLanguages = "en", +}; + +/** + * Install EFI driver + * + * @ret rc Return status code + */ +int efi_driver_install ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + int rc; + + /* Calculate driver version number. We use the build + * timestamp (in seconds since the Epoch) shifted right by six + * bits: this gives us an approximately one-minute resolution + * and a scheme which will last until the year 10680. + */ + efi_driver_binding.Version = ( build_timestamp >> 6 ); + + /* Install protocols on image handle */ + efi_driver_binding.ImageHandle = efi_image_handle; + efi_driver_binding.DriverBindingHandle = efi_image_handle; + if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( + &efi_image_handle, + &efi_driver_binding_protocol_guid, &efi_driver_binding, + &efi_component_name2_protocol_guid, &efi_wtf, + NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efi_driver_binding, "EFIDRV could not install " + "protocols: %s\n", strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Uninstall EFI driver + * + */ +void efi_driver_uninstall ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Uninstall protocols */ + bs->UninstallMultipleProtocolInterfaces ( + efi_image_handle, + &efi_driver_binding_protocol_guid, &efi_driver_binding, + &efi_component_name2_protocol_guid, &efi_wtf, NULL ); +} + /** * Try to connect EFI driver * - * @v efidrv EFI driver - * @v handle Controller handle + * @v device EFI device + * @ret rc Return status code */ -static void efi_driver_connect ( struct efi_driver *efidrv, EFI_HANDLE handle ){ +static int efi_driver_connect ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE drivers[2] = { efidrv->driver.DriverBindingHandle, NULL }; + EFI_HANDLE drivers[2] = + { efi_driver_binding.DriverBindingHandle, NULL }; + EFI_STATUS efirc; + int rc; + + /* Check if we want to drive this device */ + if ( ( efirc = efi_driver_supported ( &efi_driver_binding, device, + NULL ) ) != 0 ) { + /* Not supported; not an error */ + return 0; + } - bs->ConnectController ( handle, drivers, NULL, FALSE ); + /* Disconnect any existing drivers */ + DBGC2 ( device, "EFIDRV %p %s before disconnecting:\n", + device, efi_handle_name ( device ) ); + DBGC2_EFI_PROTOCOLS ( device, device ); + DBGC ( device, "EFIDRV %p %s disconnecting existing drivers\n", + device, efi_handle_name ( device ) ); + if ( ( efirc = bs->DisconnectController ( device, NULL, + NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFIDRV %p %s could not disconnect existing " + "drivers: %s\n", device, efi_handle_name ( device ), + strerror ( rc ) ); + /* Ignore the error and attempt to connect our drivers */ + } + DBGC2 ( device, "EFIDRV %p %s after disconnecting:\n", + device, efi_handle_name ( device ) ); + DBGC2_EFI_PROTOCOLS ( device, device ); + + /* Connect our driver */ + DBGC ( device, "EFIDRV %p %s connecting new drivers\n", + device, efi_handle_name ( device ) ); + if ( ( efirc = bs->ConnectController ( device, drivers, NULL, + FALSE ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFIDRV %p %s could not connect new drivers: " + "%s\n", device, efi_handle_name ( device ), + strerror ( rc ) ); + return rc; + } + DBGC2 ( device, "EFIDRV %p %s after connecting:\n", + device, efi_handle_name ( device ) ); + DBGC2_EFI_PROTOCOLS ( device, device ); + + return 0; } /** * Try to disconnect EFI driver * - * @v efidrv EFI driver - * @v handle Controller handle + * @v device EFI device + * @ret rc Return status code */ -static void efi_driver_disconnect ( struct efi_driver *efidrv, - EFI_HANDLE handle ) { +static int efi_driver_disconnect ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - bs->DisconnectController ( handle, efidrv->driver.DriverBindingHandle, + /* Disconnect our driver */ + bs->DisconnectController ( device, + efi_driver_binding.DriverBindingHandle, NULL ); + return 0; +} + +/** + * Reconnect original EFI driver + * + * @v device EFI device + * @ret rc Return status code + */ +static int efi_driver_reconnect ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Reconnect any available driver */ + bs->ConnectController ( device, NULL, NULL, FALSE ); + + return 0; } /** * Connect/disconnect EFI driver from all handles * - * @v efidrv EFI driver * @v method Connect/disconnect method * @ret rc Return status code */ -static int efi_driver_handles ( struct efi_driver *efidrv, - void ( * method ) ( struct efi_driver *efidrv, - EFI_HANDLE handle ) ) { +static int efi_driver_handles ( int ( * method ) ( EFI_HANDLE handle ) ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE *handles; UINTN num_handles; @@ -167,87 +463,55 @@ static int efi_driver_handles ( struct efi_driver *efidrv, &num_handles, &handles ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIDRV %s could not list handles: %s\n", - efidrv->name, strerror ( rc ) ); - return rc; + DBGC ( &efi_driver_binding, "EFIDRV could not list handles: " + "%s\n", strerror ( rc ) ); + goto err_locate; } /* Connect/disconnect driver from all handles */ - for ( i = 0 ; i < num_handles ; i++ ) - method ( efidrv, handles[i] ); + for ( i = 0 ; i < num_handles ; i++ ) { + if ( ( rc = method ( handles[i] ) ) != 0 ) + goto err_method; + } - /* Free list of handles */ - bs->FreePool ( handles ); + /* Success */ + rc = 0; - return 0; + err_method: + bs->FreePool ( handles ); + err_locate: + return rc; } /** - * Install EFI driver + * Connect EFI driver to all possible devices * - * @v efidrv EFI driver * @ret rc Return status code */ -int efi_driver_install ( struct efi_driver *efidrv ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_DRIVER_BINDING_PROTOCOL *driver = &efidrv->driver; - EFI_COMPONENT_NAME2_PROTOCOL *wtf = &efidrv->wtf; - EFI_STATUS efirc; - int rc; +int efi_driver_connect_all ( void ) { - /* Configure driver binding protocol */ - driver->ImageHandle = efi_image_handle; - - /* Configure component name protocol */ - wtf->GetDriverName = efi_driver_get_driver_name; - wtf->GetControllerName = efi_driver_get_controller_name; - wtf->SupportedLanguages = "en"; - - /* Fill in driver name */ - efi_snprintf ( efidrv->wname, - ( sizeof ( efidrv->wname ) / - sizeof ( efidrv->wname[0] ) ), - PRODUCT_SHORT_NAME "%s%s", - ( efidrv->name ? " - " : "" ), - ( efidrv->name ? efidrv->name : "" ) ); - - /* Install driver */ - if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( - &driver->DriverBindingHandle, - &efi_driver_binding_protocol_guid, driver, - &efi_component_name2_protocol_guid, wtf, - NULL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( efidrv, "EFIDRV %s could not install protocol: %s\n", - efidrv->name, strerror ( rc ) ); - return rc; - } + DBGC ( &efi_driver_binding, "EFIDRV connecting our drivers\n" ); + return efi_driver_handles ( efi_driver_connect ); +} - /* Connect devices */ - DBGC ( efidrv, "EFIDRV %s connecting devices\n", efidrv->name ); - efi_driver_handles ( efidrv, efi_driver_connect ); +/** + * Disconnect EFI driver from all possible devices + * + * @ret rc Return status code + */ +void efi_driver_disconnect_all ( void ) { - DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name ); - return 0; + DBGC ( &efi_driver_binding, "EFIDRV disconnecting our drivers\n" ); + efi_driver_handles ( efi_driver_disconnect ); } /** - * Uninstall EFI driver + * Reconnect original EFI drivers to all possible devices * - * @v efidrv EFI driver + * @ret rc Return status code */ -void efi_driver_uninstall ( struct efi_driver *efidrv ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; +void efi_driver_reconnect_all ( void ) { - /* Disconnect the driver from its devices */ - DBGC ( efidrv, "EFIDRV %s disconnecting devices\n", efidrv->name ); - efi_driver_handles ( efidrv, efi_driver_disconnect ); - - /* Uninstall the driver */ - bs->UninstallMultipleProtocolInterfaces ( - efidrv->driver.DriverBindingHandle, - &efi_driver_binding_protocol_guid, &efidrv->driver, - &efi_component_name2_protocol_guid, &efidrv->wtf, - NULL ); - DBGC ( efidrv, "EFIDRV %s uninstalled\n", efidrv->name ); + DBGC ( &efi_driver_binding, "EFIDRV reconnecting old drivers\n" ); + efi_driver_handles ( efi_driver_reconnect ); } diff --git a/roms/ipxe/src/interface/efi/efi_file.c b/roms/ipxe/src/interface/efi/efi_file.c index 4c482d2e5..2ef3c5734 100644 --- a/roms/ipxe/src/interface/efi/efi_file.c +++ b/roms/ipxe/src/interface/efi/efi_file.c @@ -30,31 +30,25 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <strings.h> #include <errno.h> #include <wchar.h> #include <ipxe/image.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/SimpleFileSystem.h> #include <ipxe/efi/Protocol/BlockIo.h> +#include <ipxe/efi/Protocol/DiskIo.h> #include <ipxe/efi/Guid/FileInfo.h> #include <ipxe/efi/Guid/FileSystemInfo.h> #include <ipxe/efi/efi_strings.h> #include <ipxe/efi/efi_file.h> -/** EFI simple file system protocol GUID */ -static EFI_GUID efi_simple_file_system_protocol_guid - = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; - /** EFI file information GUID */ static EFI_GUID efi_file_info_id = EFI_FILE_INFO_ID; /** EFI file system information GUID */ static EFI_GUID efi_file_system_info_id = EFI_FILE_SYSTEM_INFO_ID; -/** EFI block I/O protocol GUID */ -static EFI_GUID efi_block_io_protocol_guid - = EFI_BLOCK_IO_PROTOCOL_GUID; - /** EFI media ID */ #define EFI_MEDIA_ID_MAGIC 0x69505845 @@ -82,6 +76,27 @@ static const char * efi_file_name ( struct efi_file *file ) { } /** + * Find EFI file image + * + * @v wname Filename + * @ret image Image, or NULL + */ +static struct image * efi_file_find ( const CHAR16 *wname ) { + char name[ wcslen ( wname ) + 1 /* NUL */ ]; + struct image *image; + + /* Find image */ + snprintf ( name, sizeof ( name ), "%ls", wname ); + list_for_each_entry ( image, &images, list ) { + if ( strcasecmp ( image->name, name ) == 0 ) + return image; + } + + return NULL; + +} + +/** * Open file * * @v this EFI file @@ -96,7 +111,6 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, CHAR16 *wname, UINT64 mode __unused, UINT64 attributes __unused ) { struct efi_file *file = container_of ( this, struct efi_file, file ); - char name[ wcslen ( wname ) + 1 /* NUL */ ]; struct efi_file *new_file; struct image *image; @@ -120,10 +134,9 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, } /* Identify image */ - snprintf ( name, sizeof ( name ), "%ls", wname ); - image = find_image ( name ); + image = efi_file_find ( wname ); if ( ! image ) { - DBGC ( file, "EFIFILE \"%s\" does not exist\n", name ); + DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname ); return EFI_NOT_FOUND; } @@ -484,6 +497,7 @@ static EFI_STATUS EFIAPI efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused, EFI_FILE_PROTOCOL **file ) { + DBGC ( &efi_file_root, "EFIFILE open volume\n" ); *file = &efi_file_root.file; return 0; } @@ -496,38 +510,49 @@ static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = { /** Dummy block I/O reset */ static EFI_STATUS EFIAPI -efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused, - BOOLEAN extended __unused ) { +efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused, BOOLEAN extended ) { + + DBGC ( &efi_file_root, "EFIFILE block %sreset\n", + ( extended ? "extended " : "" ) ); return 0; } /** Dummy block I/O read */ static EFI_STATUS EFIAPI -efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, - UINT32 MediaId __unused, EFI_LBA lba __unused, - UINTN len __unused, VOID *data __unused ) { - return EFI_DEVICE_ERROR; +efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, UINT32 MediaId, + EFI_LBA lba, UINTN len, VOID *data ) { + + DBGC ( &efi_file_root, "EFIFILE block read ID %#08x LBA %#08llx -> " + "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ), + data, ( ( size_t ) len ) ); + return EFI_NO_MEDIA; } /** Dummy block I/O write */ static EFI_STATUS EFIAPI efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, - UINT32 MediaId __unused, EFI_LBA lba __unused, - UINTN len __unused, VOID *data __unused ) { - return EFI_DEVICE_ERROR; + UINT32 MediaId, EFI_LBA lba, UINTN len, + VOID *data ) { + + DBGC ( &efi_file_root, "EFIFILE block write ID %#08x LBA %#08llx <- " + "%p+%zx\n", MediaId, ( ( unsigned long long ) lba ), + data, ( ( size_t ) len ) ); + return EFI_NO_MEDIA; } /** Dummy block I/O flush */ static EFI_STATUS EFIAPI efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) { + + DBGC ( &efi_file_root, "EFIFILE block flush\n" ); return 0; } /** Dummy block I/O media */ static EFI_BLOCK_IO_MEDIA efi_block_io_media = { .MediaId = EFI_MEDIA_ID_MAGIC, - .MediaPresent = 1, - .ReadOnly = 1, + .MediaPresent = TRUE, + .ReadOnly = TRUE, .BlockSize = 1, }; @@ -541,37 +566,117 @@ static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = { .FlushBlocks = efi_block_io_flush_blocks, }; +/** Dummy disk I/O read */ +static EFI_STATUS EFIAPI +efi_disk_io_read_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId, + UINT64 offset, UINTN len, VOID *data ) { + + DBGC ( &efi_file_root, "EFIFILE disk read ID %#08x offset %#08llx -> " + "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ), + data, ( ( size_t ) len ) ); + return EFI_NO_MEDIA; +} + +/** Dummy disk I/O write */ +static EFI_STATUS EFIAPI +efi_disk_io_write_disk ( EFI_DISK_IO_PROTOCOL *this __unused, UINT32 MediaId, + UINT64 offset, UINTN len, VOID *data ) { + + DBGC ( &efi_file_root, "EFIFILE disk write ID %#08x offset %#08llx <- " + "%p+%zx\n", MediaId, ( ( unsigned long long ) offset ), + data, ( ( size_t ) len ) ); + return EFI_NO_MEDIA; +} + +/** Dummy EFI disk I/O protocol */ +static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = { + .Revision = EFI_DISK_IO_PROTOCOL_REVISION, + .ReadDisk = efi_disk_io_read_disk, + .WriteDisk = efi_disk_io_write_disk, +}; + /** * Install EFI simple file system protocol * * @v handle EFI handle * @ret rc Return status code */ -int efi_file_install ( EFI_HANDLE *handle ) { +int efi_file_install ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_DISK_IO_PROTOCOL *diskio; + void *interface; + } diskio; EFI_STATUS efirc; int rc; - /* Install the simple file system protocol and the block I/O - * protocol. We don't have a block device, but large parts of - * the EDK2 codebase make the assumption that file systems are - * normally attached to block devices, and so we create a - * dummy block device on the same handle just to keep things - * looking normal. + /* Install the simple file system protocol, block I/O + * protocol, and disk I/O protocol. We don't have a block + * device, but large parts of the EDK2 codebase make the + * assumption that file systems are normally attached to block + * devices, and so we create a dummy block device on the same + * handle just to keep things looking normal. */ if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( - handle, + &handle, &efi_block_io_protocol_guid, &efi_block_io_protocol, + &efi_disk_io_protocol_guid, + &efi_disk_io_protocol, &efi_simple_file_system_protocol_guid, &efi_simple_file_system_protocol, NULL ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( handle, "Could not install simple file system protocol: " - "%s\n", strerror ( rc ) ); - return rc; + DBGC ( handle, "Could not install simple file system " + "protocols: %s\n", strerror ( rc ) ); + goto err_install; } + /* The FAT filesystem driver has a bug: if a block device + * contains no FAT filesystem but does have an + * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL instance, the FAT driver + * will assume that it must have previously installed the + * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. This causes the FAT + * driver to claim control of our device, and to refuse to + * stop driving it, which prevents us from later uninstalling + * correctly. + * + * Work around this bug by opening the disk I/O protocol + * ourselves, thereby preventing the FAT driver from opening + * it. + * + * Note that the alternative approach of opening the block I/O + * protocol (and thereby in theory preventing DiskIo from + * attaching to the block I/O protocol) causes an endless loop + * of calls to our DRIVER_STOP method when starting the EFI + * shell. I have no idea why this is. + */ + if ( ( efirc = bs->OpenProtocol ( handle, &efi_disk_io_protocol_guid, + &diskio.interface, efi_image_handle, + handle, + EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){ + rc = -EEFI ( efirc ); + DBGC ( handle, "Could not open disk I/O protocol: %s\n", + strerror ( rc ) ); + DBGC_EFI_OPENERS ( handle, handle, &efi_disk_io_protocol_guid ); + goto err_open; + } + assert ( diskio.diskio == &efi_disk_io_protocol ); + return 0; + + bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid, + efi_image_handle, handle ); + err_open: + bs->UninstallMultipleProtocolInterfaces ( + handle, + &efi_simple_file_system_protocol_guid, + &efi_simple_file_system_protocol, + &efi_disk_io_protocol_guid, + &efi_disk_io_protocol, + &efi_block_io_protocol_guid, + &efi_block_io_protocol, NULL ); + err_install: + return rc; } /** @@ -581,16 +686,29 @@ int efi_file_install ( EFI_HANDLE *handle ) { */ void efi_file_uninstall ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + int rc; + + /* Close our own disk I/O protocol */ + bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid, + efi_image_handle, handle ); /* We must install the file system protocol first, since * otherwise the EDK2 code will attempt to helpfully uninstall * it when the block I/O protocol is uninstalled, leading to a * system lock-up. */ - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( handle, &efi_simple_file_system_protocol_guid, &efi_simple_file_system_protocol, + &efi_disk_io_protocol_guid, + &efi_disk_io_protocol, &efi_block_io_protocol_guid, - &efi_block_io_protocol, NULL ); + &efi_block_io_protocol, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( handle, "Could not uninstall simple file system " + "protocols: %s\n", strerror ( rc ) ); + /* Oh dear */ + } } diff --git a/roms/ipxe/src/interface/efi/efi_guid.c b/roms/ipxe/src/interface/efi/efi_guid.c new file mode 100644 index 000000000..52ba58ae4 --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_guid.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2014 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/efi/efi.h> +#include <ipxe/efi/Protocol/Arp.h> +#include <ipxe/efi/Protocol/BlockIo.h> +#include <ipxe/efi/Protocol/BusSpecificDriverOverride.h> +#include <ipxe/efi/Protocol/ComponentName.h> +#include <ipxe/efi/Protocol/ComponentName2.h> +#include <ipxe/efi/Protocol/DevicePath.h> +#include <ipxe/efi/Protocol/DevicePathToText.h> +#include <ipxe/efi/Protocol/Dhcp4.h> +#include <ipxe/efi/Protocol/DiskIo.h> +#include <ipxe/efi/Protocol/DriverBinding.h> +#include <ipxe/efi/Protocol/GraphicsOutput.h> +#include <ipxe/efi/Protocol/HiiConfigAccess.h> +#include <ipxe/efi/Protocol/Ip4.h> +#include <ipxe/efi/Protocol/Ip4Config.h> +#include <ipxe/efi/Protocol/LoadFile.h> +#include <ipxe/efi/Protocol/LoadFile2.h> +#include <ipxe/efi/Protocol/LoadedImage.h> +#include <ipxe/efi/Protocol/ManagedNetwork.h> +#include <ipxe/efi/Protocol/Mtftp4.h> +#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> +#include <ipxe/efi/Protocol/PciIo.h> +#include <ipxe/efi/Protocol/PciRootBridgeIo.h> +#include <ipxe/efi/Protocol/PxeBaseCode.h> +#include <ipxe/efi/Protocol/SimpleFileSystem.h> +#include <ipxe/efi/Protocol/SimpleNetwork.h> +#include <ipxe/efi/Protocol/TcgService.h> +#include <ipxe/efi/Protocol/Tcp4.h> +#include <ipxe/efi/Protocol/Udp4.h> +#include <ipxe/efi/Protocol/VlanConfig.h> + +/** @file + * + * EFI GUIDs + * + */ + +/** ARP protocol GUID */ +EFI_GUID efi_arp_protocol_guid + = EFI_ARP_PROTOCOL_GUID; + +/** ARP service binding protocol GUID */ +EFI_GUID efi_arp_service_binding_protocol_guid + = EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID; + +/** Block I/O protocol GUID */ +EFI_GUID efi_block_io_protocol_guid + = EFI_BLOCK_IO_PROTOCOL_GUID; + +/** Bus specific driver override protocol GUID */ +EFI_GUID efi_bus_specific_driver_override_protocol_guid + = EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID; + +/** Component name protocol GUID */ +EFI_GUID efi_component_name_protocol_guid + = EFI_COMPONENT_NAME_PROTOCOL_GUID; + +/** Component name 2 protocol GUID */ +EFI_GUID efi_component_name2_protocol_guid + = EFI_COMPONENT_NAME2_PROTOCOL_GUID; + +/** Device path protocol GUID */ +EFI_GUID efi_device_path_protocol_guid + = EFI_DEVICE_PATH_PROTOCOL_GUID; + +/** DHCPv4 protocol GUID */ +EFI_GUID efi_dhcp4_protocol_guid + = EFI_DHCP4_PROTOCOL_GUID; + +/** DHCPv4 service binding protocol GUID */ +EFI_GUID efi_dhcp4_service_binding_protocol_guid + = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; + +/** Disk I/O protocol GUID */ +EFI_GUID efi_disk_io_protocol_guid + = EFI_DISK_IO_PROTOCOL_GUID; + +/** Driver binding protocol GUID */ +EFI_GUID efi_driver_binding_protocol_guid + = EFI_DRIVER_BINDING_PROTOCOL_GUID; + +/** Graphics output protocol GUID */ +EFI_GUID efi_graphics_output_protocol_guid + = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + +/** HII configuration access protocol GUID */ +EFI_GUID efi_hii_config_access_protocol_guid + = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID; + +/** IPv4 protocol GUID */ +EFI_GUID efi_ip4_protocol_guid + = EFI_IP4_PROTOCOL_GUID; + +/** IPv4 configuration protocol GUID */ +EFI_GUID efi_ip4_config_protocol_guid + = EFI_IP4_CONFIG_PROTOCOL_GUID; + +/** IPv4 service binding protocol GUID */ +EFI_GUID efi_ip4_service_binding_protocol_guid + = EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID; + +/** Load file protocol GUID */ +EFI_GUID efi_load_file_protocol_guid + = EFI_LOAD_FILE_PROTOCOL_GUID; + +/** Load file 2 protocol GUID */ +EFI_GUID efi_load_file2_protocol_guid + = EFI_LOAD_FILE2_PROTOCOL_GUID; + +/** Loaded image protocol GUID */ +EFI_GUID efi_loaded_image_protocol_guid + = EFI_LOADED_IMAGE_PROTOCOL_GUID; + +/** Loaded image device path protocol GUID */ +EFI_GUID efi_loaded_image_device_path_protocol_guid + = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; + +/** Managed network protocol GUID */ +EFI_GUID efi_managed_network_protocol_guid + = EFI_MANAGED_NETWORK_PROTOCOL_GUID; + +/** Managed network service binding protocol GUID */ +EFI_GUID efi_managed_network_service_binding_protocol_guid + = EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID; + +/** MTFTPv4 protocol GUID */ +EFI_GUID efi_mtftp4_protocol_guid + = EFI_MTFTP4_PROTOCOL_GUID; + +/** MTFTPv4 service binding protocol GUID */ +EFI_GUID efi_mtftp4_service_binding_protocol_guid + = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID; + +/** Network interface identifier protocol GUID (old version) */ +EFI_GUID efi_nii_protocol_guid + = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID; + +/** Network interface identifier protocol GUID (new version) */ +EFI_GUID efi_nii31_protocol_guid + = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID_31; + +/** PCI I/O protocol GUID */ +EFI_GUID efi_pci_io_protocol_guid + = EFI_PCI_IO_PROTOCOL_GUID; + +/** PCI root bridge I/O protocol GUID */ +EFI_GUID efi_pci_root_bridge_io_protocol_guid + = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID; + +/** PXE base code protocol GUID */ +EFI_GUID efi_pxe_base_code_protocol_guid + = EFI_PXE_BASE_CODE_PROTOCOL_GUID; + +/** Simple file system protocol GUID */ +EFI_GUID efi_simple_file_system_protocol_guid + = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; + +/** Simple network protocol GUID */ +EFI_GUID efi_simple_network_protocol_guid + = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; + +/** TCG protocol GUID */ +EFI_GUID efi_tcg_protocol_guid + = EFI_TCG_PROTOCOL_GUID; + +/** TCPv4 protocol GUID */ +EFI_GUID efi_tcp4_protocol_guid + = EFI_TCP4_PROTOCOL_GUID; + +/** TCPv4 service binding protocol GUID */ +EFI_GUID efi_tcp4_service_binding_protocol_guid + = EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID; + +/** UDPv4 protocol GUID */ +EFI_GUID efi_udp4_protocol_guid + = EFI_UDP4_PROTOCOL_GUID; + +/** UDPv4 service binding protocol GUID */ +EFI_GUID efi_udp4_service_binding_protocol_guid + = EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID; + +/** VLAN configuration protocol GUID */ +EFI_GUID efi_vlan_config_protocol_guid + = EFI_VLAN_CONFIG_PROTOCOL_GUID; diff --git a/roms/ipxe/src/interface/efi/efi_init.c b/roms/ipxe/src/interface/efi/efi_init.c index b4ed5c147..93ada21d4 100644 --- a/roms/ipxe/src/interface/efi/efi_init.c +++ b/roms/ipxe/src/interface/efi/efi_init.c @@ -21,12 +21,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <string.h> #include <errno.h> +#include <ipxe/init.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_driver.h> #include <ipxe/efi/Protocol/LoadedImage.h> -#include <ipxe/efi/Protocol/DevicePath.h> -#include <ipxe/uuid.h> -#include <ipxe/init.h> /** Image handle passed to entry point */ EFI_HANDLE efi_image_handle; @@ -34,20 +32,9 @@ EFI_HANDLE efi_image_handle; /** Loaded image protocol for this image */ EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image; -/** Loaded image protocol device path for this image */ -EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; - /** System table passed to entry point */ EFI_SYSTEM_TABLE *efi_systab; -/** EFI loaded image protocol GUID */ -static EFI_GUID efi_loaded_image_protocol_guid - = EFI_LOADED_IMAGE_PROTOCOL_GUID; - -/** EFI loaded image device path protocol GUID */ -static EFI_GUID efi_loaded_image_device_path_protocol_guid - = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; - /** Event used to signal shutdown */ static EFI_EVENT efi_shutdown_event; @@ -55,61 +42,6 @@ static EFI_EVENT efi_shutdown_event; static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle ); /** - * Check to see if driver supports a device - * - * @v driver EFI driver - * @v device EFI device - * @v child Path to child device, if any - * @ret efirc EFI status code - */ -static EFI_STATUS EFIAPI -efi_image_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, - EFI_HANDLE device __unused, - EFI_DEVICE_PATH_PROTOCOL *child __unused ) { - - return EFI_UNSUPPORTED; -} - -/** - * Attach driver to device - * - * @v driver EFI driver - * @v device EFI device - * @v child Path to child device, if any - * @ret efirc EFI status code - */ -static EFI_STATUS EFIAPI -efi_image_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, - EFI_HANDLE device __unused, - EFI_DEVICE_PATH_PROTOCOL *child __unused ) { - - return EFI_UNSUPPORTED; -} - -/** - * Detach driver from device - * - * @v driver EFI driver - * @v device EFI device - * @v pci PCI device - * @v num_children Number of child devices - * @v children List of child devices - * @ret efirc EFI status code - */ -static EFI_STATUS EFIAPI -efi_image_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, - EFI_HANDLE device __unused, UINTN num_children __unused, - EFI_HANDLE *children __unused ) { - - return EFI_UNSUPPORTED; -} - -/** EFI loaded image driver */ -static struct efi_driver efi_image_driver = - EFI_DRIVER_INIT ( NULL, efi_image_supported, efi_image_start, - efi_image_stop ); - -/** * Shut down in preparation for booting an OS. * * This hook gets called at ExitBootServices time in order to make @@ -152,7 +84,6 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, struct efi_protocol *prot; struct efi_config_table *tab; void *loaded_image; - void *loaded_image_path; EFI_STATUS efirc; int rc; @@ -161,18 +92,24 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, efi_systab = systab; /* Sanity checks */ - if ( ! systab ) - return EFI_NOT_AVAILABLE_YET; - if ( ! systab->ConOut ) - return EFI_NOT_AVAILABLE_YET; + if ( ! systab ) { + efirc = EFI_NOT_AVAILABLE_YET; + goto err_sanity; + } + if ( ! systab->ConOut ) { + efirc = EFI_NOT_AVAILABLE_YET; + goto err_sanity; + } if ( ! systab->BootServices ) { DBGC ( systab, "EFI provided no BootServices entry point\n" ); - return EFI_NOT_AVAILABLE_YET; + efirc = EFI_NOT_AVAILABLE_YET; + goto err_sanity; } if ( ! systab->RuntimeServices ) { DBGC ( systab, "EFI provided no RuntimeServices entry " "point\n" ); - return EFI_NOT_AVAILABLE_YET; + efirc = EFI_NOT_AVAILABLE_YET; + goto err_sanity; } DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab ); bs = systab->BootServices; @@ -187,8 +124,9 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, } else { DBGC ( systab, "EFI does not provide protocol %s\n", efi_guid_ntoa ( &prot->guid ) ); - /* All protocols are required */ - return efirc; + /* Fail if protocol is required */ + if ( prot->required ) + goto err_missing_protocol; } } @@ -200,8 +138,10 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, } else { DBGC ( systab, "EFI does not provide configuration " "table %s\n", efi_guid_ntoa ( &tab->guid ) ); - if ( tab->required ) - return EFI_NOT_AVAILABLE_YET; + if ( tab->required ) { + efirc = EFI_NOT_AVAILABLE_YET; + goto err_missing_table; + } } } @@ -213,27 +153,12 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, rc = -EEFI ( efirc ); DBGC ( systab, "EFI could not get loaded image protocol: %s", strerror ( rc ) ); - return efirc; + goto err_no_loaded_image; } efi_loaded_image = loaded_image; DBGC ( systab, "EFI image base address %p\n", efi_loaded_image->ImageBase ); - /* Get loaded image device path protocol */ - if ( ( efirc = bs->OpenProtocol ( image_handle, - &efi_loaded_image_device_path_protocol_guid, - &loaded_image_path, image_handle, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( systab, "EFI could not get loaded image device path " - "protocol: %s", strerror ( rc ) ); - return efirc; - } - efi_loaded_image_path = loaded_image_path; - DBGC ( systab, "EFI image device path " ); - DBGC_EFI_DEVPATH ( systab, efi_loaded_image_path ); - DBGC ( systab, "\n" ); - /* EFI is perfectly capable of gracefully shutting down any * loaded devices if it decides to fall back to a legacy boot. * For no particularly comprehensible reason, it doesn't @@ -245,23 +170,31 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, rc = -EEFI ( efirc ); DBGC ( systab, "EFI could not create ExitBootServices event: " "%s\n", strerror ( rc ) ); - return efirc; + goto err_create_event; } - /* Install an EFI driver on the image handle, to allow the - * driver to be subsequently unloaded. - */ - efi_image_driver.driver.DriverBindingHandle = image_handle; - if ( ( rc = efi_driver_install ( &efi_image_driver ) ) != 0 ) { - DBGC ( systab, "EFI could not install loaded image driver: " - "%s\n", strerror ( rc ) ); - return EFIRC ( rc ); + /* Install driver binding protocol */ + if ( ( rc = efi_driver_install() ) != 0 ) { + DBGC ( systab, "EFI could not install driver: %s\n", + strerror ( rc ) ); + efirc = EFIRC ( rc ); + goto err_driver_install; } /* Install image unload method */ efi_loaded_image->Unload = efi_unload; return 0; + + efi_driver_uninstall(); + err_driver_install: + bs->CloseEvent ( efi_shutdown_event ); + err_create_event: + err_no_loaded_image: + err_missing_table: + err_missing_protocol: + err_sanity: + return efirc; } /** @@ -278,12 +211,15 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) { /* Shut down */ shutdown_exit(); + /* Disconnect any remaining devices */ + efi_driver_disconnect_all(); + + /* Uninstall driver binding protocol */ + efi_driver_uninstall(); + /* Uninstall exit boot services event */ bs->CloseEvent ( efi_shutdown_event ); - /* Uninstall loaded image driver */ - efi_driver_uninstall ( &efi_image_driver ); - DBGC ( systab, "EFI image unloaded\n" ); return 0; diff --git a/roms/ipxe/src/interface/efi/efi_pci.c b/roms/ipxe/src/interface/efi/efi_pci.c index dc7304a35..86c781d82 100644 --- a/roms/ipxe/src/interface/efi/efi_pci.c +++ b/roms/ipxe/src/interface/efi/efi_pci.c @@ -22,7 +22,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <errno.h> #include <ipxe/pci.h> -#include <ipxe/init.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_pci.h> #include <ipxe/efi/efi_driver.h> @@ -35,6 +34,22 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Disambiguate the various error causes */ +#define EINFO_EEFI_PCI \ + __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ + "Could not open PCI I/O protocol" ) +#define EINFO_EEFI_PCI_NOT_PCI \ + __einfo_platformify ( EINFO_EEFI_PCI, EFI_UNSUPPORTED, \ + "Not a PCI device" ) +#define EEFI_PCI_NOT_PCI __einfo_error ( EINFO_EEFI_PCI_NOT_PCI ) +#define EINFO_EEFI_PCI_IN_USE \ + __einfo_platformify ( EINFO_EEFI_PCI, EFI_ACCESS_DENIED, \ + "PCI device already has a driver" ) +#define EEFI_PCI_IN_USE __einfo_error ( EINFO_EEFI_PCI_IN_USE ) +#define EEFI_PCI( efirc ) \ + EPLATFORM ( EINFO_EEFI_PCI, efirc, \ + EEFI_PCI_NOT_PCI, EEFI_PCI_IN_USE ) + /****************************************************************************** * * iPXE PCI API @@ -44,7 +59,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** PCI root bridge I/O protocol */ static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci; -EFI_REQUIRE_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci ); +EFI_REQUEST_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci ); static unsigned long efipci_address ( struct pci_device *pci, unsigned long location ) { @@ -59,6 +74,9 @@ int efipci_read ( struct pci_device *pci, unsigned long location, EFI_STATUS efirc; int rc; + if ( ! efipci ) + return -ENOTSUP; + if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ), efipci_address ( pci, location ), 1, value ) ) != 0 ) { @@ -77,6 +95,9 @@ int efipci_write ( struct pci_device *pci, unsigned long location, EFI_STATUS efirc; int rc; + if ( ! efipci ) + return -ENOTSUP; + if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ), efipci_address ( pci, location ), 1, &value ) ) != 0 ) { @@ -105,241 +126,115 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); ****************************************************************************** */ -/** EFI PCI I/O protocol GUID */ -static EFI_GUID efi_pci_io_protocol_guid - = EFI_PCI_IO_PROTOCOL_GUID; - -/** EFI device path protocol GUID */ -static EFI_GUID efi_device_path_protocol_guid - = EFI_DEVICE_PATH_PROTOCOL_GUID; - -/** EFI PCI devices */ -static LIST_HEAD ( efi_pci_devices ); - /** - * Create EFI PCI device + * Open EFI PCI device * - * @v efidrv EFI driver - * @v device EFI device - * @ret efipci EFI PCI device, or NULL + * @v device EFI device handle + * @v attributes Protocol opening attributes + * @v pci PCI device to fill in + * @ret rc Return status code */ -struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, - EFI_HANDLE device ) { +int efipci_open ( EFI_HANDLE device, UINT32 attributes, + struct pci_device *pci ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_pci_device *efipci; union { EFI_PCI_IO_PROTOCOL *pci_io; void *interface; } pci_io; - union { - EFI_DEVICE_PATH_PROTOCOL *path; - void *interface; - } path; UINTN pci_segment, pci_bus, pci_dev, pci_fn; EFI_STATUS efirc; int rc; - /* Allocate PCI device */ - efipci = zalloc ( sizeof ( *efipci ) ); - if ( ! efipci ) - goto err_zalloc; - efipci->device = device; - efipci->efidrv = efidrv; - /* See if device is a PCI device */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_pci_io_protocol_guid, - &pci_io.interface, - efidrv->driver.DriverBindingHandle, - device, - EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ - rc = -EEFI ( efirc ); - DBGCP ( efipci, "EFIPCI device %p is not a PCI device\n", - device ); + if ( ( efirc = bs->OpenProtocol ( device, &efi_pci_io_protocol_guid, + &pci_io.interface, efi_image_handle, + device, attributes ) ) != 0 ) { + rc = -EEFI_PCI ( efirc ); + DBGCP ( device, "EFIPCI %p %s cannot open PCI protocols: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); goto err_open_protocol; } - efipci->pci_io = pci_io.pci_io; /* Get PCI bus:dev.fn address */ - if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, - &pci_segment, + if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment, &pci_bus, &pci_dev, &pci_fn ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( efipci, "EFIPCI device %p could not get PCI " - "location: %s\n", device, strerror ( rc ) ); + DBGC ( device, "EFIPCI %p %s could not get PCI location: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); goto err_get_location; } - DBGC2 ( efipci, "EFIPCI device %p is PCI %04lx:%02lx:%02lx.%lx\n", - device, ( ( unsigned long ) pci_segment ), + DBGC2 ( device, "EFIPCI %p %s is PCI %04lx:%02lx:%02lx.%lx\n", device, + efi_handle_name ( device ), ( ( unsigned long ) pci_segment ), ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ), ( ( unsigned long ) pci_fn ) ); - /* Populate PCI device */ - pci_init ( &efipci->pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) ); - if ( ( rc = pci_read_config ( &efipci->pci ) ) != 0 ) { - DBGC ( efipci, "EFIPCI " PCI_FMT " cannot read PCI " - "configuration: %s\n", - PCI_ARGS ( &efipci->pci ), strerror ( rc ) ); - goto err_pci_read_config; - } - - /* Retrieve device path */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_device_path_protocol_guid, - &path.interface, - efidrv->driver.DriverBindingHandle, - device, - EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ - rc = -EEFI ( efirc ); - DBGC ( efipci, "EFIPCI " PCI_FMT " has no device path\n", - PCI_ARGS ( &efipci->pci ) ); - goto err_no_device_path; - } - efipci->path = path.path; - - /* Add to list of PCI devices */ - list_add ( &efipci->list, &efi_pci_devices ); - - return efipci; - - bs->CloseProtocol ( device, &efi_device_path_protocol_guid, - efidrv->driver.DriverBindingHandle, device ); - err_no_device_path: - err_pci_read_config: - err_get_location: - bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, - efidrv->driver.DriverBindingHandle, device ); - err_open_protocol: - free ( efipci ); - err_zalloc: - return NULL; -} - -/** - * Enable EFI PCI device - * - * @v efipci EFI PCI device - * @ret rc Return status code - */ -int efipci_enable ( struct efi_pci_device *efipci ) { - EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io; - /* Try to enable I/O cycles, memory cycles, and bus mastering. * Some platforms will 'helpfully' report errors if these bits * can't be enabled (for example, if the card doesn't actually * support I/O cycles). Work around any such platforms by * enabling bits individually and simply ignoring any errors. */ - pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable, - EFI_PCI_IO_ATTRIBUTE_IO, NULL ); - pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable, - EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL ); - pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable, - EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL ); - - return 0; -} + pci_io.pci_io->Attributes ( pci_io.pci_io, + EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_IO, NULL ); + pci_io.pci_io->Attributes ( pci_io.pci_io, + EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL ); + pci_io.pci_io->Attributes ( pci_io.pci_io, + EfiPciIoAttributeOperationEnable, + EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL ); -/** - * Find EFI PCI device by EFI device - * - * @v device EFI device - * @ret efipci EFI PCI device, or NULL - */ -struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ) { - struct efi_pci_device *efipci; - - list_for_each_entry ( efipci, &efi_pci_devices, list ) { - if ( efipci->device == device ) - return efipci; + /* Populate PCI device */ + pci_init ( pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) ); + if ( ( rc = pci_read_config ( pci ) ) != 0 ) { + DBGC ( device, "EFIPCI %p %s cannot read PCI configuration: " + "%s\n", device, efi_handle_name ( device ), + strerror ( rc ) ); + goto err_pci_read_config; } - return NULL; -} -/** - * Find EFI PCI device by iPXE device - * - * @v dev Device - * @ret efipci EFI PCI device, or NULL - */ -struct efi_pci_device * efipci_find ( struct device *dev ) { - struct efi_pci_device *efipci; + return 0; - list_for_each_entry ( efipci, &efi_pci_devices, list ) { - if ( &efipci->pci.dev == dev ) - return efipci; - } - return NULL; + err_pci_read_config: + err_get_location: + bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, + efi_image_handle, device ); + err_open_protocol: + return rc; } /** - * Add EFI device as child of EFI PCI device + * Close EFI PCI device * - * @v efipci EFI PCI device - * @v device EFI child device - * @ret efirc EFI status code + * @v device EFI device handle */ -int efipci_child_add ( struct efi_pci_device *efipci, EFI_HANDLE device ) { +void efipci_close ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_driver *efidrv = efipci->efidrv; - union { - EFI_PCI_IO_PROTOCOL *pci_io; - void *interface; - } pci_io; - EFI_STATUS efirc; - int rc; - - /* Re-open the PCI_IO_PROTOCOL */ - if ( ( efirc = bs->OpenProtocol ( efipci->device, - &efi_pci_io_protocol_guid, - &pci_io.interface, - efidrv->driver.DriverBindingHandle, - device, - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER - ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n", - PCI_ARGS ( &efipci->pci ), strerror ( rc ) ); - return rc; - } - return 0; + bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, + efi_image_handle, device ); } /** - * Remove EFI device as child of PCI device + * Get EFI PCI device information * - * @v efipci EFI PCI device - * @v device EFI child device - * @ret efirc EFI status code + * @v device EFI device handle + * @v pci PCI device to fill in + * @ret rc Return status code */ -void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_driver *efidrv = efipci->efidrv; +int efipci_info ( EFI_HANDLE device, struct pci_device *pci ) { + int rc; - bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid, - efidrv->driver.DriverBindingHandle, device ); -} + /* Open PCI device, if possible */ + if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL, + pci ) ) != 0 ) + return rc; -/** - * Destroy EFI PCI device - * - * @v efidrv EFI driver - * @v efipci EFI PCI device - */ -void efipci_destroy ( struct efi_driver *efidrv, - struct efi_pci_device *efipci ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + /* Close PCI device */ + efipci_close ( device ); - list_del ( &efipci->list ); - bs->CloseProtocol ( efipci->device, &efi_device_path_protocol_guid, - efidrv->driver.DriverBindingHandle, - efipci->device ); - bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid, - efidrv->driver.DriverBindingHandle, - efipci->device ); - free ( efipci ); + return 0; } /****************************************************************************** @@ -352,187 +247,111 @@ void efipci_destroy ( struct efi_driver *efidrv, /** * Check to see if driver supports a device * - * @v driver EFI driver - * @v device EFI device - * @v child Path to child device, if any - * @ret efirc EFI status code + * @v device EFI device handle + * @ret rc Return status code */ -static EFI_STATUS EFIAPI -efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, - EFI_DEVICE_PATH_PROTOCOL *child ) { - struct efi_driver *efidrv = - container_of ( driver, struct efi_driver, driver ); - struct efi_pci_device *efipci; +static int efipci_supported ( EFI_HANDLE device ) { + struct pci_device pci; int rc; - DBGCP ( efidrv, "EFIPCI DRIVER_SUPPORTED %p (%p)\n", device, child ); - - /* Create temporary corresponding PCI device, if any */ - efipci = efipci_create ( efidrv, device ); - if ( ! efipci ) { - /* Non-PCI devices are simply unsupported */ - rc = -ENOTSUP; - goto err_not_pci; - } + /* Get PCI device information */ + if ( ( rc = efipci_info ( device, &pci ) ) != 0 ) + return rc; /* Look for a driver */ - if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { - DBGCP ( efipci, "EFIPCI " PCI_FMT " has no driver\n", - PCI_ARGS ( &efipci->pci ) ); - goto err_no_driver; + if ( ( rc = pci_find_driver ( &pci ) ) != 0 ) { + DBGCP ( device, "EFIPCI %p %s has no driver\n", + device, efi_handle_name ( device ) ); + return rc; } - - DBGC ( efipci, "EFIPCI " PCI_FMT " is supported by driver \"%s\"\n", - PCI_ARGS ( &efipci->pci ), efipci->pci.id->name ); - - /* Destroy temporary PCI device */ - efipci_destroy ( efidrv, efipci ); + DBGC ( device, "EFIPCI %p %s has driver \"%s\"\n", + device, efi_handle_name ( device ), pci.id->name ); return 0; - - err_no_driver: - efipci_destroy ( efidrv, efipci ); - err_not_pci: - return EFIRC ( rc ); } /** * Attach driver to device * - * @v driver EFI driver - * @v device EFI device - * @v child Path to child device, if any - * @ret efirc EFI status code + * @v efidev EFI device + * @ret rc Return status code */ -static EFI_STATUS EFIAPI -efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, - EFI_DEVICE_PATH_PROTOCOL *child ) { - struct efi_driver *efidrv = - container_of ( driver, struct efi_driver, driver ); - struct efi_pci_device *efipci; +static int efipci_start ( struct efi_device *efidev ) { + EFI_HANDLE device = efidev->device; + struct pci_device *pci; int rc; - DBGC ( efidrv, "EFIPCI DRIVER_START %p (%p)\n", device, child ); - - /* Create corresponding PCI device */ - efipci = efipci_create ( efidrv, device ); - if ( ! efipci ) { + /* Allocate PCI device */ + pci = zalloc ( sizeof ( *pci ) ); + if ( ! pci ) { rc = -ENOMEM; - goto err_create; + goto err_alloc; + } + + /* Open PCI device */ + if ( ( rc = efipci_open ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER | + EFI_OPEN_PROTOCOL_EXCLUSIVE ), + pci ) ) != 0 ) { + DBGC ( device, "EFIPCI %p %s could not open PCI device: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); + DBGC_EFI_OPENERS ( device, device, &efi_pci_io_protocol_guid ); + goto err_open; } /* Find driver */ - if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { - DBGC ( efipci, "EFIPCI " PCI_FMT " has no driver\n", - PCI_ARGS ( &efipci->pci ) ); + if ( ( rc = pci_find_driver ( pci ) ) != 0 ) { + DBGC ( device, "EFIPCI %p %s has no driver\n", + device, efi_handle_name ( device ) ); goto err_find_driver; } - /* Enable PCI device */ - if ( ( rc = efipci_enable ( efipci ) ) != 0 ) - goto err_enable; + /* Mark PCI device as a child of the EFI device */ + pci->dev.parent = &efidev->dev; + list_add ( &pci->dev.siblings, &efidev->dev.children ); /* Probe driver */ - if ( ( rc = pci_probe ( &efipci->pci ) ) != 0 ) { - DBGC ( efipci, "EFIPCI " PCI_FMT " could not probe driver " - "\"%s\": %s\n", PCI_ARGS ( &efipci->pci ), - efipci->pci.id->name, strerror ( rc ) ); + if ( ( rc = pci_probe ( pci ) ) != 0 ) { + DBGC ( device, "EFIPCI %p %s could not probe driver \"%s\": " + "%s\n", device, efi_handle_name ( device ), + pci->id->name, strerror ( rc ) ); goto err_probe; } + DBGC ( device, "EFIPCI %p %s using driver \"%s\"\n", + device, efi_handle_name ( device ), pci->id->name ); + efidev_set_drvdata ( efidev, pci ); return 0; - pci_remove ( &efipci->pci ); + pci_remove ( pci ); err_probe: - err_enable: + list_del ( &pci->dev.siblings ); err_find_driver: - efipci_destroy ( efidrv, efipci ); - err_create: - return EFIRC ( rc ); + efipci_close ( device ); + err_open: + free ( pci ); + err_alloc: + return rc; } /** * Detach driver from device * - * @v driver EFI driver - * @v device EFI device - * @v pci PCI device - * @v num_children Number of child devices - * @v children List of child devices - * @ret efirc EFI status code - */ -static EFI_STATUS EFIAPI -efipci_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, - UINTN num_children, EFI_HANDLE *children ) { - struct efi_driver *efidrv = - container_of ( driver, struct efi_driver, driver ); - struct efi_pci_device *efipci; - - DBGC ( efidrv, "EFIPCI DRIVER_STOP %p (%ld %p)\n", - device, ( ( unsigned long ) num_children ), children ); - - /* Find PCI device */ - efipci = efipci_find_efi ( device ); - if ( ! efipci ) { - DBGC ( efidrv, "EFIPCI device %p not started!\n", device ); - return EFI_INVALID_PARAMETER; - } - - /* Remove device */ - pci_remove ( &efipci->pci ); - - /* Delete EFI PCI device */ - efipci_destroy ( efidrv, efipci ); - - return 0; + * @v efidev EFI device + */ +static void efipci_stop ( struct efi_device *efidev ) { + struct pci_device *pci = efidev_get_drvdata ( efidev ); + EFI_HANDLE device = efidev->device; + + pci_remove ( pci ); + list_del ( &pci->dev.siblings ); + efipci_close ( device ); + free ( pci ); } /** EFI PCI driver */ -static struct efi_driver efipci_driver = - EFI_DRIVER_INIT ( "PCI", efipci_supported, efipci_start, efipci_stop ); - -/** - * Install EFI PCI driver - * - */ -static void efipci_driver_startup ( void ) { - struct efi_driver *efidrv = &efipci_driver; - int rc; - - /* Install driver */ - if ( ( rc = efi_driver_install ( efidrv ) ) != 0 ) { - DBGC ( efidrv, "EFIPCI could not install driver: %s\n", - strerror ( rc ) ); - return; - } - - DBGC ( efidrv, "EFIPCI driver installed\n" ); -} - -/** - * Shut down EFI PCI driver - * - * @v booting System is shutting down for OS boot - */ -static void efipci_driver_shutdown ( int booting __unused ) { - struct efi_driver *efidrv = &efipci_driver; - struct efi_pci_device *efipci; - struct efi_pci_device *tmp; - - /* Uninstall driver */ - efi_driver_uninstall ( efidrv ); - - /* Shut down any remaining devices */ - list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) { - DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; " - "forcing close\n", PCI_ARGS ( &efipci->pci ) ); - pci_remove ( &efipci->pci ); - efipci_destroy ( efidrv, efipci ); - } -} - -/** EFI PCI startup function */ -struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = { - .startup = efipci_driver_startup, - .shutdown = efipci_driver_shutdown, +struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_NORMAL ) = { + .name = "PCI", + .supported = efipci_supported, + .start = efipci_start, + .stop = efipci_stop, }; diff --git a/roms/ipxe/src/interface/efi/efi_snp.c b/roms/ipxe/src/interface/efi/efi_snp.c index 9c541552b..67fba342e 100644 --- a/roms/ipxe/src/interface/efi/efi_snp.c +++ b/roms/ipxe/src/interface/efi/efi_snp.c @@ -27,48 +27,20 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/netdevice.h> #include <ipxe/iobuf.h> #include <ipxe/in.h> -#include <ipxe/pci.h> +#include <ipxe/version.h> #include <ipxe/efi/efi.h> -#include <ipxe/efi/efi_pci.h> #include <ipxe/efi/efi_driver.h> #include <ipxe/efi/efi_strings.h> +#include <ipxe/efi/efi_utils.h> #include <ipxe/efi/efi_snp.h> -#include <config/general.h> #include <usr/autoboot.h> -/** EFI simple network protocol GUID */ -static EFI_GUID efi_simple_network_protocol_guid - = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; - -/** EFI device path protocol GUID */ -static EFI_GUID efi_device_path_protocol_guid - = EFI_DEVICE_PATH_PROTOCOL_GUID; - -/** EFI network interface identifier GUID */ -static EFI_GUID efi_nii_protocol_guid - = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID; - -/** EFI network interface identifier GUID (extra special version) */ -static EFI_GUID efi_nii31_protocol_guid = { - /* At some point, it seems that someone decided to change the - * GUID. Current EFI builds ignore the older GUID, older EFI - * builds ignore the newer GUID, so we have to expose both. - */ - 0x1ACED566, 0x76ED, 0x4218, - { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } -}; - -/** EFI component name protocol GUID */ -static EFI_GUID efi_component_name2_protocol_guid - = EFI_COMPONENT_NAME2_PROTOCOL_GUID; - -/** EFI load file protocol GUID */ -static EFI_GUID efi_load_file_protocol_guid - = EFI_LOAD_FILE_PROTOCOL_GUID; - /** List of SNP devices */ static LIST_HEAD ( efi_snp_devices ); +/** Network devices are currently claimed for use by iPXE */ +static int efi_snp_claimed; + /** * Set EFI SNP mode state * @@ -85,7 +57,7 @@ static void efi_snp_set_state ( struct efi_snp_device *snpdev ) { } else if ( ! netdev_is_open ( netdev ) ) { /* Network device not opened; report as Started */ mode->State = EfiSimpleNetworkStarted; - } else if ( ! netdev_rx_frozen ( netdev ) ) { + } else if ( efi_snp_claimed ) { /* Network device opened but claimed for use by iPXE; report * as Started to inhibit receive polling. */ @@ -164,7 +136,7 @@ efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; snpdev->started = 1; @@ -186,7 +158,7 @@ efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; snpdev->started = 0; @@ -214,7 +186,7 @@ efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, ( ( unsigned long ) extra_tx_bufsize ) ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { @@ -244,7 +216,7 @@ efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { snpdev, ( ext_verify ? "with" : "without" ) ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; netdev_close ( snpdev->netdev ); @@ -274,7 +246,7 @@ efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; netdev_close ( snpdev->netdev ); @@ -311,7 +283,7 @@ efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable, } /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Lie through our teeth, otherwise MNP refuses to accept us */ @@ -337,7 +309,7 @@ efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, ( reset ? "reset" : ll_protocol->ntoa ( new ) ) ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Set the MAC address */ @@ -348,7 +320,7 @@ efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, /* MAC address changes take effect only on netdev_open() */ if ( netdev_is_open ( snpdev->netdev ) ) { DBGC ( snpdev, "SNPDEV %p MAC address changed while net " - "devive open\n", snpdev ); + "device open\n", snpdev ); } return 0; @@ -374,7 +346,7 @@ efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, ( reset ? " reset" : "" ) ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Gather statistics */ @@ -426,7 +398,7 @@ efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6, DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Try to hash the address */ @@ -463,7 +435,7 @@ efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read, DBGC2_HDA ( snpdev, offset, data, len ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; return EFI_UNSUPPORTED; @@ -486,7 +458,7 @@ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Poll the network device */ @@ -585,7 +557,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, DBGC2 ( snpdev, "\n" ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Sanity checks */ @@ -697,7 +669,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, ( ( unsigned long ) *len ) ); /* Fail if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return EFI_NOT_READY; /* Poll the network device */ @@ -761,7 +733,7 @@ static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event, return; /* Do nothing if net device is currently claimed for use by iPXE */ - if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + if ( efi_snp_claimed ) return; /* Poll the network device */ @@ -922,36 +894,34 @@ static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) { */ static int efi_snp_probe ( struct net_device *netdev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_pci_device *efipci; + struct efi_device *efidev; struct efi_snp_device *snpdev; + union { + EFI_DEVICE_PATH_PROTOCOL *path; + void *interface; + } path; EFI_DEVICE_PATH_PROTOCOL *path_end; MAC_ADDR_DEVICE_PATH *macpath; size_t path_prefix_len = 0; EFI_STATUS efirc; int rc; - /* Find EFI PCI device */ - efipci = efipci_find ( netdev->dev ); - if ( ! efipci ) { - DBG ( "SNP skipping non-PCI device %s\n", netdev->name ); + /* Find parent EFI device */ + efidev = efidev_parent ( netdev->dev ); + if ( ! efidev ) { + DBG ( "SNP skipping non-EFI device %s\n", netdev->name ); rc = 0; - goto err_no_pci; + goto err_no_efidev; } - /* Calculate device path prefix length */ - path_end = efi_devpath_end ( efipci->path ); - path_prefix_len = ( ( ( void * ) path_end ) - - ( ( void * ) efipci->path ) ); - /* Allocate the SNP device */ - snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len + - sizeof ( *macpath ) ); + snpdev = zalloc ( sizeof ( *snpdev ) ); if ( ! snpdev ) { rc = -ENOMEM; goto err_alloc_snp; } snpdev->netdev = netdev_get ( netdev ); - snpdev->efipci = efipci; + snpdev->efidev = efidev; /* Sanity check */ if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) { @@ -988,12 +958,13 @@ static int efi_snp_probe ( struct net_device *netdev ) { efi_snprintf ( snpdev->driver_name, ( sizeof ( snpdev->driver_name ) / sizeof ( snpdev->driver_name[0] ) ), - PRODUCT_SHORT_NAME " %s", netdev->dev->driver_name ); + "%s %s", product_short_name, netdev->dev->driver_name ); efi_snprintf ( snpdev->controller_name, ( sizeof ( snpdev->controller_name ) / sizeof ( snpdev->controller_name[0] ) ), - PRODUCT_SHORT_NAME " %s (%s)", - netdev->name, netdev_addr ( netdev ) ); + "%s %s (%s, %s)", product_short_name, + netdev->dev->driver_name, netdev->dev->name, + netdev_addr ( netdev ) ); snpdev->name2.GetDriverName = efi_snp_get_driver_name; snpdev->name2.GetControllerName = efi_snp_get_controller_name; snpdev->name2.SupportedLanguages = "en"; @@ -1007,9 +978,32 @@ static int efi_snp_probe ( struct net_device *netdev ) { sizeof ( snpdev->name[0] ) ), "%s", netdev->name ); + /* Get the parent device path */ + if ( ( efirc = bs->OpenProtocol ( efidev->device, + &efi_device_path_protocol_guid, + &path.interface, efi_image_handle, + efidev->device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( snpdev, "SNPDEV %p cannot get %p %s device path: %s\n", + snpdev, efidev->device, + efi_handle_name ( efidev->device ), strerror ( rc ) ); + goto err_open_device_path; + } + + /* Allocate the new device path */ + path_end = efi_devpath_end ( path.path ); + path_prefix_len = ( ( ( void * ) path_end ) - ( ( void * ) path.path )); + snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) + + sizeof ( *path_end ) ); + if ( ! snpdev->path ) { + rc = -ENOMEM; + goto err_alloc_device_path; + } + /* Populate the device path */ - memcpy ( &snpdev->path, efipci->path, path_prefix_len ); - macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len ); + memcpy ( snpdev->path, path.path, path_prefix_len ); + macpath = ( ( ( void * ) snpdev->path ) + path_prefix_len ); path_end = ( ( void * ) ( macpath + 1 ) ); memset ( macpath, 0, sizeof ( *macpath ) ); macpath->Header.Type = MESSAGING_DEVICE_PATH; @@ -1027,7 +1021,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( &snpdev->handle, &efi_simple_network_protocol_guid, &snpdev->snp, - &efi_device_path_protocol_guid, &snpdev->path, + &efi_device_path_protocol_guid, snpdev->path, &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, @@ -1039,49 +1033,62 @@ static int efi_snp_probe ( struct net_device *netdev ) { goto err_install_protocol_interface; } - /* Add as child of PCI device */ - if ( ( rc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) { - DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT - ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ), - strerror ( rc ) ); - goto err_efipci_child_add; + /* Add as child of EFI parent device */ + if ( ( rc = efi_child_add ( efidev->device, snpdev->handle ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not become child of %p %s: " + "%s\n", snpdev, efidev->device, + efi_handle_name ( efidev->device ), strerror ( rc ) ); + goto err_efi_child_add; } /* Install HII */ if ( ( rc = efi_snp_hii_install ( snpdev ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not install HII: %s\n", snpdev, strerror ( rc ) ); - goto err_hii_install; + /* HII fails on several platforms. It's + * non-essential, so treat this as a non-fatal + * error. + */ } /* Add to list of SNP devices */ list_add ( &snpdev->list, &efi_snp_devices ); - DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n", - snpdev, netdev->name, snpdev->handle ); + /* Close device path */ + bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid, + efi_image_handle, efidev->device ); + + DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n", + snpdev, netdev->name, snpdev->handle, + efi_handle_name ( snpdev->handle ) ); return 0; - efi_snp_hii_uninstall ( snpdev ); - err_hii_install: - efipci_child_del ( efipci, snpdev->handle ); - err_efipci_child_add: + if ( snpdev->package_list ) + efi_snp_hii_uninstall ( snpdev ); + efi_child_del ( efidev->device, snpdev->handle ); + err_efi_child_add: bs->UninstallMultipleProtocolInterfaces ( snpdev->handle, &efi_simple_network_protocol_guid, &snpdev->snp, - &efi_device_path_protocol_guid, &snpdev->path, + &efi_device_path_protocol_guid, snpdev->path, &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, &efi_load_file_protocol_guid, &snpdev->load_file, NULL ); err_install_protocol_interface: + free ( snpdev->path ); + err_alloc_device_path: + bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid, + efi_image_handle, efidev->device ); + err_open_device_path: bs->CloseEvent ( snpdev->snp.WaitForPacket ); err_create_event: err_ll_addr_len: netdev_put ( netdev ); free ( snpdev ); err_alloc_snp: - err_no_pci: + err_no_efidev: return rc; } @@ -1127,18 +1134,20 @@ static void efi_snp_remove ( struct net_device *netdev ) { } /* Uninstall the SNP */ - efi_snp_hii_uninstall ( snpdev ); - efipci_child_del ( snpdev->efipci, snpdev->handle ); + if ( snpdev->package_list ) + efi_snp_hii_uninstall ( snpdev ); + efi_child_del ( snpdev->efidev->device, snpdev->handle ); list_del ( &snpdev->list ); bs->UninstallMultipleProtocolInterfaces ( snpdev->handle, &efi_simple_network_protocol_guid, &snpdev->snp, - &efi_device_path_protocol_guid, &snpdev->path, + &efi_device_path_protocol_guid, snpdev->path, &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, &efi_load_file_protocol_guid, &snpdev->load_file, NULL ); + free ( snpdev->path ); bs->CloseEvent ( snpdev->snp.WaitForPacket ); netdev_put ( snpdev->netdev ); free ( snpdev ); @@ -1153,6 +1162,22 @@ struct net_driver efi_snp_driver __net_driver = { }; /** + * Find SNP device by EFI device handle + * + * @v handle EFI device handle + * @ret snpdev SNP device, or NULL + */ +struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ) { + struct efi_snp_device *snpdev; + + list_for_each_entry ( snpdev, &efi_snp_devices, list ) { + if ( snpdev->handle == handle ) + return snpdev; + } + return NULL; +} + +/** * Get most recently opened SNP device * * @ret snpdev Most recently opened SNP device, or NULL @@ -1168,23 +1193,17 @@ struct efi_snp_device * last_opened_snpdev ( void ) { } /** - * Claim network devices for use by iPXE + * Set SNP claimed/released state * + * @v claimed Network devices are claimed for use by iPXE */ -void efi_snp_claim ( void ) { - struct net_device *netdev; - - for_each_netdev ( netdev ) - netdev_rx_unfreeze ( netdev ); -} +void efi_snp_set_claimed ( int claimed ) { + struct efi_snp_device *snpdev; -/** - * Release network devices for use via SNP - * - */ -void efi_snp_release ( void ) { - struct net_device *netdev; + /* Claim SNP devices */ + efi_snp_claimed = claimed; - for_each_netdev ( netdev ) - netdev_rx_freeze ( netdev ); + /* Update SNP mode state for each interface */ + list_for_each_entry ( snpdev, &efi_snp_devices, list ) + efi_snp_set_state ( snpdev ); } diff --git a/roms/ipxe/src/interface/efi/efi_snp_hii.c b/roms/ipxe/src/interface/efi/efi_snp_hii.c index c272527c0..c49c76a32 100644 --- a/roms/ipxe/src/interface/efi/efi_snp_hii.c +++ b/roms/ipxe/src/interface/efi/efi_snp_hii.c @@ -59,11 +59,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/efi/efi_hii.h> #include <ipxe/efi/efi_snp.h> #include <ipxe/efi/efi_strings.h> -#include <config/general.h> - -/** EFI configuration access protocol GUID */ -static EFI_GUID efi_hii_config_access_protocol_guid - = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID; /** EFI platform setup formset GUID */ static EFI_GUID efi_hii_platform_setup_formset_guid @@ -75,7 +70,7 @@ static EFI_GUID efi_hii_ibm_ucm_compliant_formset_guid /** EFI HII database protocol */ static EFI_HII_DATABASE_PROTOCOL *efihii; -EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii ); +EFI_REQUEST_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii ); /** * Identify settings to be exposed via HII @@ -162,7 +157,7 @@ efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) { struct device *dev = netdev->dev; struct efi_ifr_builder ifr; EFI_HII_PACKAGE_LIST_HEADER *package; - const char *product_name; + const char *name; EFI_GUID package_guid; EFI_GUID formset_guid; EFI_GUID varstore_guid; @@ -173,7 +168,7 @@ efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) { efi_ifr_init ( &ifr ); /* Determine product name */ - product_name = ( PRODUCT_NAME[0] ? PRODUCT_NAME : PRODUCT_SHORT_NAME ); + name = ( product_name[0] ? product_name : product_short_name ); /* Generate GUIDs */ efi_snp_hii_random_guid ( &package_guid ); @@ -181,13 +176,13 @@ efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) { efi_snp_hii_random_guid ( &varstore_guid ); /* Generate title string (used more than once) */ - title_id = efi_ifr_string ( &ifr, "%s (%s)", product_name, + title_id = efi_ifr_string ( &ifr, "%s (%s)", name, netdev_addr ( netdev ) ); /* Generate opcodes */ efi_ifr_form_set_op ( &ifr, &formset_guid, title_id, - efi_ifr_string ( &ifr, - "Configure " PRODUCT_SHORT_NAME), + efi_ifr_string ( &ifr, "Configure %s", + product_short_name ), &efi_hii_platform_setup_formset_guid, &efi_hii_ibm_ucm_compliant_formset_guid, NULL ); efi_ifr_guid_class_op ( &ifr, EFI_NETWORK_DEVICE_CLASS ); @@ -197,7 +192,7 @@ efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) { efi_ifr_text_op ( &ifr, efi_ifr_string ( &ifr, "Name" ), efi_ifr_string ( &ifr, "Firmware product name" ), - efi_ifr_string ( &ifr, "%s", product_name ) ); + efi_ifr_string ( &ifr, "%s", name ) ); efi_ifr_text_op ( &ifr, efi_ifr_string ( &ifr, "Version" ), efi_ifr_string ( &ifr, "Firmware version" ), @@ -649,6 +644,12 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { int efirc; int rc; + /* Do nothing if HII database protocol is not supported */ + if ( ! efihii ) { + rc = -ENOTSUP; + goto err_no_hii; + } + /* Initialise HII protocol */ memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) ); @@ -694,6 +695,7 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { free ( snpdev->package_list ); snpdev->package_list = NULL; err_build_package_list: + err_no_hii: return rc; } @@ -705,6 +707,11 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + /* Do nothing if HII database protocol is not supported */ + if ( ! efihii ) + return; + + /* Uninstall protocols and remove package list */ bs->UninstallMultipleProtocolInterfaces ( snpdev->handle, &efi_hii_config_access_protocol_guid, &snpdev->hii, diff --git a/roms/ipxe/src/interface/efi/efi_utils.c b/roms/ipxe/src/interface/efi/efi_utils.c new file mode 100644 index 000000000..936ad48ec --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_utils.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2011 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_pci.h> +#include <ipxe/efi/efi_utils.h> + +/** @file + * + * EFI utilities + * + */ + +/** + * Find end of device path + * + * @v path Path to device + * @ret path_end End of device path + */ +EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { + + while ( path->Type != END_DEVICE_PATH_TYPE ) { + path = ( ( ( void * ) path ) + + /* There's this amazing new-fangled thing known as + * a UINT16, but who wants to use one of those? */ + ( ( path->Length[1] << 8 ) | path->Length[0] ) ); + } + + return path; +} + +/** + * Locate parent device supporting a given protocol + * + * @v device EFI device handle + * @v protocol Protocol GUID + * @v parent Parent EFI device handle to fill in + * @ret rc Return status code + */ +int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, + EFI_HANDLE *parent ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_DEVICE_PATH_PROTOCOL *path; + void *interface; + } path; + EFI_DEVICE_PATH_PROTOCOL *devpath; + EFI_STATUS efirc; + int rc; + + /* Get device path */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_device_path_protocol_guid, + &path.interface, + efi_image_handle, device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "EFIDEV %p %s cannot open device path: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); + goto err_open_device_path; + } + devpath = path.path; + + /* Check for presence of specified protocol */ + if ( ( efirc = bs->LocateDevicePath ( protocol, &devpath, + parent ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFIDEV %p %s has no parent supporting %s: %s\n", + device, efi_handle_name ( device ), + efi_guid_ntoa ( protocol ), strerror ( rc ) ); + goto err_locate_protocol; + } + + /* Success */ + rc = 0; + + err_locate_protocol: + bs->CloseProtocol ( device, &efi_device_path_protocol_guid, + efi_image_handle, device ); + err_open_device_path: + return rc; +} + +/** + * Add EFI device as child of another EFI device + * + * @v parent EFI parent device handle + * @v child EFI child device handle + * @ret rc Return status code + */ +int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *devpath; + EFI_STATUS efirc; + int rc; + + /* Re-open the device path protocol */ + if ( ( efirc = bs->OpenProtocol ( parent, + &efi_device_path_protocol_guid, + &devpath, + efi_image_handle, child, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( parent, "EFIDEV %p %s could not add child", + parent, efi_handle_name ( parent ) ); + DBGC ( parent, " %p %s: %s\n", child, + efi_handle_name ( child ), strerror ( rc ) ); + DBGC_EFI_OPENERS ( parent, parent, + &efi_device_path_protocol_guid ); + return rc; + } + + DBGC2 ( parent, "EFIDEV %p %s added child", + parent, efi_handle_name ( parent ) ); + DBGC2 ( parent, " %p %s\n", child, efi_handle_name ( child ) ); + return 0; +} + +/** + * Remove EFI device as child of another EFI device + * + * @v parent EFI parent device handle + * @v child EFI child device handle + */ +void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + bs->CloseProtocol ( parent, &efi_device_path_protocol_guid, + efi_image_handle, child ); + DBGC2 ( parent, "EFIDEV %p %s removed child", + parent, efi_handle_name ( parent ) ); + DBGC2 ( parent, " %p %s\n", + child, efi_handle_name ( child ) ); +} + +/** + * Get underlying PCI device information + * + * @v device EFI device handle + * @v prefix Device name prefix + * @v dev Generic device to fill in + * @ret rc Return status code + */ +static int efi_pci_info ( EFI_HANDLE device, const char *prefix, + struct device *dev ) { + EFI_HANDLE pci_device; + struct pci_device pci; + int rc; + + /* Find parent PCI device */ + if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid, + &pci_device ) ) != 0 ) { + DBGC ( device, "EFIDEV %p %s is not a PCI device: %s\n", + device, efi_handle_name ( device ), strerror ( rc ) ); + return rc; + } + + /* Get PCI device information */ + if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) { + DBGC ( device, "EFIDEV %p %s could not get PCI information: " + "%s\n", device, efi_handle_name ( device ), + strerror ( rc ) ); + return rc; + } + + /* Populate device information */ + memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) ); + snprintf ( dev->name, sizeof ( dev->name ), "%s-%s", + prefix, pci.dev.name ); + + return 0; +} + +/** + * Get underlying device information + * + * @v device EFI device handle + * @v prefix Device name prefix + * @v dev Generic device to fill in + */ +void efi_device_info ( EFI_HANDLE device, const char *prefix, + struct device *dev ) { + int rc; + + /* Try getting underlying PCI device information */ + if ( ( rc = efi_pci_info ( device, prefix, dev ) ) == 0 ) + return; + + /* If we cannot get any underlying device information, fall + * back to providing information about the EFI handle. + */ + DBGC ( device, "EFIDEV %p %s could not get underlying device " + "information\n", device, efi_handle_name ( device ) ); + dev->desc.bus_type = BUS_TYPE_EFI; + snprintf ( dev->name, sizeof ( dev->name ), "%s-%p", prefix, device ); +} diff --git a/roms/ipxe/src/interface/efi/efi_wrap.c b/roms/ipxe/src/interface/efi/efi_wrap.c new file mode 100644 index 000000000..ff46b76ed --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_wrap.c @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2014 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * EFI image wrapping + * + */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/Protocol/LoadedImage.h> +#include <ipxe/efi/efi_wrap.h> + +/** EFI system table wrapper */ +static EFI_SYSTEM_TABLE efi_systab_wrapper; + +/** EFI boot services table wrapper */ +static EFI_BOOT_SERVICES efi_bs_wrapper; + +/** Colour for debug messages */ +#define colour &efi_systab_wrapper + +/** + * Convert EFI status code to text + * + * @v efirc EFI status code + * @ret text EFI status code text + */ +static const char * efi_status ( EFI_STATUS efirc ) { + static char buf[ 19 /* "0xXXXXXXXXXXXXXXXX" + NUL */ ]; + + switch ( efirc ) { + case EFI_SUCCESS : return "0"; + case EFI_LOAD_ERROR : return "LOAD_ERROR"; + case EFI_INVALID_PARAMETER : return "INVALID_PARAMETER"; + case EFI_UNSUPPORTED : return "UNSUPPORTED"; + case EFI_BAD_BUFFER_SIZE : return "BAD_BUFFER_SIZE"; + case EFI_BUFFER_TOO_SMALL : return "BUFFER_TOO_SMALL"; + case EFI_NOT_READY : return "NOT_READY"; + case EFI_DEVICE_ERROR : return "DEVICE_ERROR"; + case EFI_WRITE_PROTECTED : return "WRITE_PROTECTED"; + case EFI_OUT_OF_RESOURCES : return "OUT_OF_RESOURCES"; + case EFI_VOLUME_CORRUPTED : return "VOLUME_CORRUPTED"; + case EFI_VOLUME_FULL : return "VOLUME_FULL"; + case EFI_NO_MEDIA : return "NO_MEDIA"; + case EFI_MEDIA_CHANGED : return "MEDIA_CHANGED"; + case EFI_NOT_FOUND : return "NOT_FOUND"; + case EFI_ACCESS_DENIED : return "ACCESS_DENIED"; + case EFI_NO_RESPONSE : return "NO_RESPONSE"; + case EFI_NO_MAPPING : return "NO_MAPPING"; + case EFI_TIMEOUT : return "TIMEOUT"; + case EFI_NOT_STARTED : return "NOT_STARTED"; + case EFI_ALREADY_STARTED : return "ALREADY_STARTED"; + case EFI_ABORTED : return "ABORTED"; + case EFI_ICMP_ERROR : return "ICMP_ERROR"; + case EFI_TFTP_ERROR : return "TFTP_ERROR"; + case EFI_PROTOCOL_ERROR : return "PROTOCOL_ERROR"; + case EFI_INCOMPATIBLE_VERSION : return "INCOMPATIBLE_VERSION"; + case EFI_SECURITY_VIOLATION : return "SECURITY_VIOLATION"; + case EFI_CRC_ERROR : return "CRC_ERROR"; + case EFI_END_OF_MEDIA : return "END_OF_MEDIA"; + case EFI_END_OF_FILE : return "END_OF_FILE"; + case EFI_INVALID_LANGUAGE : return "INVALID_LANGUAGE"; + case EFI_COMPROMISED_DATA : return "COMPROMISED_DATA"; + case EFI_WARN_UNKNOWN_GLYPH : return "WARN_UNKNOWN_GLYPH"; + case EFI_WARN_DELETE_FAILURE : return "WARN_DELETE_FAILURE"; + case EFI_WARN_WRITE_FAILURE : return "WARN_WRITE_FAILURE"; + case EFI_WARN_BUFFER_TOO_SMALL : return "WARN_BUFFER_TOO_SMALL"; + case EFI_WARN_STALE_DATA : return "WARN_STALE_DATA"; + default: + snprintf ( buf, sizeof ( buf ), "%#lx", + ( unsigned long ) efirc ); + return buf; + } +} + +/** + * Wrap HandleProtocol() + * + */ +static EFI_STATUS EFIAPI +efi_handle_protocol_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, + VOID **interface ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "HandleProtocol ( %p %s, %s, ... ) ", handle, + efi_handle_name ( handle ), efi_guid_ntoa ( protocol ) ); + efirc = bs->HandleProtocol ( handle, protocol, interface ); + DBGC ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *interface, retaddr ); + return efirc; +} + +/** + * Wrap LocateHandle() + * + */ +static EFI_STATUS EFIAPI +efi_locate_handle_wrapper ( EFI_LOCATE_SEARCH_TYPE search_type, + EFI_GUID *protocol, VOID *search_key, + UINTN *buffer_size, EFI_HANDLE *buffer ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "LocateHandle ( %d, %s, ..., %zd, ... ) ", search_type, + efi_guid_ntoa ( protocol ), ( ( size_t ) *buffer_size ) ); + efirc = bs->LocateHandle ( search_type, protocol, search_key, + buffer_size, buffer ); + DBGC ( colour, "= %s ( %zd ) -> %p\n", + efi_status ( efirc ), ( ( size_t ) *buffer_size ), retaddr ); + return efirc; +} + +/** + * Wrap LocateDevicePath() + * + */ +static EFI_STATUS EFIAPI +efi_locate_device_path_wrapper ( EFI_GUID *protocol, + EFI_DEVICE_PATH_PROTOCOL **device_path, + EFI_HANDLE *device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "LocateDevicePath ( %s, %s, ... ) ", + efi_guid_ntoa ( protocol ), efi_devpath_text ( *device_path ) ); + efirc = bs->LocateDevicePath ( protocol, device_path, device ); + DBGC ( colour, "= %s ( %p, ", + efi_status ( efirc ), efi_devpath_text ( *device_path ) ); + DBGC ( colour, "%p %s ) -> %p\n", + *device, efi_handle_name ( *device ), retaddr ); + return efirc; +} + +/** + * Wrap LoadImage() + * + */ +static EFI_STATUS EFIAPI +efi_load_image_wrapper ( BOOLEAN boot_policy, EFI_HANDLE parent_image_handle, + EFI_DEVICE_PATH_PROTOCOL *device_path, + VOID *source_buffer, UINTN source_size, + EFI_HANDLE *image_handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "LoadImage ( %d, %p %s, ", boot_policy, + parent_image_handle, efi_handle_name ( parent_image_handle ) ); + DBGC ( colour, "%s, %p, %#llx, ... ) ", + efi_devpath_text ( device_path ), source_buffer, + ( ( unsigned long long ) source_size ) ); + efirc = bs->LoadImage ( boot_policy, parent_image_handle, device_path, + source_buffer, source_size, image_handle ); + DBGC ( colour, "= %s ( ", efi_status ( efirc ) ); + if ( efirc == 0 ) { + DBGC ( colour, "%p %s ", *image_handle, + efi_handle_name ( *image_handle ) ); + } + DBGC ( colour, ") -> %p\n", retaddr ); + + /* Wrap the new image */ + if ( efirc == 0 ) + efi_wrap ( *image_handle ); + + return efirc; +} + +/** + * Wrap ExitBootServices() + * + */ +static EFI_STATUS EFIAPI +efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "ExitBootServices ( %p %s, %#llx ) ", + image_handle, efi_handle_name ( image_handle ), + ( ( unsigned long long ) map_key ) ); + efirc = bs->ExitBootServices ( image_handle, map_key ); + DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap OpenProtocol() + * + */ +static EFI_STATUS EFIAPI +efi_open_protocol_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, + VOID **interface, EFI_HANDLE agent_handle, + EFI_HANDLE controller_handle, UINT32 attributes ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "OpenProtocol ( %p %s, %s, ..., ", handle, + efi_handle_name ( handle ), efi_guid_ntoa ( protocol ) ); + DBGC ( colour, "%p %s, ", agent_handle, + efi_handle_name ( agent_handle ) ); + DBGC ( colour, "%p %s, %#x ) ", controller_handle, + efi_handle_name ( controller_handle ), attributes ); + efirc = bs->OpenProtocol ( handle, protocol, interface, agent_handle, + controller_handle, attributes ); + DBGC ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *interface, retaddr ); + return efirc; +} + +/** + * Wrap LocateProtocol() + * + */ +static EFI_STATUS EFIAPI +efi_locate_protocol_wrapper ( EFI_GUID *protocol, VOID *registration, + VOID **interface ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "LocateProtocol ( %s, %p, ... ) ", + efi_guid_ntoa ( protocol ), registration ); + efirc = bs->LocateProtocol ( protocol, registration, interface ); + DBGC ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *interface, retaddr ); + return efirc; +} + +/** + * Wrap the calls made by a loaded image + * + * @v handle Image handle + */ + void efi_wrap ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_LOADED_IMAGE_PROTOCOL *image; + void *intf; + } loaded; + EFI_STATUS efirc; + int rc; + + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return; + + /* Populate table wrappers */ + memcpy ( &efi_systab_wrapper, efi_systab, + sizeof ( efi_systab_wrapper ) ); + memcpy ( &efi_bs_wrapper, bs, sizeof ( efi_bs_wrapper ) ); + efi_systab_wrapper.BootServices = &efi_bs_wrapper; + efi_bs_wrapper.HandleProtocol = efi_handle_protocol_wrapper; + efi_bs_wrapper.LocateHandle = efi_locate_handle_wrapper; + efi_bs_wrapper.LocateDevicePath = efi_locate_device_path_wrapper; + efi_bs_wrapper.LoadImage = efi_load_image_wrapper; + efi_bs_wrapper.ExitBootServices = efi_exit_boot_services_wrapper; + efi_bs_wrapper.OpenProtocol = efi_open_protocol_wrapper; + efi_bs_wrapper.LocateProtocol = efi_locate_protocol_wrapper; + + /* Open loaded image protocol */ + if ( ( efirc = bs->OpenProtocol ( handle, + &efi_loaded_image_protocol_guid, + &loaded.intf, efi_image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( colour, "Could not get loaded image protocol for %p %s: " + "%s\n", handle, efi_handle_name ( handle ), + strerror ( rc ) ); + return; + } + + /* Provide system table wrapper to image */ + loaded.image->SystemTable = &efi_systab_wrapper; + DBGC ( colour, "Wrapped image %p %s at base %p has protocols:\n", + handle, efi_handle_name ( handle ), loaded.image->ImageBase ); + DBGC_EFI_PROTOCOLS ( colour, handle ); + DBGC ( colour, "Parent image %p %s\n", loaded.image->ParentHandle, + efi_handle_name ( loaded.image->ParentHandle ) ); + DBGC ( colour, "Device %p %s ", loaded.image->DeviceHandle, + efi_handle_name ( loaded.image->DeviceHandle ) ); + DBGC ( colour, "file %p %s\n", loaded.image->FilePath, + efi_devpath_text ( loaded.image->FilePath ) ); + + /* Close loaded image protocol */ + bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid, + efi_image_handle, NULL ); +} diff --git a/roms/ipxe/src/interface/smbios/smbios_settings.c b/roms/ipxe/src/interface/smbios/smbios_settings.c index 5dcf00201..83e4320e9 100644 --- a/roms/ipxe/src/interface/smbios/smbios_settings.c +++ b/roms/ipxe/src/interface/smbios/smbios_settings.c @@ -241,3 +241,15 @@ const struct setting asset_setting __setting ( SETTING_HOST_EXTRA, asset ) = { .type = &setting_type_string, .scope = &smbios_settings_scope, }; + +/** Board serial number setting (may differ from chassis serial number) */ +const struct setting board_serial_setting __setting ( SETTING_HOST_EXTRA, + board_serial ) = { + .name = "board-serial", + .description = "Base board serial", + .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_BASE_BOARD_INFORMATION, + struct smbios_base_board_information, + serial ), + .type = &setting_type_string, + .scope = &smbios_settings_scope, +}; diff --git a/roms/ipxe/src/interface/xen/xenbus.c b/roms/ipxe/src/interface/xen/xenbus.c new file mode 100644 index 000000000..ffc8aba3e --- /dev/null +++ b/roms/ipxe/src/interface/xen/xenbus.c @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2014 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 (at your option) 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <errno.h> +#include <ipxe/malloc.h> +#include <ipxe/device.h> +#include <ipxe/timer.h> +#include <ipxe/nap.h> +#include <ipxe/xen.h> +#include <ipxe/xenstore.h> +#include <ipxe/xenbus.h> + +/** @file + * + * Xen device bus + * + */ + +/* Disambiguate the various error causes */ +#define ETIMEDOUT_UNKNOWN \ + __einfo_error ( EINFO_ETIMEDOUT_UNKNOWN ) +#define EINFO_ETIMEDOUT_UNKNOWN \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateUnknown, \ + "Unknown" ) +#define ETIMEDOUT_INITIALISING \ + __einfo_error ( EINFO_ETIMEDOUT_INITIALISING ) +#define EINFO_ETIMEDOUT_INITIALISING \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitialising, \ + "Initialising" ) +#define ETIMEDOUT_INITWAIT \ + __einfo_error ( EINFO_ETIMEDOUT_INITWAIT ) +#define EINFO_ETIMEDOUT_INITWAIT \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitWait, \ + "InitWait" ) +#define ETIMEDOUT_INITIALISED \ + __einfo_error ( EINFO_ETIMEDOUT_INITIALISED ) +#define EINFO_ETIMEDOUT_INITIALISED \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateInitialised, \ + "Initialised" ) +#define ETIMEDOUT_CONNECTED \ + __einfo_error ( EINFO_ETIMEDOUT_CONNECTED ) +#define EINFO_ETIMEDOUT_CONNECTED \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateConnected, \ + "Connected" ) +#define ETIMEDOUT_CLOSING \ + __einfo_error ( EINFO_ETIMEDOUT_CLOSING ) +#define EINFO_ETIMEDOUT_CLOSING \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateClosing, \ + "Closing" ) +#define ETIMEDOUT_CLOSED \ + __einfo_error ( EINFO_ETIMEDOUT_CLOSED ) +#define EINFO_ETIMEDOUT_CLOSED \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateClosed, \ + "Closed" ) +#define ETIMEDOUT_RECONFIGURING \ + __einfo_error ( EINFO_ETIMEDOUT_RECONFIGURING ) +#define EINFO_ETIMEDOUT_RECONFIGURING \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateReconfiguring, \ + "Reconfiguring" ) +#define ETIMEDOUT_RECONFIGURED \ + __einfo_error ( EINFO_ETIMEDOUT_RECONFIGURED ) +#define EINFO_ETIMEDOUT_RECONFIGURED \ + __einfo_uniqify ( EINFO_ETIMEDOUT, XenbusStateReconfigured, \ + "Reconfigured" ) +#define ETIMEDOUT_STATE( state ) \ + EUNIQ ( EINFO_ETIMEDOUT, (state), ETIMEDOUT_UNKNOWN, \ + ETIMEDOUT_INITIALISING, ETIMEDOUT_INITWAIT, \ + ETIMEDOUT_INITIALISED, ETIMEDOUT_CONNECTED, \ + ETIMEDOUT_CLOSING, ETIMEDOUT_CLOSED, \ + ETIMEDOUT_RECONFIGURING, ETIMEDOUT_RECONFIGURED ) + +/** Maximum time to wait for backend to reach a given state, in ticks */ +#define XENBUS_BACKEND_TIMEOUT ( 5 * TICKS_PER_SEC ) + +/** + * Set device state + * + * @v xendev Xen device + * @v state New state + * @ret rc Return status code + */ +int xenbus_set_state ( struct xen_device *xendev, int state ) { + int rc; + + /* Attempt to set state */ + if ( ( rc = xenstore_write_num ( xendev->xen, state, xendev->key, + "state", NULL ) ) != 0 ) { + DBGC ( xendev, "XENBUS %s could not set state=\"%d\": %s\n", + xendev->key, state, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Get backend state + * + * @v xendev Xen device + * @ret state Backend state, or negative error + */ +int xenbus_backend_state ( struct xen_device *xendev ) { + unsigned long state; + int rc; + + /* Attempt to get backend state */ + if ( ( rc = xenstore_read_num ( xendev->xen, &state, xendev->backend, + "state", NULL ) ) != 0 ) { + DBGC ( xendev, "XENBUS %s could not read %s/state: %s\n", + xendev->key, xendev->backend, strerror ( rc ) ); + return rc; + } + + return state; +} + +/** + * Wait for backend to reach a given state + * + * @v xendev Xen device + * @v state Desired backend state + * @ret rc Return status code + */ +int xenbus_backend_wait ( struct xen_device *xendev, int state ) { + unsigned long started = currticks(); + unsigned long elapsed; + unsigned int attempts = 0; + int current_state; + int rc; + + /* Wait for backend to reach this state */ + do { + + /* Get current backend state */ + current_state = xenbus_backend_state ( xendev ); + if ( current_state < 0 ) { + rc = current_state; + return rc; + } + if ( current_state == state ) + return 0; + + /* Allow time for backend to react */ + cpu_nap(); + + /* XenStore is a very slow interface; any fixed delay + * time would be dwarfed by the XenStore access time. + * We therefore use wall clock to time out this + * operation. + */ + elapsed = ( currticks() - started ); + attempts++; + + } while ( elapsed < XENBUS_BACKEND_TIMEOUT ); + + /* Construct status code from current backend state */ + rc = -ETIMEDOUT_STATE ( current_state ); + DBGC ( xendev, "XENBUS %s timed out after %d attempts waiting for " + "%s/state=\"%d\": %s\n", xendev->key, attempts, xendev->backend, + state, strerror ( rc ) ); + + return rc; +} + +/** + * Find driver for Xen device + * + * @v type Device type + * @ret driver Driver, or NULL + */ +static struct xen_driver * xenbus_find_driver ( const char *type ) { + struct xen_driver *xendrv; + + for_each_table_entry ( xendrv, XEN_DRIVERS ) { + if ( strcmp ( xendrv->type, type ) == 0 ) + return xendrv; + } + return NULL; +} + +/** + * Probe Xen device + * + * @v xen Xen hypervisor + * @v parent Parent device + * @v type Device type + * @v instance Device instance + * @ret rc Return status code + */ +static int xenbus_probe_device ( struct xen_hypervisor *xen, + struct device *parent, const char *type, + const char *instance ) { + struct xen_device *xendev; + size_t key_len; + int rc; + + /* Allocate and initialise structure */ + key_len = ( 7 /* "device/" */ + strlen ( type ) + 1 /* "/" */ + + strlen ( instance ) + 1 /* NUL */ ); + xendev = zalloc ( sizeof ( *xendev ) + key_len ); + if ( ! xendev ) { + rc = -ENOMEM; + goto err_alloc; + } + snprintf ( xendev->dev.name, sizeof ( xendev->dev.name ), "%s/%s", + type, instance ); + xendev->dev.desc.bus_type = BUS_TYPE_XEN; + INIT_LIST_HEAD ( &xendev->dev.children ); + list_add_tail ( &xendev->dev.siblings, &parent->children ); + xendev->dev.parent = parent; + xendev->xen = xen; + xendev->key = ( ( void * ) ( xendev + 1 ) ); + snprintf ( xendev->key, key_len, "device/%s/%s", type, instance ); + + /* Read backend key */ + if ( ( rc = xenstore_read ( xen, &xendev->backend, xendev->key, + "backend", NULL ) ) != 0 ) { + DBGC ( xendev, "XENBUS %s could not read backend: %s\n", + xendev->key, strerror ( rc ) ); + goto err_read_backend; + } + + /* Read backend domain ID */ + if ( ( rc = xenstore_read_num ( xen, &xendev->backend_id, xendev->key, + "backend-id", NULL ) ) != 0 ) { + DBGC ( xendev, "XENBUS %s could not read backend-id: %s\n", + xendev->key, strerror ( rc ) ); + goto err_read_backend_id; + } + DBGC ( xendev, "XENBUS %s backend=\"%s\" in domain %ld\n", + xendev->key, xendev->backend, xendev->backend_id ); + + /* Look for a driver */ + xendev->driver = xenbus_find_driver ( type ); + if ( ! xendev->driver ) { + DBGC ( xendev, "XENBUS %s has no driver\n", xendev->key ); + /* Not a fatal error */ + rc = 0; + goto err_no_driver; + } + xendev->dev.driver_name = xendev->driver->name; + DBGC ( xendev, "XENBUS %s has driver \"%s\"\n", xendev->key, + xendev->driver->name ); + + /* Probe driver */ + if ( ( rc = xendev->driver->probe ( xendev ) ) != 0 ) { + DBGC ( xendev, "XENBUS could not probe %s: %s\n", + xendev->key, strerror ( rc ) ); + goto err_probe; + } + + return 0; + + xendev->driver->remove ( xendev ); + err_probe: + err_no_driver: + err_read_backend_id: + free ( xendev->backend ); + err_read_backend: + list_del ( &xendev->dev.siblings ); + free ( xendev ); + err_alloc: + return rc; +} + +/** + * Remove Xen device + * + * @v xendev Xen device + */ +static void xenbus_remove_device ( struct xen_device *xendev ) { + + /* Remove device */ + xendev->driver->remove ( xendev ); + free ( xendev->backend ); + list_del ( &xendev->dev.siblings ); + free ( xendev ); +} + +/** + * Probe Xen devices of a given type + * + * @v xen Xen hypervisor + * @v parent Parent device + * @v type Device type + * @ret rc Return status code + */ +static int xenbus_probe_type ( struct xen_hypervisor *xen, + struct device *parent, const char *type ) { + char *children; + char *child; + size_t len; + int rc; + + /* Get children of this key */ + if ( ( rc = xenstore_directory ( xen, &children, &len, "device", + type, NULL ) ) != 0 ) { + DBGC ( xen, "XENBUS could not list \"%s\" devices: %s\n", + type, strerror ( rc ) ); + goto err_directory; + } + + /* Probe each child */ + for ( child = children ; child < ( children + len ) ; + child += ( strlen ( child ) + 1 /* NUL */ ) ) { + if ( ( rc = xenbus_probe_device ( xen, parent, type, + child ) ) != 0 ) + goto err_probe_device; + } + + free ( children ); + return 0; + + err_probe_device: + free ( children ); + err_directory: + return rc; +} + +/** + * Probe Xen bus + * + * @v xen Xen hypervisor + * @v parent Parent device + * @ret rc Return status code + */ +int xenbus_probe ( struct xen_hypervisor *xen, struct device *parent ) { + char *types; + char *type; + size_t len; + int rc; + + /* Get children of "device" key */ + if ( ( rc = xenstore_directory ( xen, &types, &len, "device", + NULL ) ) != 0 ) { + DBGC ( xen, "XENBUS could not list device types: %s\n", + strerror ( rc ) ); + goto err_directory; + } + + /* Probe each child type */ + for ( type = types ; type < ( types + len ) ; + type += ( strlen ( type ) + 1 /* NUL */ ) ) { + if ( ( rc = xenbus_probe_type ( xen, parent, type ) ) != 0 ) + goto err_probe_type; + } + + free ( types ); + return 0; + + xenbus_remove ( xen, parent ); + err_probe_type: + free ( types ); + err_directory: + return rc; +} + +/** + * Remove Xen bus + * + * @v xen Xen hypervisor + * @v parent Parent device + */ +void xenbus_remove ( struct xen_hypervisor *xen __unused, + struct device *parent ) { + struct xen_device *xendev; + struct xen_device *tmp; + + /* Remove devices */ + list_for_each_entry_safe ( xendev, tmp, &parent->children, + dev.siblings ) { + xenbus_remove_device ( xendev ); + } +} diff --git a/roms/ipxe/src/interface/xen/xengrant.c b/roms/ipxe/src/interface/xen/xengrant.c new file mode 100644 index 000000000..be12b23dc --- /dev/null +++ b/roms/ipxe/src/interface/xen/xengrant.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2014 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 (at your option) 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <strings.h> +#include <errno.h> +#include <assert.h> +#include <ipxe/io.h> +#include <ipxe/xen.h> +#include <ipxe/xengrant.h> + +/** @file + * + * Xen grant tables + * + */ + +/** Grant table version to try setting + * + * Using version 1 grant tables limits guests to using 16TB of + * grantable RAM, and prevents the use of subpage grants. Some + * versions of the Xen hypervisor refuse to allow the grant table + * version to be set after the first grant references have been + * created, so the loaded operating system may be stuck with whatever + * choice we make here. We therefore currently use version 2 grant + * tables, since they give the most flexibility to the loaded OS. + * + * Current versions (7.2.0) of the Windows PV drivers have no support + * for version 2 grant tables, and will merrily create version 1 + * entries in what the hypervisor believes to be a version 2 table. + * This causes some confusion. + * + * Avoid this problem by attempting to use version 1 tables, since + * otherwise we may render Windows unable to boot. + * + * Play nicely with other potential bootloaders by accepting either + * version 1 or version 2 grant tables (if we are unable to set our + * requested version). + */ +#define XENGRANT_TRY_VERSION 1 + +/** + * Initialise grant table + * + * @v xen Xen hypervisor + * @ret rc Return status code + */ +int xengrant_init ( struct xen_hypervisor *xen ) { + struct gnttab_query_size size; + struct gnttab_set_version set_version; + struct gnttab_get_version get_version; + struct grant_entry_v1 *v1; + union grant_entry_v2 *v2; + unsigned int version; + int xenrc; + int rc; + + /* Get grant table size */ + size.dom = DOMID_SELF; + if ( ( xenrc = xengrant_query_size ( xen, &size ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( xen, "XENGRANT could not get table size: %s\n", + strerror ( rc ) ); + return rc; + } + xen->grant.len = ( size.nr_frames * PAGE_SIZE ); + + /* Set grant table version, if applicable */ + set_version.version = XENGRANT_TRY_VERSION; + if ( ( xenrc = xengrant_set_version ( xen, &set_version ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( xen, "XENGRANT could not set version %d: %s\n", + XENGRANT_TRY_VERSION, strerror ( rc ) ); + /* Continue; use whatever version is current */ + } + + /* Get grant table version */ + get_version.dom = DOMID_SELF; + get_version.pad = 0; + if ( ( xenrc = xengrant_get_version ( xen, &get_version ) ) == 0 ) { + version = get_version.version; + switch ( version ) { + + case 0: + /* Version not yet specified: will be version 1 */ + version = 1; + break; + + case 1 : + /* Version 1 table: nothing special to do */ + break; + + case 2: + /* Version 2 table: configure shift appropriately */ + xen->grant.shift = ( fls ( sizeof ( *v2 ) / + sizeof ( *v1 ) ) - 1 ); + break; + + default: + /* Unsupported version */ + DBGC ( xen, "XENGRANT detected unsupported version " + "%d\n", version ); + return -ENOTSUP; + + } + } else { + rc = -EXEN ( xenrc ); + DBGC ( xen, "XENGRANT could not get version (assuming v1): " + "%s\n", strerror ( rc ) ); + version = 1; + } + + DBGC ( xen, "XENGRANT using v%d table with %d entries\n", + version, xengrant_entries ( xen ) ); + return 0; +} + +/** + * Allocate grant references + * + * @v xen Xen hypervisor + * @v refs Grant references to fill in + * @v count Number of references + * @ret rc Return status code + */ +int xengrant_alloc ( struct xen_hypervisor *xen, grant_ref_t *refs, + unsigned int count ) { + struct grant_entry_header *hdr; + unsigned int entries = xengrant_entries ( xen ); + unsigned int mask = ( entries - 1 ); + unsigned int check = 0; + unsigned int avail; + unsigned int ref; + + /* Fail unless we have enough references available */ + avail = ( entries - xen->grant.used - GNTTAB_NR_RESERVED_ENTRIES ); + if ( avail < count ) { + DBGC ( xen, "XENGRANT cannot allocate %d references (only %d " + "of %d available)\n", count, avail, entries ); + return -ENOBUFS; + } + DBGC ( xen, "XENGRANT allocating %d references (from %d of %d " + "available)\n", count, avail, entries ); + + /* Update number of references used */ + xen->grant.used += count; + + /* Find unused references */ + for ( ref = xen->grant.ref ; count ; ref = ( ( ref + 1 ) & mask ) ) { + + /* Sanity check */ + assert ( check++ < entries ); + + /* Skip reserved references */ + if ( ref < GNTTAB_NR_RESERVED_ENTRIES ) + continue; + + /* Skip in-use references */ + hdr = xengrant_header ( xen, ref ); + if ( readw ( &hdr->flags ) & GTF_type_mask ) + continue; + if ( readw ( &hdr->domid ) == DOMID_SELF ) + continue; + + /* Zero reference */ + xengrant_zero ( xen, hdr ); + + /* Mark reference as in-use. We leave the flags as + * empty (to avoid creating a valid grant table entry) + * and set the domid to DOMID_SELF. + */ + writew ( DOMID_SELF, &hdr->domid ); + DBGC2 ( xen, "XENGRANT allocated ref %d\n", ref ); + + /* Record reference */ + refs[--count] = ref; + } + + /* Update cursor */ + xen->grant.ref = ref; + + return 0; +} + +/** + * Free grant references + * + * @v xen Xen hypervisor + * @v refs Grant references + * @v count Number of references + */ +void xengrant_free ( struct xen_hypervisor *xen, grant_ref_t *refs, + unsigned int count ) { + struct grant_entry_header *hdr; + unsigned int ref; + unsigned int i; + + /* Free references */ + for ( i = 0 ; i < count ; i++ ) { + + /* Sanity check */ + ref = refs[i]; + assert ( ref < xengrant_entries ( xen ) ); + + /* Zero reference */ + hdr = xengrant_header ( xen, ref ); + xengrant_zero ( xen, hdr ); + DBGC2 ( xen, "XENGRANT freed ref %d\n", ref ); + } +} diff --git a/roms/ipxe/src/interface/xen/xenstore.c b/roms/ipxe/src/interface/xen/xenstore.c new file mode 100644 index 000000000..b96982927 --- /dev/null +++ b/roms/ipxe/src/interface/xen/xenstore.c @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2014 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 (at your option) 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ipxe/io.h> +#include <ipxe/nap.h> +#include <ipxe/malloc.h> +#include <ipxe/xen.h> +#include <ipxe/xenevent.h> +#include <ipxe/xenstore.h> + +/* + * xs_wire.h attempts to define a static error table xsd_errors, which + * interacts badly with the dynamically generated error numbers used + * by iPXE. Prevent this table from being constructed by including + * errno.h only after including xs_wire.h. + * + */ +#include <xen/io/xs_wire.h> +#include <errno.h> + +/** @file + * + * XenStore interface + * + */ + +/** Request identifier */ +static uint32_t xenstore_req_id; + +/** + * Send XenStore request raw data + * + * @v xen Xen hypervisor + * @v data Data buffer + * @v len Length of data + */ +static void xenstore_send ( struct xen_hypervisor *xen, const void *data, + size_t len ) { + struct xenstore_domain_interface *intf = xen->store.intf; + XENSTORE_RING_IDX prod = readl ( &intf->req_prod ); + XENSTORE_RING_IDX cons; + XENSTORE_RING_IDX idx; + const char *bytes = data; + size_t offset = 0; + size_t fill; + + DBGCP ( intf, "XENSTORE raw request:\n" ); + DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( prod ), data, len ); + + /* Write one byte at a time */ + while ( offset < len ) { + + /* Wait for space to become available */ + while ( 1 ) { + cons = readl ( &intf->req_cons ); + fill = ( prod - cons ); + if ( fill < XENSTORE_RING_SIZE ) + break; + DBGC2 ( xen, "." ); + cpu_nap(); + rmb(); + } + + /* Write byte */ + idx = MASK_XENSTORE_IDX ( prod++ ); + writeb ( bytes[offset++], &intf->req[idx] ); + } + + /* Update producer counter */ + wmb(); + writel ( prod, &intf->req_prod ); + wmb(); +} + +/** + * Send XenStore request string (excluding terminating NUL) + * + * @v xen Xen hypervisor + * @v string String + */ +static void xenstore_send_string ( struct xen_hypervisor *xen, + const char *string ) { + + xenstore_send ( xen, string, strlen ( string ) ); +} + +/** + * Receive XenStore response raw data + * + * @v xen Xen hypervisor + * @v data Data buffer, or NULL to discard data + * @v len Length of data + */ +static void xenstore_recv ( struct xen_hypervisor *xen, void *data, + size_t len ) { + struct xenstore_domain_interface *intf = xen->store.intf; + XENSTORE_RING_IDX cons = readl ( &intf->rsp_cons ); + XENSTORE_RING_IDX prod; + XENSTORE_RING_IDX idx; + char *bytes = data; + size_t offset = 0; + size_t fill; + + DBGCP ( intf, "XENSTORE raw response:\n" ); + + /* Read one byte at a time */ + while ( offset < len ) { + + /* Wait for data to be ready */ + while ( 1 ) { + prod = readl ( &intf->rsp_prod ); + fill = ( prod - cons ); + if ( fill > 0 ) + break; + DBGC2 ( xen, "." ); + cpu_nap(); + rmb(); + } + + /* Read byte */ + idx = MASK_XENSTORE_IDX ( cons++ ); + if ( data ) + bytes[offset++] = readb ( &intf->rsp[idx] ); + } + if ( data ) + DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( cons - len ), data, len ); + + /* Update consumer counter */ + writel ( cons, &intf->rsp_cons ); + wmb(); +} + +/** + * Send XenStore request + * + * @v xen Xen hypervisor + * @v type Message type + * @v req_id Request ID + * @v value Value, or NULL to omit + * @v key Key path components + * @ret rc Return status code + */ +static int xenstore_request ( struct xen_hypervisor *xen, + enum xsd_sockmsg_type type, uint32_t req_id, + const char *value, va_list key ) { + struct xsd_sockmsg msg; + struct evtchn_send event; + const char *string; + va_list tmp; + int xenrc; + int rc; + + /* Construct message header */ + msg.type = type; + msg.req_id = req_id; + msg.tx_id = 0; + msg.len = 0; + DBGC2 ( xen, "XENSTORE request ID %d type %d ", req_id, type ); + + /* Calculate total length */ + va_copy ( tmp, key ); + while ( ( string = va_arg ( tmp, const char * ) ) != NULL ) { + DBGC2 ( xen, "%s%s", ( msg.len ? "/" : "" ), string ); + msg.len += ( strlen ( string ) + 1 /* '/' or NUL */ ); + } + va_end ( tmp ); + if ( value ) { + DBGC2 ( xen, " = \"%s\"", value ); + msg.len += strlen ( value ); + } + DBGC2 ( xen, "\n" ); + + /* Send message */ + xenstore_send ( xen, &msg, sizeof ( msg ) ); + string = va_arg ( key, const char * ); + assert ( string != NULL ); + xenstore_send_string ( xen, string ); + while ( ( string = va_arg ( key, const char * ) ) != NULL ) { + xenstore_send_string ( xen, "/" ); + xenstore_send_string ( xen, string ); + } + xenstore_send ( xen, "", 1 ); /* Separating NUL */ + if ( value ) + xenstore_send_string ( xen, value ); + + /* Notify the back end */ + event.port = xen->store.port; + if ( ( xenrc = xenevent_send ( xen, &event ) ) != 0 ) { + rc = -EXEN ( xenrc ); + DBGC ( xen, "XENSTORE could not notify back end: %s\n", + strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Receive XenStore response + * + * @v xen Xen hypervisor + * @v req_id Request ID + * @v value Value to fill in + * @v len Length to fill in + * @ret rc Return status code + * + * The caller is responsible for eventually calling free() on the + * returned value. Note that the value may comprise multiple + * NUL-terminated strings concatenated together. A terminating NUL + * will always be appended to the returned value. + */ +static int xenstore_response ( struct xen_hypervisor *xen, uint32_t req_id, + char **value, size_t *len ) { + struct xsd_sockmsg msg; + char *string; + int rc; + + /* Receive message header */ + xenstore_recv ( xen, &msg, sizeof ( msg ) ); + *len = msg.len; + + /* Allocate space for response */ + *value = zalloc ( msg.len + 1 /* terminating NUL */ ); + + /* Receive data. Do this even if allocation failed, or if the + * request ID was incorrect, to avoid leaving data in the + * ring. + */ + xenstore_recv ( xen, *value, msg.len ); + + /* Validate request ID */ + if ( msg.req_id != req_id ) { + DBGC ( xen, "XENSTORE response ID mismatch (got %d, expected " + "%d)\n", msg.req_id, req_id ); + rc = -EPROTO; + goto err_req_id; + } + + /* Check for allocation failure */ + if ( ! *value ) { + DBGC ( xen, "XENSTORE could not allocate %d bytes for " + "response\n", msg.len ); + rc = -ENOMEM; + goto err_alloc; + } + + /* Check for explicit errors */ + if ( msg.type == XS_ERROR ) { + DBGC ( xen, "XENSTORE response error \"%s\"\n", *value ); + rc = -EIO; + goto err_explicit; + } + + DBGC2 ( xen, "XENSTORE response ID %d\n", req_id ); + if ( DBG_EXTRA ) { + for ( string = *value ; string < ( *value + msg.len ) ; + string += ( strlen ( string ) + 1 /* NUL */ ) ) { + DBGC2 ( xen, " - \"%s\"\n", string ); + } + } + return 0; + + err_explicit: + err_alloc: + err_req_id: + free ( *value ); + *value = NULL; + return rc; +} + +/** + * Issue a XenStore message + * + * @v xen Xen hypervisor + * @v type Message type + * @v response Response value to fill in, or NULL to discard + * @v len Response length to fill in, or NULL to ignore + * @v request Request value, or NULL to omit + * @v key Key path components + * @ret rc Return status code + */ +static int xenstore_message ( struct xen_hypervisor *xen, + enum xsd_sockmsg_type type, char **response, + size_t *len, const char *request, va_list key ) { + char *response_value; + size_t response_len; + int rc; + + /* Send request */ + if ( ( rc = xenstore_request ( xen, type, ++xenstore_req_id, + request, key ) ) != 0 ) + return rc; + + /* Receive response */ + if ( ( rc = xenstore_response ( xen, xenstore_req_id, &response_value, + &response_len ) ) != 0 ) + return rc; + + /* Return response, if applicable */ + if ( response ) { + *response = response_value; + } else { + free ( response_value ); + } + if ( len ) + *len = response_len; + + return 0; +} + +/** + * Read XenStore value + * + * @v xen Xen hypervisor + * @v value Value to fill in + * @v key Key path components + * @ret rc Return status code + * + * On a successful return, the caller is responsible for calling + * free() on the returned value. + */ +static int xenstore_vread ( struct xen_hypervisor *xen, char **value, + va_list key ) { + + return xenstore_message ( xen, XS_READ, value, NULL, NULL, key ); +} + +/** + * Read XenStore value + * + * @v xen Xen hypervisor + * @v value Value to fill in + * @v ... Key path components + * @ret rc Return status code + * + * On a successful return, the caller is responsible for calling + * free() on the returned value. + */ +__attribute__ (( sentinel )) int +xenstore_read ( struct xen_hypervisor *xen, char **value, ... ) { + va_list key; + int rc; + + va_start ( key, value ); + rc = xenstore_vread ( xen, value, key ); + va_end ( key ); + return rc; +} + +/** + * Read XenStore numeric value + * + * @v xen Xen hypervisor + * @v num Numeric value to fill in + * @v ... Key path components + * @ret rc Return status code + */ +__attribute__ (( sentinel )) int +xenstore_read_num ( struct xen_hypervisor *xen, unsigned long *num, ... ) { + va_list key; + char *value; + char *endp; + int rc; + + /* Try to read text value */ + va_start ( key, num ); + rc = xenstore_vread ( xen, &value, key ); + va_end ( key ); + if ( rc != 0 ) + goto err_read; + + /* Try to parse as numeric value */ + *num = strtoul ( value, &endp, 10 ); + if ( ( *value == '\0' ) || ( *endp != '\0' ) ) { + DBGC ( xen, "XENSTORE found invalid numeric value \"%s\"\n", + value ); + rc = -EINVAL; + goto err_strtoul; + } + + err_strtoul: + free ( value ); + err_read: + return rc; +} + +/** + * Write XenStore value + * + * @v xen Xen hypervisor + * @v value Value + * @v key Key path components + * @ret rc Return status code + */ +static int xenstore_vwrite ( struct xen_hypervisor *xen, const char *value, + va_list key ) { + + return xenstore_message ( xen, XS_WRITE, NULL, NULL, value, key ); +} + +/** + * Write XenStore value + * + * @v xen Xen hypervisor + * @v value Value + * @v ... Key path components + * @ret rc Return status code + */ +__attribute__ (( sentinel )) int +xenstore_write ( struct xen_hypervisor *xen, const char *value, ... ) { + va_list key; + int rc; + + va_start ( key, value ); + rc = xenstore_vwrite ( xen, value, key ); + va_end ( key ); + return rc; +} + +/** + * Write XenStore numeric value + * + * @v xen Xen hypervisor + * @v num Numeric value + * @v ... Key path components + * @ret rc Return status code + */ +__attribute__ (( sentinel )) int +xenstore_write_num ( struct xen_hypervisor *xen, unsigned long num, ... ) { + char value[ 21 /* "18446744073709551615" + NUL */ ]; + va_list key; + int rc; + + /* Construct value */ + snprintf ( value, sizeof ( value ), "%ld", num ); + + /* Write value */ + va_start ( key, num ); + rc = xenstore_vwrite ( xen, value, key ); + va_end ( key ); + return rc; +} + +/** + * Delete XenStore value + * + * @v xen Xen hypervisor + * @v ... Key path components + * @ret rc Return status code + */ +__attribute__ (( sentinel )) int +xenstore_rm ( struct xen_hypervisor *xen, ... ) { + va_list key; + int rc; + + va_start ( key, xen ); + rc = xenstore_message ( xen, XS_RM, NULL, NULL, NULL, key ); + va_end ( key ); + return rc; +} + +/** + * Read XenStore directory + * + * @v xen Xen hypervisor + * @v children Child key names to fill in + * @v len Length of child key names to fill in + * @v ... Key path components + * @ret rc Return status code + */ +__attribute__ (( sentinel )) int +xenstore_directory ( struct xen_hypervisor *xen, char **children, size_t *len, + ... ) { + va_list key; + int rc; + + va_start ( key, len ); + rc = xenstore_message ( xen, XS_DIRECTORY, children, len, NULL, key ); + va_end ( key ); + return rc; +} + +/** + * Dump XenStore directory contents (for debugging) + * + * @v xen Xen hypervisor + * @v key Key + */ +void xenstore_dump ( struct xen_hypervisor *xen, const char *key ) { + char *value; + char *children; + char *child; + char *child_key; + size_t len; + int rc; + + /* Try to dump current key as a value */ + if ( ( rc = xenstore_read ( xen, &value, key, NULL ) ) == 0 ) { + DBGC ( xen, "%s = \"%s\"\n", key, value ); + free ( value ); + } + + /* Try to recurse into each child in turn */ + if ( ( rc = xenstore_directory ( xen, &children, &len, key, + NULL ) ) == 0 ) { + for ( child = children ; child < ( children + len ) ; + child += ( strlen ( child ) + 1 /* NUL */ ) ) { + + /* Construct child key */ + asprintf ( &child_key, "%s/%s", key, child ); + if ( ! child_key ) { + DBGC ( xen, "XENSTORE could not allocate child " + "key \"%s/%s\"\n", key, child ); + rc = -ENOMEM; + break; + } + + /* Recurse into child key, continuing on error */ + xenstore_dump ( xen, child_key ); + free ( child_key ); + } + free ( children ); + } +} diff --git a/roms/ipxe/src/net/eth_slow.c b/roms/ipxe/src/net/eth_slow.c index 69c38f30a..db54b55a4 100644 --- a/roms/ipxe/src/net/eth_slow.c +++ b/roms/ipxe/src/net/eth_slow.c @@ -167,7 +167,8 @@ static int eth_slow_lacp_rx ( struct io_buffer *iobuf, lacp->actor.key = htons ( 1 ); lacp->actor.port_priority = htons ( LACP_PORT_PRIORITY_MAX ); lacp->actor.port = htons ( 1 ); - lacp->actor.state = ( LACP_STATE_IN_SYNC | + lacp->actor.state = ( LACP_STATE_AGGREGATABLE | + LACP_STATE_IN_SYNC | LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING | ( lacp->partner.state & LACP_STATE_FAST ) ); diff --git a/roms/ipxe/src/net/ethernet.c b/roms/ipxe/src/net/ethernet.c index a2e565899..03978c2a8 100644 --- a/roms/ipxe/src/net/ethernet.c +++ b/roms/ipxe/src/net/ethernet.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> +#include <stdlib.h> #include <stdio.h> #include <string.h> #include <byteswap.h> @@ -113,6 +114,21 @@ void eth_init_addr ( const void *hw_addr, void *ll_addr ) { } /** + * Generate random Ethernet address + * + * @v hw_addr Generated hardware address + */ +void eth_random_addr ( void *hw_addr ) { + uint8_t *addr = hw_addr; + unsigned int i; + + for ( i = 0 ; i < ETH_ALEN ; i++ ) + addr[i] = random(); + addr[0] &= ~0x01; /* Clear multicast bit */ + addr[0] |= 0x02; /* Set locally-assigned bit */ +} + +/** * Transcribe Ethernet address * * @v ll_addr Link-layer address diff --git a/roms/ipxe/src/net/fcp.c b/roms/ipxe/src/net/fcp.c index 241b54638..9c36a4c72 100644 --- a/roms/ipxe/src/net/fcp.c +++ b/roms/ipxe/src/net/fcp.c @@ -551,7 +551,6 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd, struct fcp_device *fcpdev = fcpcmd->fcpdev; struct scsi_cmd *command = &fcpcmd->command; struct fcp_rsp *rsp = iobuf->data; - struct scsi_sense *sense; struct scsi_rsp response; int rc; @@ -607,8 +606,8 @@ static int fcpcmd_recv_rsp ( struct fcp_command *fcpcmd, if ( rsp->flags & FCP_RSP_RESIDUAL_UNDERRUN ) response.overrun = -response.overrun; } - if ( ( sense = fcp_rsp_sense_data ( rsp ) ) != NULL ) - memcpy ( &response.sense, sense, sizeof ( response.sense ) ); + scsi_parse_sense ( fcp_rsp_sense_data ( rsp ), + fcp_rsp_sense_data_len ( rsp ), &response.sense ); /* Free buffer before sending response, to minimise * out-of-memory errors. diff --git a/roms/ipxe/src/net/ipv6.c b/roms/ipxe/src/net/ipv6.c index f753751df..3c374168c 100644 --- a/roms/ipxe/src/net/ipv6.c +++ b/roms/ipxe/src/net/ipv6.c @@ -515,7 +515,8 @@ static int ipv6_tx ( struct io_buffer *iobuf, } if ( sin6_src && ! IN6_IS_ADDR_UNSPECIFIED ( &sin6_src->sin6_addr ) ) src = &sin6_src->sin6_addr; - memcpy ( &iphdr->src, src, sizeof ( iphdr->src ) ); + if ( src ) + memcpy ( &iphdr->src, src, sizeof ( iphdr->src ) ); /* Fix up checksums */ if ( trans_csum ) { @@ -900,7 +901,7 @@ static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) { const char *netdev_name; /* Identify network device, if applicable */ - if ( IN6_IS_ADDR_LINKLOCAL ( in ) ) { + if ( IN6_IS_ADDR_LINKLOCAL ( in ) || IN6_IS_ADDR_MULTICAST ( in ) ) { netdev = find_netdev_by_index ( sin6->sin6_scope_id ); netdev_name = ( netdev ? netdev->name : "UNKNOWN" ); } else { diff --git a/roms/ipxe/src/net/ndp.c b/roms/ipxe/src/net/ndp.c index 6450aa9f0..e62f7d5cb 100644 --- a/roms/ipxe/src/net/ndp.c +++ b/roms/ipxe/src/net/ndp.c @@ -120,7 +120,6 @@ static int ndp_tx_request ( struct net_device *netdev, sin6_src.sin6_family = AF_INET6; memcpy ( &sin6_src.sin6_addr, net_source, sizeof ( sin6_src.sin6_addr ) ); - sin6_src.sin6_scope_id = netdev->index; /* Construct multicast destination address */ memset ( &sin6_dest, 0, sizeof ( sin6_dest ) ); diff --git a/roms/ipxe/src/net/netdevice.c b/roms/ipxe/src/net/netdevice.c index a05d6610b..a55e6b7d7 100644 --- a/roms/ipxe/src/net/netdevice.c +++ b/roms/ipxe/src/net/netdevice.c @@ -50,6 +50,9 @@ struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); /** List of open network devices, in reverse order of opening */ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices ); +/** Network device index */ +static unsigned int netdev_index = 0; + /** Network polling profiler */ static struct profiler net_poll_profiler __profiler = { .name = "net.poll" }; @@ -597,24 +600,36 @@ struct net_device * alloc_netdev ( size_t priv_len ) { * devices. */ int register_netdev ( struct net_device *netdev ) { - static unsigned int ifindex = 0; struct ll_protocol *ll_protocol = netdev->ll_protocol; struct net_driver *driver; + struct net_device *duplicate; uint32_t seed; int rc; + /* Set initial link-layer address, if not already set */ + if ( ! netdev_has_ll_addr ( netdev ) ) { + ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); + } + + /* Reject network devices that are already available via a + * different hardware device. + */ + duplicate = find_netdev_by_ll_addr ( ll_protocol, netdev->ll_addr ); + if ( duplicate && ( duplicate->dev != netdev->dev ) ) { + DBGC ( netdev, "NETDEV rejecting duplicate (phys %s) of %s " + "(phys %s)\n", netdev->dev->name, duplicate->name, + duplicate->dev->name ); + rc = -EEXIST; + goto err_duplicate; + } + /* Record device index and create device name */ - netdev->index = ifindex++; + netdev->index = netdev_index++; if ( netdev->name[0] == '\0' ) { snprintf ( netdev->name, sizeof ( netdev->name ), "net%d", netdev->index ); } - /* Set initial link-layer address, if not already set */ - if ( ! netdev_has_ll_addr ( netdev ) ) { - ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); - } - /* Use least significant bits of the link-layer address to * improve the randomness of the (non-cryptographic) random * number generator. @@ -658,6 +673,7 @@ int register_netdev ( struct net_device *netdev ) { clear_settings ( netdev_settings ( netdev ) ); unregister_settings ( netdev_settings ( netdev ) ); err_register_settings: + err_duplicate: return rc; } @@ -764,6 +780,10 @@ void unregister_netdev ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name ); list_del ( &netdev->list ); netdev_put ( netdev ); + + /* Reset network device index if no devices remain */ + if ( list_empty ( &net_devices ) ) + netdev_index = 0; } /** Enable or disable interrupts @@ -847,6 +867,27 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type, } /** + * Get network device by link-layer address + * + * @v ll_protocol Link-layer protocol + * @v ll_addr Link-layer address + * @ret netdev Network device, or NULL + */ +struct net_device * find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol, + const void *ll_addr ) { + struct net_device *netdev; + + list_for_each_entry ( netdev, &net_devices, list ) { + if ( ( netdev->ll_protocol == ll_protocol ) && + ( memcmp ( netdev->ll_addr, ll_addr, + ll_protocol->ll_addr_len ) == 0 ) ) + return netdev; + } + + return NULL; +} + +/** * Get most recently opened network device * * @ret netdev Most recently opened network device, or NULL @@ -1039,7 +1080,7 @@ static unsigned int net_discard ( void ) { /* Discard first deferred packet */ list_del ( &iobuf->list ); - free ( iobuf ); + free_iob ( iobuf ); /* Report discard */ discarded++; diff --git a/roms/ipxe/src/net/oncrpc/nfs_open.c b/roms/ipxe/src/net/oncrpc/nfs_open.c index 349957ffe..c0dceb82f 100644 --- a/roms/ipxe/src/net/oncrpc/nfs_open.c +++ b/roms/ipxe/src/net/oncrpc/nfs_open.c @@ -40,6 +40,7 @@ #include <ipxe/oncrpc_iob.h> #include <ipxe/portmap.h> #include <ipxe/mount.h> +#include <ipxe/nfs_uri.h> /** @file * @@ -101,10 +102,7 @@ struct nfs_request { struct oncrpc_cred_sys auth_sys; char * hostname; - char * path; - char * mountpoint; - char * filename; - size_t filename_offset; + struct nfs_uri uri; struct nfs_fh readlink_fh; struct nfs_fh current_fh; @@ -127,8 +125,9 @@ static void nfs_free ( struct refcnt *refcnt ) { nfs = container_of ( refcnt, struct nfs_request, refcnt ); DBGC ( nfs, "NFS_OPEN %p freed\n", nfs ); + nfs_uri_free ( &nfs->uri ); + free ( nfs->hostname ); - free ( nfs->path ); free ( nfs->auth_sys.hostname ); free ( nfs ); } @@ -274,10 +273,10 @@ static void nfs_mount_step ( struct nfs_request *nfs ) { if ( nfs->mount_state == NFS_MOUNT_NONE ) { DBGC ( nfs, "NFS_OPEN %p MNT call (%s)\n", nfs, - nfs->mountpoint ); + nfs_uri_mountpoint ( &nfs->uri ) ); rc = mount_mnt ( &nfs->mount_intf, &nfs->mount_session, - nfs->mountpoint ); + nfs_uri_mountpoint ( &nfs->uri ) ); if ( rc != 0 ) goto err; @@ -289,7 +288,7 @@ static void nfs_mount_step ( struct nfs_request *nfs ) { DBGC ( nfs, "NFS_OPEN %p UMNT call\n", nfs ); rc = mount_umnt ( &nfs->mount_intf, &nfs->mount_session, - nfs->mountpoint ); + nfs_uri_mountpoint ( &nfs->uri ) ); if ( rc != 0 ) goto err; } @@ -303,7 +302,6 @@ static int nfs_mount_deliver ( struct nfs_request *nfs, struct io_buffer *io_buf, struct xfer_metadata *meta __unused ) { int rc; - char *sep; struct oncrpc_reply reply; struct mount_mnt_reply mnt_reply; @@ -318,19 +316,29 @@ static int nfs_mount_deliver ( struct nfs_request *nfs, DBGC ( nfs, "NFS_OPEN %p got MNT reply\n", nfs ); rc = mount_get_mnt_reply ( &mnt_reply, &reply ); if ( rc != 0 ) { - if ( mnt_reply.status != MNT3ERR_NOTDIR ) + switch ( mnt_reply.status ) { + case MNT3ERR_NOTDIR: + case MNT3ERR_NOENT: + case MNT3ERR_ACCES: + break; + + default: + goto err; + } + + if ( ! strcmp ( nfs_uri_mountpoint ( &nfs->uri ), + "/" ) ) goto err; - if ( strcmp ( nfs->mountpoint, "/" ) == 0 ) + if ( ( rc = nfs_uri_next_mountpoint ( &nfs->uri ) ) ) goto err; - sep = strrchr ( nfs->mountpoint, '/' ); - nfs->filename[-1] = '/'; - nfs->filename = sep + 1; - *sep = '\0'; + DBGC ( nfs, "NFS_OPEN %p MNT failed retrying with " \ + "%s\n", nfs, nfs_uri_mountpoint ( &nfs->uri ) ); + + nfs->mount_state--; + nfs_mount_step ( nfs ); - DBGC ( nfs, "NFS_OPEN %p ENOTDIR received retrying" \ - "with %s\n", nfs, nfs->mountpoint ); goto done; } @@ -358,22 +366,13 @@ done: static void nfs_step ( struct nfs_request *nfs ) { int rc; - char *path_component = NULL; + char *path_component; if ( ! xfer_window ( &nfs->nfs_intf ) ) return; if ( nfs->nfs_state == NFS_LOOKUP ) { - while ( path_component == NULL || path_component[0] == '\0') { - path_component = nfs->filename; - while ( *nfs->filename != '\0' ) { - nfs->filename_offset++; - if ( *nfs->filename++ == '/' ) { - *(nfs->filename - 1) = '\0'; - break; - } - } - } + path_component = nfs_uri_next_path_component ( &nfs->uri ); DBGC ( nfs, "NFS_OPEN %p LOOKUP call (%s)\n", nfs, path_component ); @@ -443,11 +442,11 @@ static int nfs_deliver ( struct nfs_request *nfs, if ( lookup_reply.ent_type == NFS_ATTR_SYMLINK ) { nfs->readlink_fh = lookup_reply.fh; - nfs->nfs_state = NFS_READLINK; + nfs->nfs_state = NFS_READLINK; } else { nfs->current_fh = lookup_reply.fh; - if ( nfs->filename[0] == '\0' ) + if ( nfs->uri.lookup_pos[0] == '\0' ) nfs->nfs_state = NFS_READ; else nfs->nfs_state--; @@ -458,7 +457,7 @@ static int nfs_deliver ( struct nfs_request *nfs, } if ( nfs->nfs_state == NFS_READLINK_SENT ) { - char *new_filename; + char *path; struct nfs_readlink_reply readlink_reply; DBGC ( nfs, "NFS_OPEN %p got READLINK reply\n", nfs ); @@ -468,46 +467,23 @@ static int nfs_deliver ( struct nfs_request *nfs, goto err; if ( readlink_reply.path_len == 0 ) - return -EINVAL; - - if ( readlink_reply.path[0] == '/' ) { - if ( strncmp ( readlink_reply.path, nfs->mountpoint, - strlen ( nfs->mountpoint ) ) != 0 ) - return -EINVAL; - - /* The mountpoint part of the path is ended by a '/' */ - if ( strlen ( nfs->mountpoint ) != - readlink_reply.path_len ) { - readlink_reply.path += 1; - readlink_reply.path_len -= 1; - } - - /* We are considering the last part of the absolute - * path as a relative path from the mountpoint. - */ - readlink_reply.path += strlen ( nfs->mountpoint ); - readlink_reply.path_len -= strlen ( nfs->mountpoint ); + { + rc = -EINVAL; + goto err; } - new_filename = malloc ( readlink_reply.path_len + - strlen ( nfs->filename ) + 2 ); - if ( ! new_filename ) { + if ( ! ( path = strndup ( readlink_reply.path, + readlink_reply.path_len ) ) ) + { rc = -ENOMEM; goto err; } - memcpy ( new_filename, readlink_reply.path, - readlink_reply.path_len ); - strcpy ( new_filename + readlink_reply.path_len + 1, - nfs->filename ); - new_filename[readlink_reply.path_len] = '/'; - - free ( nfs->filename - nfs->filename_offset ); - nfs->filename = new_filename; - nfs->filename_offset = 0; + nfs_uri_symlink ( &nfs->uri, path ); + free ( path ); - DBGC ( nfs, "NFS_OPEN %p new filename: %s\n", nfs, - nfs->filename ); + DBGC ( nfs, "NFS_OPEN %p new path: %s\n", nfs, + nfs->uri.path ); nfs->nfs_state = NFS_LOOKUP; nfs_step ( nfs ); @@ -626,30 +602,21 @@ static int nfs_parse_uri ( struct nfs_request *nfs, const struct uri *uri ) { if ( ! uri || ! uri->host || ! uri->path ) return -EINVAL; - if ( ! ( nfs->path = strdup ( uri->path ) ) ) - return -ENOMEM; + if ( ( rc = nfs_uri_init ( &nfs->uri, uri ) ) != 0 ) + return rc; if ( ! ( nfs->hostname = strdup ( uri->host ) ) ) { rc = -ENOMEM; goto err_hostname; } - nfs->filename = basename ( nfs->path ); - nfs->mountpoint = dirname ( nfs->path ); - - if ( nfs->filename[0] == '\0' ) - goto err_filename; - - DBGC ( nfs, "NFS_OPEN %p URI parsed: (mountpoint=%s, filename=%s)\n", - nfs, nfs->mountpoint, nfs->filename ); + DBGC ( nfs, "NFS_OPEN %p URI parsed: (mountpoint=%s, path=%s)\n", + nfs, nfs_uri_mountpoint ( &nfs->uri), nfs->uri.path ); return 0; -err_filename: - rc = -EINVAL; - free ( nfs->hostname ); err_hostname: - free ( nfs->path ); + nfs_uri_free ( &nfs->uri ); return rc; } @@ -686,6 +653,9 @@ static int nfs_open ( struct interface *xfer, struct uri *uri ) { mount_init_session ( &nfs->mount_session, &nfs->auth_sys.credential ); nfs_init_session ( &nfs->nfs_session, &nfs->auth_sys.credential ); + DBGC ( nfs, "NFS_OPEN %p connecting to port mapper (%s:%d)...\n", nfs, + nfs->hostname, PORTMAP_PORT ); + rc = nfs_connect ( &nfs->pm_intf, PORTMAP_PORT, nfs->hostname ); if ( rc != 0 ) goto err_connect; @@ -699,6 +669,8 @@ static int nfs_open ( struct interface *xfer, struct uri *uri ) { err_connect: free ( nfs->auth_sys.hostname ); err_cred: + nfs_uri_free ( &nfs->uri ); + free ( nfs->hostname ); err_uri: free ( nfs ); return rc; diff --git a/roms/ipxe/src/net/oncrpc/nfs_uri.c b/roms/ipxe/src/net/oncrpc/nfs_uri.c new file mode 100644 index 000000000..c4c3f21e9 --- /dev/null +++ b/roms/ipxe/src/net/oncrpc/nfs_uri.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2014 Marin Hannache <ipxe@mareo.fr>. + * + * 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. + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <libgen.h> +#include <ipxe/nfs_uri.h> + +/** @file + * + * Network File System protocol URI handling functions + * + */ + +int nfs_uri_init ( struct nfs_uri *nfs_uri, const struct uri *uri ) { + if ( ! ( nfs_uri->mountpoint = strdup ( uri->path ) ) ) + return -ENOMEM; + + nfs_uri->filename = basename ( nfs_uri->mountpoint ); + if ( strchr ( uri->path, '/' ) != NULL ) + nfs_uri->mountpoint = dirname ( nfs_uri->mountpoint ); + + if ( nfs_uri->filename[0] == '\0' ) { + free ( nfs_uri->mountpoint ); + return -EINVAL; + } + + if ( ! ( nfs_uri->path = strdup ( nfs_uri->filename ) ) ) { + free ( nfs_uri->mountpoint ); + return -ENOMEM; + } + nfs_uri->lookup_pos = nfs_uri->path; + + return 0; +} + +char *nfs_uri_mountpoint ( const struct nfs_uri *uri ) { + if ( uri->mountpoint + 1 == uri->filename || + uri->mountpoint == uri->filename ) + return "/"; + + return uri->mountpoint; +} + +int nfs_uri_next_mountpoint ( struct nfs_uri *uri ) { + char *sep; + + if ( uri->mountpoint + 1 == uri->filename || + uri->mountpoint == uri->filename ) + return -ENOENT; + + sep = strrchr ( uri->mountpoint, '/' ); + uri->filename[-1] = '/'; + uri->filename = sep + 1; + *sep = '\0'; + + free ( uri->path ); + if ( ! ( uri->path = strdup ( uri->filename ) ) ) { + uri->path = NULL; + return -ENOMEM; + } + uri->lookup_pos = uri->path; + + return 0; +} + +int nfs_uri_symlink ( struct nfs_uri *uri, const char *symlink ) { + size_t len; + char *new_path; + + if ( ! uri->path ) + return -EINVAL; + + if ( *symlink == '/' ) + { + if ( strncmp ( symlink, uri->mountpoint, + strlen ( uri->mountpoint ) ) != 0 ) + return -EINVAL; + + len = strlen ( uri->lookup_pos ) + strlen ( symlink ) - \ + strlen ( uri->mountpoint ); + if ( ! ( new_path = malloc ( len * sizeof ( char ) ) ) ) + return -ENOMEM; + + strcpy ( new_path, symlink + strlen ( uri->mountpoint ) ); + strcpy ( new_path + strlen ( new_path ), uri->lookup_pos ); + + } else { + len = strlen ( uri->lookup_pos ) + strlen ( symlink ); + if ( ! ( new_path = malloc ( len * sizeof ( char ) ) ) ) + return -ENOMEM; + + + strcpy ( new_path, symlink ); + strcpy ( new_path + strlen ( new_path ), uri->lookup_pos ); + } + + free ( uri->path ); + uri->lookup_pos = uri->path = new_path; + + return 0; +} + +char *nfs_uri_next_path_component ( struct nfs_uri *uri ) { + char *sep; + char *start; + + if ( ! uri->path ) + return NULL; + + for ( sep = uri->lookup_pos ; *sep != '\0' && *sep != '/'; sep++ ) + ; + + start = uri->lookup_pos; + uri->lookup_pos = sep; + if ( *sep != '\0' ) { + uri->lookup_pos++; + *sep = '\0'; + if ( *start == '\0' ) + return nfs_uri_next_path_component ( uri ); + } + + return start; +} + +void nfs_uri_free ( struct nfs_uri *uri ) { + free ( uri->mountpoint ); + free ( uri->path ); + uri->mountpoint = NULL; + uri->path = NULL; +} diff --git a/roms/ipxe/src/net/tcp.c b/roms/ipxe/src/net/tcp.c index 1c48769ac..987cb63e1 100644 --- a/roms/ipxe/src/net/tcp.c +++ b/roms/ipxe/src/net/tcp.c @@ -16,6 +16,7 @@ #include <ipxe/uri.h> #include <ipxe/netdevice.h> #include <ipxe/profile.h> +#include <ipxe/process.h> #include <ipxe/tcpip.h> #include <ipxe/tcp.h> @@ -107,6 +108,8 @@ struct tcp_connection { struct list_head tx_queue; /** Receive queue */ struct list_head rx_queue; + /** Transmission process */ + struct process process; /** Retransmission timer */ struct retry_timer timer; /** Shutdown (TIME_WAIT) timer */ @@ -166,6 +169,7 @@ static struct profiler tcp_rx_profiler __profiler = { .name = "tcp.rx" }; static struct profiler tcp_xfer_profiler __profiler = { .name = "tcp.xfer" }; /* Forward declarations */ +static struct process_descriptor tcp_process_desc; static struct interface_descriptor tcp_xfer_desc; static void tcp_expired ( struct retry_timer *timer, int over ); static void tcp_wait_expired ( struct retry_timer *timer, int over ); @@ -273,6 +277,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer, DBGC ( tcp, "TCP %p allocated\n", tcp ); ref_init ( &tcp->refcnt, NULL ); intf_init ( &tcp->xfer, &tcp_xfer_desc, &tcp->refcnt ); + process_init_stopped ( &tcp->process, &tcp_process_desc, &tcp->refcnt ); timer_init ( &tcp->timer, tcp_expired, &tcp->refcnt ); timer_init ( &tcp->wait, tcp_wait_expired, &tcp->refcnt ); tcp->prev_tcp_state = TCP_CLOSED; @@ -369,6 +374,7 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) { pending_put ( &tcp->pending_flags ); /* Remove from list and drop reference */ + process_del ( &tcp->process ); stop_timer ( &tcp->timer ); stop_timer ( &tcp->wait ); list_del ( &tcp->list ); @@ -497,7 +503,7 @@ static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len, * will have been started if necessary, and so the stack will * eventually attempt to retransmit the failed packet. */ -static int tcp_xmit ( struct tcp_connection *tcp ) { +static void tcp_xmit ( struct tcp_connection *tcp ) { struct io_buffer *iobuf; struct tcp_header *tcphdr; struct tcp_mss_option *mssopt; @@ -517,7 +523,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { /* If retransmission timer is already running, do nothing */ if ( timer_running ( &tcp->timer ) ) - return 0; + return; /* Calculate both the actual (payload) and sequence space * lengths that we wish to transmit. @@ -537,7 +543,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { /* If we have nothing to transmit, stop now */ if ( ( seq_len == 0 ) && ! ( tcp->flags & TCP_ACK_PENDING ) ) - return 0; + return; /* If we are transmitting anything that requires * acknowledgement (i.e. consumes sequence space), start the @@ -553,7 +559,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x " "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ), tcp->rcv_ack ); - return -ENOMEM; + return; } iob_reserve ( iobuf, TCP_MAX_HEADER_LEN ); @@ -620,16 +626,19 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { DBGC ( tcp, "TCP %p could not transmit %08x..%08x %08x: %s\n", tcp, tcp->snd_seq, ( tcp->snd_seq + tcp->snd_sent ), tcp->rcv_ack, strerror ( rc ) ); - return rc; + return; } /* Clear ACK-pending flag */ tcp->flags &= ~TCP_ACK_PENDING; profile_stop ( &tcp_tx_profiler ); - return 0; } +/** TCP process descriptor */ +static struct process_descriptor tcp_process_desc = + PROC_DESC_ONCE ( struct tcp_connection, process, tcp_xmit ); + /** * Retransmission timer expired * @@ -1272,8 +1281,16 @@ static int tcp_rx ( struct io_buffer *iobuf, /* Dump out any state change as a result of the received packet */ tcp_dump_state ( tcp ); - /* Send out any pending data */ - tcp_xmit ( tcp ); + /* Schedule transmission of ACK (and any pending data). If we + * have received any out-of-order packets (i.e. if the receive + * queue remains non-empty after processing) then send the ACK + * immediately in order to trigger Fast Retransmission. + */ + if ( list_empty ( &tcp->rx_queue ) ) { + process_add ( &tcp->process ); + } else { + tcp_xmit ( tcp ); + } /* If this packet was the last we expect to receive, set up * timer to expire and cause the connection to be freed. diff --git a/roms/ipxe/src/net/tcp/iscsi.c b/roms/ipxe/src/net/tcp/iscsi.c index a6fcd251b..03c6d0f23 100644 --- a/roms/ipxe/src/net/tcp/iscsi.c +++ b/roms/ipxe/src/net/tcp/iscsi.c @@ -412,11 +412,12 @@ static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi, = &iscsi->rx_bhs.scsi_response; struct scsi_rsp rsp; uint32_t residual_count; + size_t data_len; int rc; /* Buffer up the PDU data */ if ( ( rc = iscsi_rx_buffered_data ( iscsi, data, len ) ) != 0 ) { - DBGC ( iscsi, "iSCSI %p could not buffer login response: %s\n", + DBGC ( iscsi, "iSCSI %p could not buffer SCSI response: %s\n", iscsi, strerror ( rc ) ); return rc; } @@ -432,9 +433,11 @@ static int iscsi_rx_scsi_response ( struct iscsi_session *iscsi, } else if ( response->flags & ISCSI_DATA_FLAG_UNDERFLOW ) { rsp.overrun = -(residual_count); } - if ( ISCSI_DATA_LEN ( response->lengths ) ) - memcpy ( &rsp.sense, ( iscsi->rx_buffer + 2 ), - sizeof ( rsp.sense ) ); + data_len = ISCSI_DATA_LEN ( response->lengths ); + if ( data_len ) { + scsi_parse_sense ( ( iscsi->rx_buffer + 2 ), ( data_len - 2 ), + &rsp.sense ); + } iscsi_rx_buffered_data_done ( iscsi ); /* Check for errors */ diff --git a/roms/ipxe/src/net/tcp/oncrpc.c b/roms/ipxe/src/net/tcp/oncrpc.c index cd33ece02..6469867e9 100644 --- a/roms/ipxe/src/net/tcp/oncrpc.c +++ b/roms/ipxe/src/net/tcp/oncrpc.c @@ -37,7 +37,7 @@ #include <ipxe/oncrpc_iob.h> #include <ipxe/init.h> #include <ipxe/settings.h> -#include <config/general.h> +#include <ipxe/version.h> /** @file * @@ -88,7 +88,7 @@ int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys ) { fetch_string_setting_copy ( NULL, &hostname_setting, &auth_sys->hostname ); if ( ! auth_sys->hostname ) - if ( ! ( auth_sys->hostname = strdup ( PRODUCT_SHORT_NAME ) ) ) + if ( ! ( auth_sys->hostname = strdup ( product_short_name ) ) ) return -ENOMEM; auth_sys->uid = fetch_uintz_setting ( NULL, &uid_setting ); diff --git a/roms/ipxe/src/net/udp/dhcp.c b/roms/ipxe/src/net/udp/dhcp.c index e6d3eddff..04fad04c2 100644 --- a/roms/ipxe/src/net/udp/dhcp.c +++ b/roms/ipxe/src/net/udp/dhcp.c @@ -842,53 +842,6 @@ static struct dhcp_session_state dhcp_state_pxebs = { */ /** - * Construct DHCP client hardware address field and broadcast flag - * - * @v netdev Network device - * @v chaddr Hardware address buffer - * @v flags Flags to set (or NULL) - * @ret hlen Hardware address length - */ -unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr, - uint16_t *flags ) { - struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct dhcphdr *dhcphdr; - int rc; - - /* If the link-layer address cannot fit into the chaddr field - * (as is the case for IPoIB) then try using the Ethernet- - * compatible link-layer address. If we do this, set the - * broadcast flag, since chaddr then does not represent a - * valid link-layer address for the return path. - * - * If we cannot produce an Ethernet-compatible link-layer - * address, try using the hardware address. - * - * If even the hardware address is too large, use an empty - * chaddr field and set the broadcast flag. - * - * This goes against RFC4390, but RFC4390 mandates that we use - * a DHCP client identifier that conforms with RFC4361, which - * we cannot do without either persistent (NIC-independent) - * storage, or by eliminating the hardware address completely - * from the DHCP packet, which seems unfriendly to users. - */ - if ( ll_protocol->ll_addr_len <= sizeof ( dhcphdr->chaddr ) ) { - memcpy ( chaddr, netdev->ll_addr, ll_protocol->ll_addr_len ); - return ll_protocol->ll_addr_len; - } - if ( flags ) - *flags |= htons ( BOOTP_FL_BROADCAST ); - if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, chaddr ) ) == 0 ) - return ETH_ALEN; - if ( ll_protocol->hw_addr_len <= sizeof ( dhcphdr->chaddr ) ) { - memcpy ( chaddr, netdev->hw_addr, ll_protocol->hw_addr_len ); - return ll_protocol->hw_addr_len; - } - return 0; -} - -/** * Create a DHCP packet * * @v dhcppkt DHCP packet structure to fill in @@ -1153,6 +1106,8 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) { static int dhcp_deliver ( struct dhcp_session *dhcp, struct io_buffer *iobuf, struct xfer_metadata *meta ) { + struct net_device *netdev = dhcp->netdev; + struct ll_protocol *ll_protocol = netdev->ll_protocol; struct sockaddr_in *peer; size_t data_len; struct dhcp_packet *dhcppkt; @@ -1203,9 +1158,21 @@ static int dhcp_deliver ( struct dhcp_session *dhcp, goto err_xid; }; + /* Check for matching client hardware address */ + if ( memcmp ( dhcphdr->chaddr, netdev->ll_addr, + ll_protocol->ll_addr_len ) != 0 ) { + DBGC ( dhcp, "DHCP %p %s from %s:%d has bad chaddr %s\n", + dhcp, dhcp_msgtype_name ( msgtype ), + inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ), + ll_protocol->ntoa ( dhcphdr->chaddr ) ); + rc = -EINVAL; + goto err_chaddr; + } + /* Handle packet based on current state */ dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id ); + err_chaddr: err_xid: dhcppkt_put ( dhcppkt ); err_alloc_dhcppkt: diff --git a/roms/ipxe/src/net/udp/dhcpv6.c b/roms/ipxe/src/net/udp/dhcpv6.c index cbc8d794a..f7736d08e 100644 --- a/roms/ipxe/src/net/udp/dhcpv6.c +++ b/roms/ipxe/src/net/udp/dhcpv6.c @@ -924,7 +924,6 @@ int start_dhcpv6 ( struct interface *job, struct net_device *netdev, /* Construct client and server addresses */ memset ( &addresses, 0, sizeof ( addresses ) ); addresses.client.sin6.sin6_family = AF_INET6; - addresses.client.sin6.sin6_scope_id = netdev->index; addresses.client.sin6.sin6_port = htons ( DHCPV6_CLIENT_PORT ); addresses.server.sin6.sin6_family = AF_INET6; ipv6_all_dhcp_relay_and_servers ( &addresses.server.sin6.sin6_addr ); diff --git a/roms/ipxe/src/net/udp/syslog.c b/roms/ipxe/src/net/udp/syslog.c index d51737125..d65d19ab8 100644 --- a/roms/ipxe/src/net/udp/syslog.c +++ b/roms/ipxe/src/net/udp/syslog.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> #include <stdlib.h> +#include <ctype.h> #include <byteswap.h> #include <ipxe/xfer.h> #include <ipxe/open.h> @@ -91,15 +92,15 @@ static char *syslog_domain; */ int syslog_send ( struct interface *xfer, unsigned int severity, const char *message, const char *terminator ) { + const char *hostname = ( syslog_hostname ? syslog_hostname : "" ); + const char *domain = ( ( hostname[0] && syslog_domain ) ? + syslog_domain : "" ); return xfer_printf ( xfer, "<%d>%s%s%s%sipxe: %s%s", SYSLOG_PRIORITY ( SYSLOG_DEFAULT_FACILITY, - severity ), - ( syslog_hostname ? syslog_hostname : "" ), - ( syslog_domain ? "." : "" ), - ( syslog_domain ? syslog_domain : "" ), - ( ( syslog_hostname || syslog_domain ) ? " " : ""), - message, terminator ); + severity ), hostname, + ( domain[0] ? "." : "" ), domain, + ( hostname[0] ? " " : "" ), message, terminator ); } /****************************************************************************** @@ -212,6 +213,28 @@ const struct setting syslog6_setting __setting ( SETTING_MISC, syslog6 ) = { }; /** + * Strip invalid characters from host/domain name + * + * @v name Name to strip + */ +static void syslog_fix_name ( char *name ) { + char *fixed = name; + int c; + + /* Do nothing if name does not exist */ + if ( ! name ) + return; + + /* Strip any non-printable or whitespace characters from the name */ + do { + c = *(name++); + *fixed = c; + if ( isprint ( c ) && ! isspace ( c ) ) + fixed++; + } while ( c ); +} + +/** * Apply syslog settings * * @ret rc Return status code @@ -223,8 +246,10 @@ static int apply_syslog_settings ( void ) { /* Fetch hostname and domain name */ free ( syslog_hostname ); fetch_string_setting_copy ( NULL, &hostname_setting, &syslog_hostname ); + syslog_fix_name ( syslog_hostname ); free ( syslog_domain ); fetch_string_setting_copy ( NULL, &domain_setting, &syslog_domain ); + syslog_fix_name ( syslog_domain ); /* Fetch log server */ syslog_console.disabled = CONSOLE_DISABLED; diff --git a/roms/ipxe/src/tests/ipv6_test.c b/roms/ipxe/src/tests/ipv6_test.c index 4de310ab0..e16fc7c3d 100644 --- a/roms/ipxe/src/tests/ipv6_test.c +++ b/roms/ipxe/src/tests/ipv6_test.c @@ -37,6 +37,30 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Define inline IPv6 address */ #define IPV6(...) { __VA_ARGS__ } +/** The unspecified IPv6 address */ +static const struct in6_addr sample_unspecified = { + .s6_addr = IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), +}; + +/** A sample link-local IPv6 address */ +static const struct in6_addr sample_link_local = { + .s6_addr = IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45 ), +}; + +/** A sample global IPv6 address */ +static const struct in6_addr sample_global = { + .s6_addr = IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, + 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45 ), +}; + +/** A sample multicast IPv6 address */ +static const struct in6_addr sample_multicast = { + .s6_addr = IPV6 ( 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), +}; + /** * Report an inet6_ntoa() test result * @@ -97,6 +121,20 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ static void ipv6_test_exec ( void ) { + /* Address testing macros */ + ok ( IN6_IS_ADDR_UNSPECIFIED ( &sample_unspecified ) ); + ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_link_local ) ); + ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_global ) ); + ok ( ! IN6_IS_ADDR_UNSPECIFIED ( &sample_multicast ) ); + ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_unspecified ) ); + ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_link_local ) ); + ok ( ! IN6_IS_ADDR_MULTICAST ( &sample_global ) ); + ok ( IN6_IS_ADDR_MULTICAST ( &sample_multicast ) ); + ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_unspecified ) ); + ok ( IN6_IS_ADDR_LINKLOCAL ( &sample_link_local ) ); + ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_global ) ); + ok ( ! IN6_IS_ADDR_LINKLOCAL ( &sample_multicast ) ); + /* inet6_ntoa() tests */ inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45 ), diff --git a/roms/ipxe/src/tests/ocsp_test.c b/roms/ipxe/src/tests/ocsp_test.c index 24405db80..a318c185a 100644 --- a/roms/ipxe/src/tests/ocsp_test.c +++ b/roms/ipxe/src/tests/ocsp_test.c @@ -825,6 +825,253 @@ CERTIFICATE ( startssl_crt, 0x1c, 0xec, 0xc2, 0x1c, 0xc5, 0xc2, 0xf5, 0x67, 0x48, 0xa7, 0x11, 0x01, 0x69, 0x83, 0xfd, 0x8e ) ); +/* + * subject RapidSSL SHA256 CA - G3 + * issuer GeoTrust Global CA + */ +CERTIFICATE ( rapidssl_crt, + DATA ( 0x30, 0x82, 0x04, 0x25, 0x30, 0x82, 0x03, 0x0d, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x03, 0x02, 0x3a, 0x77, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x30, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, + 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x43, + 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x38, 0x32, + 0x39, 0x32, 0x31, 0x33, 0x39, 0x33, 0x32, 0x5a, 0x17, 0x0d, + 0x32, 0x32, 0x30, 0x35, 0x32, 0x30, 0x32, 0x31, 0x33, 0x39, + 0x33, 0x32, 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, + 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, + 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xaf, + 0x54, 0x9b, 0xd9, 0x58, 0x5d, 0x1e, 0x2c, 0x56, 0xc6, 0xd5, + 0xe8, 0x7f, 0xf4, 0x7d, 0x16, 0x03, 0xff, 0xd0, 0x8b, 0x5a, + 0xe4, 0x8e, 0xa7, 0xdd, 0x54, 0x2e, 0xd4, 0x04, 0xc0, 0x5d, + 0x98, 0x9c, 0x8d, 0x90, 0x0f, 0xbc, 0x10, 0x65, 0x5f, 0xda, + 0x9a, 0xd6, 0x44, 0x7c, 0xc0, 0x9f, 0xb5, 0xe9, 0x4a, 0x8c, + 0x0b, 0x06, 0x43, 0x04, 0xbb, 0xf4, 0x96, 0xe2, 0x26, 0xf6, + 0x61, 0x01, 0x91, 0x66, 0x31, 0x22, 0xc3, 0x34, 0x34, 0x5f, + 0x3f, 0x3f, 0x91, 0x2f, 0x44, 0x5f, 0xdc, 0xc7, 0x14, 0xb6, + 0x03, 0x9f, 0x86, 0x4b, 0x0e, 0xa3, 0xff, 0xa0, 0x80, 0x02, + 0x83, 0xc3, 0xd3, 0x1f, 0x69, 0x52, 0xd6, 0x9d, 0x64, 0x0f, + 0xc9, 0x83, 0xe7, 0x1b, 0xc4, 0x70, 0xac, 0x94, 0xe7, 0xc3, + 0xa4, 0x6a, 0x2c, 0xbd, 0xb8, 0x9e, 0x69, 0xd8, 0xbe, 0x0a, + 0x8f, 0x16, 0x63, 0x5a, 0x68, 0x71, 0x80, 0x7b, 0x30, 0xde, + 0x15, 0x04, 0xbf, 0xcc, 0xd3, 0xbf, 0x3e, 0x48, 0x05, 0x55, + 0x7a, 0xb3, 0xd7, 0x10, 0x0c, 0x03, 0xfc, 0x9b, 0xfd, 0x08, + 0xa7, 0x8c, 0x8c, 0xdb, 0xa7, 0x8e, 0xf1, 0x1e, 0x63, 0xdc, + 0xb3, 0x01, 0x2f, 0x7f, 0xaf, 0x57, 0xc3, 0x3c, 0x48, 0xa7, + 0x83, 0x68, 0x21, 0xa7, 0x2f, 0xe7, 0xa7, 0x3f, 0xf0, 0xb5, + 0x0c, 0xfc, 0xf5, 0x84, 0xd1, 0x53, 0xbc, 0x0e, 0x72, 0x4f, + 0x60, 0x0c, 0x42, 0xb8, 0x98, 0xad, 0x19, 0x88, 0x57, 0xd7, + 0x04, 0xec, 0x87, 0xbf, 0x7e, 0x87, 0x4e, 0xa3, 0x21, 0xf9, + 0x53, 0xfd, 0x36, 0x98, 0x48, 0x8d, 0xd6, 0xf8, 0xbb, 0x48, + 0xf2, 0x29, 0xc8, 0x64, 0xd1, 0xcc, 0x54, 0x48, 0x53, 0x8b, + 0xaf, 0xb7, 0x65, 0x1e, 0xbf, 0x29, 0x33, 0x29, 0xd9, 0x29, + 0x60, 0x48, 0xf8, 0xff, 0x91, 0xbc, 0x57, 0x58, 0xe5, 0x35, + 0x2e, 0xbb, 0x69, 0xb6, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, 0x19, 0x30, 0x1f, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0xc0, 0x7a, 0x98, 0x68, 0x8d, 0x89, 0xfb, 0xab, 0x05, + 0x64, 0x0c, 0x11, 0x7d, 0xaa, 0x7d, 0x65, 0xb8, 0xca, 0xcc, + 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0xc3, 0x9c, 0xf3, 0xfc, 0xd3, 0x46, 0x08, 0x34, + 0xbb, 0xce, 0x46, 0x7f, 0xa0, 0x7c, 0x5b, 0xf3, 0xe2, 0x08, + 0xcb, 0x59, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x35, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x2e, 0x30, 0x2c, 0x30, + 0x2a, 0xa0, 0x28, 0xa0, 0x26, 0x86, 0x24, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, + 0x2f, 0x67, 0x74, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x2e, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x22, 0x30, 0x20, 0x30, + 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, + 0x01, 0x86, 0x12, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x67, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, + 0x6d, 0x30, 0x4c, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, + 0x30, 0x43, 0x30, 0x41, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, + 0x86, 0xf8, 0x45, 0x01, 0x07, 0x36, 0x30, 0x33, 0x30, 0x31, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, + 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xa3, + 0x58, 0x1e, 0xc6, 0x43, 0x32, 0xac, 0xac, 0x2f, 0x93, 0x78, + 0xb7, 0xea, 0xae, 0x54, 0x40, 0x47, 0x2d, 0x7e, 0x78, 0x8d, + 0x50, 0xf6, 0xf8, 0x66, 0xac, 0xd6, 0x4f, 0x73, 0xd6, 0x44, + 0xef, 0xaf, 0x0b, 0xcc, 0x5b, 0xc1, 0xf4, 0x4f, 0x9a, 0x8f, + 0x49, 0x7e, 0x60, 0xaf, 0xc2, 0x27, 0xc7, 0x16, 0xf1, 0xfb, + 0x93, 0x81, 0x90, 0xa9, 0x7c, 0xef, 0x6f, 0x7e, 0x6e, 0x45, + 0x94, 0x16, 0x84, 0xbd, 0xec, 0x49, 0xf1, 0xc4, 0x0e, 0xf4, + 0xaf, 0x04, 0x59, 0x83, 0x87, 0x0f, 0x2c, 0x3b, 0x97, 0xc3, + 0x5a, 0x12, 0x9b, 0x7b, 0x04, 0x35, 0x7b, 0xa3, 0x95, 0x33, + 0x08, 0x7b, 0x93, 0x71, 0x22, 0x42, 0xb3, 0xa9, 0xd9, 0x6f, + 0x4f, 0x81, 0x92, 0xfc, 0x07, 0xb6, 0x79, 0xbc, 0x84, 0x4a, + 0x9d, 0x77, 0x09, 0xf1, 0xc5, 0x89, 0xf2, 0xf0, 0xb4, 0x9c, + 0x54, 0xaa, 0x12, 0x7b, 0x0d, 0xba, 0x4f, 0xef, 0x93, 0x19, + 0xec, 0xef, 0x7d, 0x4e, 0x61, 0xa3, 0x8e, 0x76, 0x9c, 0x59, + 0xcf, 0x8c, 0x94, 0xb1, 0x84, 0x97, 0xf7, 0x1a, 0xb9, 0x07, + 0xb8, 0xb2, 0xc6, 0x4f, 0x13, 0x79, 0xdb, 0xbf, 0x4f, 0x51, + 0x1b, 0x7f, 0x69, 0x0d, 0x51, 0x2a, 0xc1, 0xd6, 0x15, 0xff, + 0x37, 0x51, 0x34, 0x65, 0x51, 0xf4, 0x1e, 0xbe, 0x38, 0x6a, + 0xec, 0x0e, 0xab, 0xbf, 0x3d, 0x7b, 0x39, 0x05, 0x7b, 0xf4, + 0xf3, 0xfb, 0x1a, 0xa1, 0xd0, 0xc8, 0x7e, 0x4e, 0x64, 0x8d, + 0xcd, 0x8c, 0x61, 0x55, 0x90, 0xfe, 0x3a, 0xca, 0x5d, 0x25, + 0x0f, 0xf8, 0x1d, 0xa3, 0x4a, 0x74, 0x56, 0x4f, 0x1a, 0x55, + 0x40, 0x70, 0x75, 0x25, 0xa6, 0x33, 0x2e, 0xba, 0x4b, 0xa5, + 0x5d, 0x53, 0x9a, 0x0d, 0x30, 0xe1, 0x8d, 0x5f, 0x61, 0x2c, + 0xaf, 0xcc, 0xef, 0xb0, 0x99, 0xa1, 0x80, 0xff, 0x0b, 0xf2, + 0x62, 0x4c, 0x70, 0x26, 0x98 ), + FINGERPRINT ( 0xbc, 0x3f, 0x03, 0xa4, 0x36, 0x24, 0x0e, 0xdb, + 0xa5, 0xf8, 0x37, 0x14, 0xf6, 0xf6, 0x77, 0xe3, + 0x4b, 0x37, 0xf9, 0xb1, 0xf0, 0xc0, 0x8c, 0x1e, + 0x55, 0x8d, 0x98, 0x1e, 0x27, 0x9e, 0x82, 0x09 ) ); + +/* + * subject *.vultr.com + * issuer RapidSSL SHA256 CA - G3 + */ +CERTIFICATE ( vultr_crt, + DATA ( 0x30, 0x82, 0x04, 0xa8, 0x30, 0x82, 0x03, 0x90, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x03, 0x00, 0x95, 0x4d, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x16, + 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x47, + 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, + 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x43, + 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x34, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x31, + 0x32, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x32, 0x32, + 0x32, 0x31, 0x39, 0x32, 0x39, 0x31, 0x30, 0x5a, 0x30, 0x81, + 0x8f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x0a, 0x47, 0x54, 0x36, 0x32, 0x30, 0x37, 0x39, 0x37, + 0x32, 0x31, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65, 0x20, 0x77, 0x77, 0x77, + 0x2e, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, + 0x29, 0x31, 0x33, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x13, 0x26, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x2d, + 0x20, 0x52, 0x61, 0x70, 0x69, 0x64, 0x53, 0x53, 0x4c, 0x28, + 0x52, 0x29, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x0b, 0x2a, 0x2e, 0x76, 0x75, 0x6c, 0x74, 0x72, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9f, 0xa8, 0x2e, + 0x65, 0x41, 0x05, 0xec, 0xef, 0x69, 0x92, 0xf6, 0xd3, 0x53, + 0x4f, 0xd4, 0x8e, 0xd3, 0x49, 0x8c, 0xc7, 0x85, 0x6d, 0xb0, + 0x71, 0xe0, 0x28, 0x04, 0x80, 0x85, 0x82, 0x3e, 0x3f, 0xdb, + 0x0c, 0xed, 0xcd, 0x2b, 0x04, 0xc8, 0x67, 0x15, 0x8c, 0x25, + 0xd6, 0x7a, 0x54, 0x67, 0x94, 0xbe, 0x33, 0x12, 0x33, 0x88, + 0xfe, 0x5d, 0x1d, 0x36, 0x62, 0x4e, 0xbc, 0x1e, 0x7e, 0xd3, + 0x3e, 0x7c, 0x3c, 0x59, 0x4a, 0x99, 0x0b, 0xca, 0x9b, 0x1e, + 0xc7, 0xf7, 0xe7, 0x6d, 0xdc, 0x57, 0xbe, 0x3a, 0xab, 0xc2, + 0x0b, 0xb1, 0xbe, 0x90, 0xa1, 0x54, 0x07, 0xc5, 0x48, 0x65, + 0xc1, 0x32, 0x99, 0x92, 0x26, 0x97, 0x90, 0x3e, 0x68, 0x6b, + 0xac, 0xbd, 0x4f, 0x0e, 0x88, 0x38, 0xd3, 0xdc, 0x80, 0x9e, + 0xb9, 0x66, 0x5d, 0xeb, 0x19, 0xfd, 0x85, 0xff, 0xba, 0xf0, + 0x89, 0x20, 0x08, 0xea, 0xd8, 0x01, 0x76, 0x29, 0xdc, 0xf0, + 0x1c, 0xfa, 0xbf, 0x6f, 0x7b, 0x67, 0xf4, 0xc4, 0xee, 0xe3, + 0xde, 0x95, 0xa2, 0x76, 0x65, 0x98, 0xc5, 0x21, 0xdc, 0xe9, + 0x95, 0xee, 0x83, 0x97, 0xae, 0xdd, 0xab, 0xdb, 0xc0, 0x47, + 0xc8, 0x68, 0x00, 0xb3, 0xab, 0x11, 0x4f, 0x81, 0xf5, 0x45, + 0x01, 0xd1, 0x64, 0xfd, 0x53, 0xbf, 0x86, 0xef, 0x87, 0xca, + 0x8e, 0x55, 0xa0, 0x27, 0x27, 0xe5, 0x9e, 0xc1, 0x69, 0x28, + 0x2a, 0x9f, 0x2d, 0xe2, 0x2c, 0x25, 0xef, 0x74, 0x1b, 0x52, + 0xe4, 0x81, 0xf4, 0xc2, 0x71, 0x0a, 0x48, 0xff, 0x47, 0xa5, + 0xea, 0x0a, 0xf5, 0xb1, 0x6d, 0xae, 0x09, 0x2b, 0xf9, 0x23, + 0x6a, 0x28, 0x58, 0x3d, 0xbb, 0x9f, 0x80, 0xb2, 0x81, 0x03, + 0xae, 0xe5, 0xea, 0xbe, 0x97, 0xae, 0xec, 0x3c, 0x33, 0xc7, + 0x68, 0xf0, 0x6c, 0x89, 0x9d, 0x01, 0x2a, 0x1e, 0x2b, 0xd7, + 0x93, 0x5a, 0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, + 0x01, 0x52, 0x30, 0x82, 0x01, 0x4e, 0x30, 0x1f, 0x06, 0x03, + 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc3, + 0x9c, 0xf3, 0xfc, 0xd3, 0x46, 0x08, 0x34, 0xbb, 0xce, 0x46, + 0x7f, 0xa0, 0x7c, 0x5b, 0xf3, 0xe2, 0x08, 0xcb, 0x59, 0x30, + 0x57, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, + 0x01, 0x04, 0x4b, 0x30, 0x49, 0x30, 0x1f, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x13, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x76, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x26, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, + 0x86, 0x1a, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, + 0x76, 0x2e, 0x73, 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x67, 0x76, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, + 0x03, 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x21, 0x06, 0x03, 0x55, + 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0x82, 0x0b, 0x2a, 0x2e, + 0x76, 0x75, 0x6c, 0x74, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x82, + 0x09, 0x76, 0x75, 0x6c, 0x74, 0x72, 0x2e, 0x63, 0x6f, 0x6d, + 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x24, 0x30, + 0x22, 0x30, 0x20, 0xa0, 0x1e, 0xa0, 0x1c, 0x86, 0x1a, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x67, 0x76, 0x2e, 0x73, + 0x79, 0x6d, 0x63, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x76, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x0c, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, + 0x45, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3e, 0x30, 0x3c, + 0x30, 0x3a, 0x06, 0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, + 0x45, 0x01, 0x07, 0x36, 0x30, 0x2c, 0x30, 0x2a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1e, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, + 0x77, 0x2e, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x6c, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x93, 0x63, 0x02, 0x6a, 0xa1, 0x2a, 0xf3, 0xbe, 0x64, 0x2b, + 0x36, 0xaf, 0x66, 0x16, 0x49, 0x29, 0x56, 0x6c, 0xc7, 0x75, + 0x74, 0xf3, 0x69, 0xd8, 0x85, 0xce, 0x50, 0x3b, 0x43, 0x89, + 0xaf, 0x74, 0x99, 0x26, 0x34, 0xa4, 0x27, 0xa8, 0xfa, 0xfe, + 0x45, 0xaf, 0xbe, 0x75, 0x22, 0x3d, 0x15, 0xca, 0xa6, 0x38, + 0xc9, 0x2b, 0x3c, 0xf4, 0x11, 0x9f, 0x96, 0xa7, 0x69, 0x3e, + 0xf8, 0xf0, 0x88, 0xd8, 0xd2, 0x9c, 0x1c, 0x0e, 0x4c, 0xfd, + 0xf3, 0x3b, 0x48, 0x25, 0x68, 0xb3, 0x8d, 0x7e, 0x26, 0x73, + 0x73, 0xcb, 0x3a, 0x41, 0x92, 0x16, 0x55, 0xe1, 0xff, 0x00, + 0x07, 0xa2, 0xfe, 0xfe, 0x25, 0xfc, 0x86, 0x0f, 0x49, 0xff, + 0x96, 0x78, 0x02, 0x65, 0xd7, 0xad, 0xcd, 0x0c, 0x82, 0x35, + 0x56, 0xfe, 0x12, 0x25, 0xa9, 0x8f, 0xc2, 0xa4, 0xe9, 0x43, + 0xbb, 0x85, 0x62, 0x21, 0x62, 0x5d, 0x70, 0x76, 0x79, 0x75, + 0xeb, 0xd6, 0x82, 0x53, 0x0d, 0xde, 0x77, 0x95, 0x56, 0x87, + 0x44, 0x13, 0x82, 0x7d, 0xa9, 0x9a, 0x94, 0x7e, 0x1c, 0x6d, + 0x7f, 0x72, 0xef, 0x04, 0x84, 0xdf, 0x65, 0x98, 0x17, 0xb4, + 0xbe, 0xfe, 0x30, 0x0f, 0xfa, 0x8d, 0x9f, 0x29, 0x1d, 0xbd, + 0x99, 0xa7, 0xe3, 0x09, 0x1d, 0x13, 0x21, 0xfd, 0x9e, 0x03, + 0x17, 0xb9, 0x9e, 0x48, 0x35, 0x66, 0xe5, 0x86, 0x0a, 0x0f, + 0x04, 0xfd, 0xcd, 0x3b, 0x13, 0x59, 0xd6, 0x0c, 0x05, 0x8c, + 0xd2, 0x6b, 0x5c, 0x45, 0x33, 0x43, 0x91, 0xac, 0xb8, 0xdd, + 0xe3, 0xbe, 0xdf, 0x7b, 0x5c, 0x94, 0xa9, 0xfd, 0xc0, 0xf8, + 0xa9, 0xd2, 0x82, 0xcd, 0xbf, 0x60, 0xd7, 0xf8, 0x3d, 0x53, + 0xf7, 0x6a, 0xdc, 0x46, 0xc4, 0x22, 0x84, 0x98, 0x6a, 0x32, + 0xf2, 0xdf, 0x43, 0xd9, 0x5a, 0xdb, 0x97, 0x20, 0x05, 0x0b, + 0x3e, 0x06, 0x38, 0x13, 0x3a, 0x21 ), + FINGERPRINT ( 0x2c, 0x58, 0x63, 0x6e, 0xf1, 0xab, 0x8f, 0xff, + 0x86, 0x5d, 0x4f, 0x8d, 0x3f, 0xa9, 0x4d, 0x63, + 0xe7, 0xe6, 0xc6, 0x03, 0x1e, 0xc9, 0x0e, 0xfb, + 0xe8, 0xaa, 0xa6, 0xf4, 0x6f, 0x21, 0xc7, 0x7b ) ); + OCSP ( barclays_ocsp, &barclays_crt, &verisign_crt, DATA ( 0x30, 0x51, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x4b, 0x30, 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, @@ -1301,12 +1548,164 @@ OCSP ( unknown_ocsp, &thawte_crt, &startssl_crt, 0x8c, 0x3e, 0xb4, 0x66, 0x76, 0x67, 0x34, 0x70, 0x00, 0x63, 0xcf, 0x9e, 0xc8, 0xc5, 0x5f, 0x48, 0x06, 0x53, 0x26, 0x55 ) ); +OCSP ( vultr_ocsp, &vultr_crt, &rapidssl_crt, + DATA ( 0x30, 0x44, 0x30, 0x42, 0x30, 0x40, 0x30, 0x3e, 0x30, 0x3c, + 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14, 0x40, 0x0b, 0x46, 0x7a, 0xf1, 0xe6, 0xb2, + 0xd3, 0x09, 0x83, 0xba, 0x0d, 0x60, 0x7e, 0x7e, 0x59, 0x37, + 0x48, 0x24, 0xc4, 0x04, 0x14, 0xc3, 0x9c, 0xf3, 0xfc, 0xd3, + 0x46, 0x08, 0x34, 0xbb, 0xce, 0x46, 0x7f, 0xa0, 0x7c, 0x5b, + 0xf3, 0xe2, 0x08, 0xcb, 0x59, 0x02, 0x03, 0x00, 0x95, 0x4d ), + DATA ( 0x30, 0x82, 0x05, 0x70, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x05, + 0x69, 0x30, 0x82, 0x05, 0x65, 0x06, 0x09, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x05, 0x56, + 0x30, 0x82, 0x05, 0x52, 0x30, 0x81, 0x91, 0xa2, 0x16, 0x04, + 0x14, 0xfa, 0x58, 0xdb, 0x09, 0x53, 0xbc, 0x19, 0xc5, 0xe7, + 0xb5, 0x8b, 0xf6, 0x10, 0xf8, 0x1e, 0x84, 0x6d, 0x3a, 0x8f, + 0xd8, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x34, 0x31, 0x31, 0x32, + 0x32, 0x32, 0x33, 0x30, 0x38, 0x35, 0x36, 0x5a, 0x30, 0x66, + 0x30, 0x64, 0x30, 0x3c, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x40, 0x0b, 0x46, + 0x7a, 0xf1, 0xe6, 0xb2, 0xd3, 0x09, 0x83, 0xba, 0x0d, 0x60, + 0x7e, 0x7e, 0x59, 0x37, 0x48, 0x24, 0xc4, 0x04, 0x14, 0xc3, + 0x9c, 0xf3, 0xfc, 0xd3, 0x46, 0x08, 0x34, 0xbb, 0xce, 0x46, + 0x7f, 0xa0, 0x7c, 0x5b, 0xf3, 0xe2, 0x08, 0xcb, 0x59, 0x02, + 0x03, 0x00, 0x95, 0x4d, 0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, + 0x31, 0x34, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x30, 0x38, + 0x35, 0x36, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30, 0x31, + 0x34, 0x31, 0x31, 0x32, 0x39, 0x32, 0x33, 0x30, 0x38, 0x35, + 0x36, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x01, 0x00, 0x6a, 0x71, 0x8f, 0x84, 0x66, 0xb5, 0x75, 0xe6, + 0x97, 0xa4, 0xb9, 0xc6, 0xa0, 0x37, 0x6f, 0x23, 0x76, 0x3c, + 0x59, 0x4c, 0x1c, 0x2d, 0x9f, 0x70, 0xab, 0x83, 0xbf, 0xa9, + 0xbf, 0x79, 0x31, 0x69, 0xdd, 0x78, 0xd5, 0x59, 0x90, 0x68, + 0xbe, 0x25, 0xb7, 0x53, 0x7d, 0x8b, 0xcf, 0x66, 0x3b, 0xcd, + 0xe0, 0xd2, 0x40, 0x1d, 0xc8, 0x29, 0xe4, 0x37, 0xbf, 0x20, + 0x7e, 0x64, 0x8d, 0x0d, 0xc7, 0xed, 0x0d, 0x08, 0x05, 0x36, + 0x27, 0x4f, 0xb8, 0xe3, 0x19, 0xec, 0xf0, 0x96, 0xe8, 0x48, + 0x9b, 0x8b, 0x2c, 0x18, 0xdb, 0x1e, 0x68, 0x11, 0xf3, 0xfb, + 0x9c, 0x68, 0xad, 0xcc, 0x15, 0xe0, 0x25, 0x08, 0x98, 0xd2, + 0xbf, 0xd0, 0x57, 0xe6, 0x4c, 0x73, 0x5a, 0x2c, 0xc8, 0x89, + 0xd6, 0xe4, 0xd0, 0x47, 0x6d, 0x8c, 0xc7, 0x75, 0xb1, 0x4e, + 0x10, 0x34, 0xe5, 0x40, 0xa3, 0xb1, 0x50, 0x07, 0x3d, 0x7d, + 0xad, 0xeb, 0x1d, 0x91, 0x7f, 0x77, 0x2e, 0x0d, 0x9a, 0xa7, + 0xbb, 0x68, 0x89, 0xd2, 0x05, 0x58, 0x16, 0xf1, 0x5e, 0x1d, + 0x05, 0xf6, 0x9e, 0xe9, 0x89, 0x52, 0x35, 0xb7, 0x29, 0x7a, + 0x68, 0x02, 0x6f, 0xc7, 0x20, 0x30, 0xc8, 0xde, 0x97, 0x3f, + 0xb7, 0x28, 0x38, 0x39, 0xd1, 0x4b, 0x4b, 0x90, 0x71, 0xe5, + 0x58, 0xa4, 0xa3, 0xbd, 0x78, 0x95, 0xb5, 0x54, 0xdd, 0xf7, + 0x4f, 0x8e, 0x78, 0x73, 0x86, 0xbf, 0x28, 0xb0, 0xdd, 0xc0, + 0xe9, 0x4a, 0xf5, 0x9f, 0x02, 0x8e, 0x63, 0x8f, 0x59, 0xf1, + 0x93, 0xf0, 0x45, 0x97, 0x30, 0xdb, 0x0a, 0x04, 0x3e, 0x81, + 0x99, 0x20, 0x7a, 0xb2, 0xe6, 0x8c, 0x8f, 0x2a, 0x4c, 0x31, + 0xf1, 0x64, 0xbc, 0xb7, 0xec, 0xb1, 0xf9, 0x69, 0x1f, 0x99, + 0x89, 0x3e, 0x3e, 0xa0, 0xf4, 0xde, 0x79, 0xa7, 0xae, 0xa3, + 0x23, 0xbd, 0x16, 0xbb, 0x6d, 0x0f, 0x15, 0x68, 0xa0, 0x82, + 0x03, 0xa6, 0x30, 0x82, 0x03, 0xa2, 0x30, 0x82, 0x03, 0x9e, + 0x30, 0x82, 0x02, 0x86, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, + 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0d, 0x47, 0x65, 0x6f, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x20, 0x30, 0x1e, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17, 0x52, 0x61, 0x70, + 0x69, 0x64, 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, + 0x35, 0x36, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x38, 0x32, 0x39, + 0x32, 0x33, 0x33, 0x39, 0x33, 0x30, 0x5a, 0x17, 0x0d, 0x31, + 0x35, 0x30, 0x35, 0x32, 0x32, 0x32, 0x33, 0x33, 0x39, 0x33, + 0x30, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x13, 0x26, 0x52, 0x61, 0x70, 0x69, 0x64, + 0x53, 0x53, 0x4c, 0x20, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, + 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, + 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x64, 0x65, 0x72, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, + 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x9b, 0xf2, 0x8e, 0xe9, + 0x57, 0x3e, 0xa8, 0x5c, 0xfd, 0x00, 0x14, 0x21, 0xe7, 0xe4, + 0x57, 0xbb, 0x55, 0xc8, 0xa8, 0x50, 0x93, 0xdc, 0xbf, 0xfc, + 0xde, 0x46, 0x8a, 0x53, 0x9f, 0x12, 0xaa, 0x7c, 0xf1, 0xdd, + 0x89, 0x9e, 0x02, 0x27, 0x9c, 0x1a, 0xa0, 0x94, 0xf5, 0xec, + 0x06, 0xa3, 0xdb, 0xf3, 0x3f, 0x6d, 0xfd, 0x30, 0x6d, 0xab, + 0xcb, 0xc3, 0x72, 0xa9, 0x25, 0x35, 0x69, 0x67, 0x07, 0xaf, + 0x9c, 0x91, 0x3a, 0x24, 0x03, 0x74, 0x59, 0xfd, 0x69, 0xa6, + 0xfe, 0x23, 0xa4, 0x6c, 0x2f, 0xbe, 0x44, 0x56, 0x47, 0xee, + 0xdb, 0x07, 0xc3, 0x72, 0x3f, 0x14, 0xdc, 0x16, 0xb9, 0x66, + 0x48, 0x7c, 0x6e, 0x69, 0x6f, 0xa1, 0x05, 0xc6, 0x36, 0x08, + 0x01, 0xdd, 0x1c, 0xb8, 0x52, 0xf4, 0x86, 0x96, 0x85, 0x39, + 0x89, 0xb0, 0x31, 0x67, 0x62, 0xc5, 0x52, 0x91, 0x72, 0xd7, + 0x96, 0x8c, 0xe1, 0x0a, 0x02, 0x6a, 0xfe, 0x82, 0xca, 0xc0, + 0x34, 0xc9, 0xbc, 0x45, 0xa7, 0xc0, 0x4b, 0xa0, 0x7c, 0x7c, + 0xcc, 0x29, 0xe5, 0x8c, 0xf6, 0x91, 0x65, 0x33, 0xf1, 0x7b, + 0xda, 0x55, 0x69, 0x93, 0x2d, 0x4e, 0xb9, 0xb4, 0x7f, 0x56, + 0xe6, 0x80, 0xbe, 0x23, 0x4a, 0x4a, 0x65, 0xa6, 0xab, 0xa2, + 0x40, 0xb1, 0x75, 0x62, 0x13, 0xc1, 0xfd, 0x52, 0xe1, 0xbb, + 0x7b, 0xb1, 0x7f, 0x8a, 0x0c, 0x27, 0x35, 0xec, 0x27, 0x3b, + 0xa5, 0xe7, 0x75, 0xb8, 0xe3, 0xc4, 0xcf, 0x4d, 0x8a, 0x02, + 0x57, 0x57, 0x16, 0xa2, 0x8e, 0x9d, 0x87, 0x5a, 0x32, 0xb6, + 0xf6, 0x1d, 0xf5, 0xe3, 0xd7, 0xcf, 0x79, 0xc8, 0x77, 0x74, + 0xdc, 0xe5, 0xba, 0xde, 0x5c, 0x22, 0xad, 0xc0, 0xfa, 0x67, + 0xf3, 0x26, 0xbf, 0xcc, 0xd4, 0x88, 0xd5, 0xda, 0x87, 0x4d, + 0x9d, 0x99, 0xc1, 0xce, 0xa4, 0x9a, 0xda, 0x99, 0xa5, 0xa2, + 0xe1, 0xc5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xaa, + 0x30, 0x81, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc3, 0x9c, 0xf3, 0xfc, + 0xd3, 0x46, 0x08, 0x34, 0xbb, 0xce, 0x46, 0x7f, 0xa0, 0x7c, + 0x5b, 0xf3, 0xe2, 0x08, 0xcb, 0x59, 0x30, 0x0f, 0x06, 0x09, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05, 0x04, + 0x02, 0x05, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xfa, 0x58, 0xdb, 0x09, 0x53, 0xbc, + 0x19, 0xc5, 0xe7, 0xb5, 0x8b, 0xf6, 0x10, 0xf8, 0x1e, 0x84, + 0x6d, 0x3a, 0x8f, 0xd8, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x09, 0x30, 0x0c, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x21, 0x06, 0x03, 0x55, + 0x1d, 0x11, 0x04, 0x1a, 0x30, 0x18, 0xa4, 0x16, 0x30, 0x14, + 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x09, 0x54, 0x47, 0x56, 0x2d, 0x42, 0x2d, 0x32, 0x31, 0x34, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x3e, 0x45, 0xce, 0x3d, 0x53, 0x8c, 0x88, 0xcd, 0xde, 0xf1, + 0x38, 0x0c, 0x00, 0x7a, 0x7e, 0x22, 0xe7, 0x1a, 0xa5, 0xbe, + 0xee, 0x1c, 0x17, 0x20, 0xc3, 0x65, 0x68, 0x86, 0x27, 0x83, + 0x62, 0xd7, 0xdc, 0x1d, 0x6c, 0xfa, 0x24, 0x2e, 0x66, 0x50, + 0xe5, 0xe0, 0x42, 0xa5, 0x73, 0x67, 0x2a, 0xea, 0x5a, 0x17, + 0x20, 0x3b, 0x14, 0xd4, 0x74, 0x14, 0xbd, 0x18, 0x60, 0xbe, + 0xa6, 0x46, 0xb1, 0xc2, 0x82, 0xc9, 0xb6, 0x99, 0x67, 0x56, + 0xbe, 0x17, 0xda, 0x78, 0x05, 0x48, 0x65, 0x9d, 0x48, 0xb5, + 0xda, 0x1d, 0x52, 0x59, 0x2a, 0xac, 0x09, 0x2d, 0x29, 0x18, + 0x96, 0xc1, 0x58, 0x79, 0xfc, 0x73, 0x0b, 0x70, 0x4d, 0x31, + 0x61, 0x80, 0xc7, 0x77, 0x02, 0xf1, 0x12, 0xb3, 0x80, 0x6f, + 0xb9, 0x05, 0x69, 0xcf, 0x4f, 0x80, 0x7d, 0xf5, 0x06, 0xe6, + 0x2e, 0xc7, 0x53, 0x99, 0x8b, 0x07, 0xc7, 0x7a, 0xe6, 0xf3, + 0x12, 0x86, 0xd1, 0xbb, 0x8a, 0x8a, 0xfb, 0x9d, 0xd1, 0x0b, + 0xe7, 0x9f, 0x12, 0x06, 0xfb, 0x7d, 0x8e, 0xe7, 0xb7, 0x39, + 0xe0, 0x3c, 0xd0, 0xe8, 0x35, 0x44, 0x28, 0xb7, 0xcb, 0xee, + 0xef, 0xa7, 0x14, 0xfa, 0x0e, 0x34, 0xaf, 0x78, 0x59, 0x1e, + 0x91, 0xd9, 0xe0, 0x9b, 0x3c, 0x9e, 0x3a, 0xbf, 0xf5, 0xf5, + 0x11, 0x5b, 0x04, 0x48, 0xcd, 0x3a, 0x3f, 0xee, 0x46, 0x6d, + 0x69, 0x68, 0x39, 0xc1, 0x4d, 0x54, 0xfd, 0x6c, 0x27, 0x1e, + 0x5b, 0x58, 0x00, 0xbb, 0x4f, 0x1b, 0x12, 0xd3, 0xbb, 0x46, + 0xf4, 0x7c, 0x4a, 0x44, 0xb5, 0xcb, 0x4f, 0xf2, 0x3d, 0xc3, + 0x51, 0xfc, 0x7a, 0x2c, 0x59, 0xd0, 0x82, 0x73, 0xe3, 0x88, + 0xfc, 0x25, 0x4c, 0x35, 0x6f, 0x88, 0x85, 0xff, 0xad, 0x8c, + 0x83, 0xc4, 0x76, 0x58, 0x6b, 0xfa, 0xf2, 0xed, 0x5b, 0x95, + 0xd9, 0x07, 0x55, 0x58, 0xfe, 0x08 ) ); + /** Time at which OCSP responses are valid */ static time_t test_time = 1337062083ULL; /* Tue 15 May 2012 06:08:03 */ /** Time at which OCSP responses are not valid */ static time_t test_stale = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ +/** Time at which "vultr" OCSP response (generated more recently) is valid */ +static time_t test_vultr = 1416697736ULL; /* Sat 22 Nov 23:08:56 2014 */ + /** * Report certificate parsing test result * @@ -1398,12 +1797,15 @@ static void ocsp_test_exec ( void ) { ocsp_certificate_ok ( &verisign_crt ); ocsp_certificate_ok ( &thawte_crt ); ocsp_certificate_ok ( &startssl_crt ); + ocsp_certificate_ok ( &rapidssl_crt ); + ocsp_certificate_ok ( &vultr_crt ); /* Parse OCSP checks */ ocsp_check_ok ( &barclays_ocsp ); ocsp_check_ok ( &google_ocsp ); ocsp_check_ok ( &unauthorized_ocsp ); ocsp_check_ok ( &unknown_ocsp ); + ocsp_check_ok ( &vultr_ocsp ); /* "barclays" test */ ocsp_request_ok ( &barclays_ocsp ); @@ -1425,13 +1827,22 @@ static void ocsp_test_exec ( void ) { ocsp_request_ok ( &unknown_ocsp ); ocsp_response_fail_ok ( &unknown_ocsp ); + /* "vultr" test */ + ocsp_request_ok ( &vultr_ocsp ); + ocsp_response_ok ( &vultr_ocsp ); + ocsp_validate_ok ( &vultr_ocsp, test_vultr ); + ocsp_validate_fail_ok ( &vultr_ocsp, test_stale ); + /* Drop OCSP check references */ ocsp_put ( unknown_ocsp.ocsp ); ocsp_put ( unauthorized_ocsp.ocsp ); ocsp_put ( google_ocsp.ocsp ); ocsp_put ( barclays_ocsp.ocsp ); + ocsp_put ( vultr_ocsp.ocsp ); /* Drop certificate references */ + x509_put ( vultr_crt.cert ); + x509_put ( rapidssl_crt.cert ); x509_put ( startssl_crt.cert ); x509_put ( thawte_crt.cert ); x509_put ( verisign_crt.cert ); diff --git a/roms/ipxe/src/tests/string_test.c b/roms/ipxe/src/tests/string_test.c index 88181cc21..3b48d9f3d 100644 --- a/roms/ipxe/src/tests/string_test.c +++ b/roms/ipxe/src/tests/string_test.c @@ -124,6 +124,36 @@ static void string_test_exec ( void ) { memswap ( ( test + 1 ), ( test + 4 ), 3 ); ok ( memcmp ( test, expected, sizeof ( test ) ) == 0 ); } + + /* Test strdup() */ + { + const char *orig = "testing testing"; + char *dup = strdup ( orig ); + ok ( dup != NULL ); + ok ( dup != orig ); + ok ( strcmp ( dup, orig ) == 0 ); + free ( dup ); + } + + /* Test strndup() */ + { + const char *normal = "testing testing"; + const char unterminated[6] = { 'h', 'e', 'l', 'l', 'o', '!' }; + char *dup; + dup = strndup ( normal, 32 ); + ok ( dup != NULL ); + ok ( dup != normal ); + ok ( strcmp ( dup, normal ) == 0 ); + free ( dup ); + dup = strndup ( normal, 4 ); + ok ( dup != NULL ); + ok ( strcmp ( dup, "test" ) == 0 ); + free ( dup ); + dup = strndup ( unterminated, 5 ); + ok ( dup != NULL ); + ok ( strcmp ( dup, "hello" ) == 0 ); + free ( dup ); + } } /** String self-test */ diff --git a/roms/ipxe/src/tests/x509_test.c b/roms/ipxe/src/tests/x509_test.c index d3e01faf1..fd39e12d2 100644 --- a/roms/ipxe/src/tests/x509_test.c +++ b/roms/ipxe/src/tests/x509_test.c @@ -413,8 +413,8 @@ CERTIFICATE ( useless_crt, * issuer iPXE self-test leaf CA */ CERTIFICATE ( server_crt, - DATA ( 0x30, 0x82, 0x02, 0xba, 0x30, 0x82, 0x02, 0x23, 0xa0, 0x03, - 0x02, 0x01, 0x02, 0x02, 0x01, 0x18, 0x30, 0x0d, 0x06, 0x09, + DATA ( 0x30, 0x82, 0x02, 0xd2, 0x30, 0x82, 0x02, 0x3b, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x1e, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, @@ -431,9 +431,9 @@ CERTIFICATE ( server_crt, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x30, 0x35, - 0x31, 0x33, 0x34, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, + 0x31, 0x33, 0x34, 0x35, 0x30, 0x35, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x33, 0x34, 0x35, 0x30, - 0x30, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x35, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, @@ -449,45 +449,47 @@ CERTIFICATE ( server_crt, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, - 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0x9d, 0x87, 0xe4, 0xa7, - 0xcf, 0x12, 0x08, 0x43, 0x4c, 0x90, 0x8b, 0x10, 0x7d, 0xcc, - 0x94, 0x1e, 0x5e, 0xef, 0xa7, 0x90, 0xbc, 0xe8, 0xe4, 0xee, - 0xd9, 0xb4, 0xd9, 0x63, 0x55, 0xc7, 0x03, 0x98, 0x42, 0xd7, - 0x4e, 0xaf, 0xd7, 0xdc, 0x40, 0x83, 0x61, 0x1b, 0xcc, 0x7b, - 0xf5, 0x1d, 0xba, 0x9f, 0x66, 0xfb, 0xe7, 0x42, 0xbd, 0xd7, - 0xac, 0xeb, 0x3c, 0xa2, 0x99, 0x6a, 0xe4, 0x8f, 0xb4, 0x06, - 0x4e, 0xc3, 0x3b, 0x62, 0xcd, 0x6a, 0x30, 0x0a, 0xe0, 0xb1, - 0x50, 0x83, 0x77, 0xc4, 0x97, 0x15, 0xc4, 0x7c, 0x40, 0xb8, - 0x60, 0x39, 0x07, 0x72, 0x4b, 0xd2, 0x61, 0x5c, 0xd0, 0xac, - 0x21, 0x9b, 0x85, 0xba, 0x53, 0x39, 0x1d, 0xef, 0xe9, 0xb7, - 0x69, 0xed, 0x7f, 0x1c, 0x38, 0x56, 0x0a, 0xe5, 0x24, 0xd0, - 0x1a, 0xa5, 0x9a, 0xd2, 0x5e, 0x1b, 0x47, 0x42, 0x49, 0x08, - 0x0d, 0x68, 0x2d, 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, - 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x11, - 0x04, 0x2b, 0x30, 0x29, 0x82, 0x12, 0x64, 0x65, 0x6d, 0x6f, + 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xac, 0x7b, 0x54, 0xc1, + 0x97, 0x4d, 0x56, 0xbd, 0xb2, 0x52, 0xb3, 0x5c, 0x1b, 0x28, + 0xae, 0x91, 0x33, 0xf0, 0xc8, 0xc2, 0x3c, 0x7d, 0xe8, 0x95, + 0x72, 0xaf, 0xfe, 0xa1, 0x68, 0xe1, 0xbd, 0xe2, 0x9d, 0x4c, + 0xe8, 0x95, 0x56, 0x94, 0xce, 0x47, 0x57, 0x1b, 0xb1, 0x08, + 0xa1, 0x5b, 0x02, 0x8f, 0x56, 0x75, 0x1e, 0x4f, 0xfd, 0xc5, + 0x87, 0x5c, 0x1c, 0x3f, 0xab, 0x4f, 0xba, 0x25, 0x14, 0x6d, + 0xe3, 0xa2, 0x47, 0x33, 0xd0, 0x78, 0x63, 0xcc, 0x11, 0x37, + 0x08, 0x73, 0x25, 0x42, 0x20, 0xa9, 0x57, 0x29, 0xeb, 0x44, + 0x80, 0x0d, 0xe6, 0x76, 0x4b, 0x02, 0x8b, 0x67, 0xb2, 0x99, + 0xfe, 0xb3, 0x44, 0x62, 0xdf, 0x34, 0x0e, 0xf3, 0xe2, 0x17, + 0x42, 0x8f, 0x36, 0x42, 0x5a, 0x1c, 0x03, 0x3e, 0x06, 0x0d, + 0x5e, 0x08, 0x52, 0xd1, 0x06, 0xfb, 0xa9, 0xdb, 0x13, 0x15, + 0x08, 0x6d, 0x03, 0x85, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x4e, 0x30, 0x4c, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x11, + 0x04, 0x43, 0x30, 0x41, 0x82, 0x12, 0x64, 0x65, 0x6d, 0x6f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x13, 0x2a, 0x2e, 0x61, 0x6c, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, - 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, - 0x03, 0x81, 0x81, 0x00, 0x23, 0x16, 0x6a, 0x10, 0x55, 0x44, - 0xb9, 0x9d, 0x9f, 0x9f, 0x53, 0x51, 0x3d, 0x7d, 0x33, 0xa1, - 0x84, 0xb2, 0x5a, 0xfb, 0x1d, 0x76, 0xd5, 0xb1, 0x79, 0x66, - 0xf5, 0xe3, 0xa6, 0x58, 0x2e, 0x3d, 0xec, 0x9f, 0xcf, 0x7d, - 0x75, 0x3b, 0xd7, 0xe8, 0xf6, 0x96, 0xd7, 0xdd, 0x89, 0x1e, - 0x30, 0x25, 0xd9, 0xbb, 0xc0, 0x99, 0xc0, 0x1f, 0x1b, 0x4f, - 0xa6, 0x8e, 0xd5, 0x76, 0x50, 0x18, 0xa1, 0x7a, 0x48, 0x08, - 0xd5, 0x75, 0xee, 0x20, 0x82, 0x12, 0xc0, 0xe8, 0xeb, 0xf1, - 0x50, 0xee, 0x9d, 0xbd, 0x73, 0x7c, 0xb5, 0x13, 0x05, 0x91, - 0x1f, 0xc6, 0x50, 0x08, 0xbc, 0x98, 0xde, 0x43, 0x9a, 0xa4, - 0x9f, 0x69, 0xf7, 0x6e, 0x36, 0x20, 0x42, 0x80, 0x72, 0xba, - 0x0d, 0x63, 0x4c, 0xc5, 0x00, 0x0d, 0x85, 0xaa, 0x14, 0x38, - 0x28, 0x11, 0x3e, 0xa2, 0xcc, 0xc2, 0xac, 0xe8, 0xa7, 0xbe, - 0x0a, 0xa0 ), - FINGERPRINT ( 0x2f, 0xd3, 0xe0, 0x69, 0xde, 0xbc, 0x7c, 0x39, - 0xa7, 0xee, 0x23, 0x3b, 0xf5, 0x92, 0xf5, 0xbe, - 0x05, 0xab, 0xb5, 0xf8, 0x42, 0x9e, 0xf5, 0x9c, - 0x24, 0xde, 0x9e, 0x1f, 0xeb, 0xed, 0xd1, 0x20 ) ); + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x87, 0x04, 0xc0, 0xa8, 0x00, + 0x01, 0x87, 0x10, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x69, 0xff, 0xfe, 0x50, 0x58, 0x45, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x63, 0x83, + 0xf5, 0xde, 0xf7, 0x59, 0x81, 0xd3, 0x34, 0x61, 0xfd, 0x2c, + 0x0c, 0xec, 0x1c, 0x25, 0xd2, 0x2c, 0xe8, 0x90, 0x4f, 0x34, + 0x43, 0x2c, 0x86, 0x18, 0x9e, 0x66, 0x26, 0x0d, 0x02, 0x2a, + 0xea, 0x28, 0xc6, 0xbb, 0x51, 0x02, 0xbe, 0x8f, 0x51, 0x50, + 0xc7, 0x04, 0x49, 0x97, 0xb9, 0xd4, 0xa5, 0x74, 0x39, 0xaa, + 0x22, 0xbb, 0x4e, 0x46, 0x57, 0x15, 0x0e, 0xcf, 0x64, 0x60, + 0xc8, 0x13, 0xdf, 0x82, 0x09, 0x3b, 0x92, 0xf5, 0x69, 0x80, + 0xd2, 0x5e, 0x53, 0x9d, 0x3a, 0xcd, 0x9e, 0x81, 0xa1, 0xbd, + 0x5b, 0x66, 0x89, 0x4d, 0xf7, 0xa4, 0xd6, 0x92, 0xe4, 0xe1, + 0x80, 0x87, 0xfa, 0xa5, 0x47, 0x25, 0x9c, 0x35, 0x77, 0xa5, + 0x11, 0x1b, 0x48, 0x4c, 0x5e, 0x5e, 0x2f, 0xc7, 0xf8, 0x78, + 0x4c, 0x36, 0x41, 0xfb, 0x91, 0x5d, 0xf6, 0x43, 0x99, 0x7c, + 0xcd, 0x7f, 0x27, 0x4c, 0x75, 0xca ), + FINGERPRINT ( 0x82, 0xd3, 0xa0, 0x4c, 0x0d, 0x7d, 0x3c, 0xb1, + 0x90, 0x63, 0xd8, 0xef, 0x1e, 0xd2, 0xdd, 0x10, + 0xd5, 0x89, 0x40, 0x35, 0xb9, 0x5e, 0x98, 0x44, + 0x30, 0xa2, 0x48, 0x9a, 0xb8, 0x2f, 0xcf, 0xe3 ) ); /* * subject not.a.ca.test.ipxe.org @@ -1033,6 +1035,11 @@ static void x509_test_exec ( void ) { x509_check_name_fail_ok ( &server_crt, "ipxe.org" ); x509_check_name_fail_ok ( &server_crt, "org" ); x509_check_name_fail_ok ( &server_crt, "" ); + x509_check_name_ok ( &server_crt, "192.168.0.1" ); + x509_check_name_fail_ok ( &server_crt, "192.168.0.2" ); + x509_check_name_ok ( &server_crt, "fe80::69ff:fe50:5845" ); + x509_check_name_ok ( &server_crt, "FE80:0:0:0:0:69FF:FE50:5845" ); + x509_check_name_fail_ok ( &server_crt, "fe80::69ff:fe50:5846" ); /* Parse all certificate chains */ x509_chain_ok ( &server_chain ); @@ -1101,3 +1108,5 @@ struct self_test x509_test __self_test = { REQUIRE_OBJECT ( rsa ); REQUIRE_OBJECT ( sha1 ); REQUIRE_OBJECT ( sha256 ); +REQUIRE_OBJECT ( ipv4 ); +REQUIRE_OBJECT ( ipv6 ); diff --git a/roms/ipxe/src/usr/autoboot.c b/roms/ipxe/src/usr/autoboot.c index af3d1f7bb..47476ae40 100644 --- a/roms/ipxe/src/usr/autoboot.c +++ b/roms/ipxe/src/usr/autoboot.c @@ -49,8 +49,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** Device location of preferred autoboot device */ -struct device_description autoboot_device; +/** Link-layer address of preferred autoboot device, if known */ +static uint8_t autoboot_ll_addr[MAX_LL_ADDR_LEN]; + +/** Device location of preferred autoboot device, if known */ +static struct device_description autoboot_desc; + +/** Autoboot device tester */ +static int ( * is_autoboot_device ) ( struct net_device *netdev ); /* Disambiguate the various error causes */ #define ENOENT_BOOT __einfo_error ( EINFO_ENOENT_BOOT ) @@ -422,15 +428,60 @@ int netboot ( struct net_device *netdev ) { } /** - * Test if network device matches the autoboot device location + * Test if network device matches the autoboot device bus type and location * * @v netdev Network device - * @ret is_autoboot Network device matches the autoboot device location + * @ret is_autoboot Network device matches the autoboot device + */ +static int is_autoboot_busloc ( struct net_device *netdev ) { + + return ( ( netdev->dev->desc.bus_type == autoboot_desc.bus_type ) && + ( netdev->dev->desc.location == autoboot_desc.location ) ); +} + +/** + * Identify autoboot device by bus type and location + * + * @v bus_type Bus type + * @v location Location */ -static int is_autoboot_device ( struct net_device *netdev ) { +void set_autoboot_busloc ( unsigned int bus_type, unsigned int location ) { + + /* Record autoboot device description */ + autoboot_desc.bus_type = bus_type; + autoboot_desc.location = location; + + /* Mark autoboot device as present */ + is_autoboot_device = is_autoboot_busloc; +} + +/** + * Test if network device matches the autoboot device link-layer address + * + * @v netdev Network device + * @ret is_autoboot Network device matches the autoboot device + */ +static int is_autoboot_ll_addr ( struct net_device *netdev ) { + + return ( memcmp ( netdev->ll_addr, autoboot_ll_addr, + netdev->ll_protocol->ll_addr_len ) == 0 ); +} + +/** + * Identify autoboot device by link-layer address + * + * @v ll_addr Link-layer address + * @v len Length of link-layer address + */ +void set_autoboot_ll_addr ( const void *ll_addr, size_t len ) { + + /* Record autoboot link-layer address (truncated if necessary) */ + if ( len > sizeof ( autoboot_ll_addr ) ) + len = sizeof ( autoboot_ll_addr ); + memcpy ( autoboot_ll_addr, ll_addr, len ); - return ( ( netdev->dev->desc.bus_type == autoboot_device.bus_type ) && - ( netdev->dev->desc.location == autoboot_device.location ) ); + /* Mark autoboot device as present */ + is_autoboot_device = is_autoboot_ll_addr; } /** @@ -447,8 +498,7 @@ static int autoboot ( void ) { for_each_netdev ( netdev ) { /* Skip any non-matching devices, if applicable */ - if ( autoboot_device.bus_type && - ( ! is_autoboot_device ( netdev ) ) ) + if ( is_autoboot_device && ( ! is_autoboot_device ( netdev ) ) ) continue; /* Attempt booting from this device */ @@ -499,10 +549,10 @@ void ipxe ( struct net_device *netdev ) { * do so. * */ - printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "iPXE %s" + printf ( NORMAL "\n\n%s\n" BOLD "iPXE %s" NORMAL " -- Open Source Network Boot Firmware -- " CYAN "http://ipxe.org" NORMAL "\n" - "Features:", product_version ); + "Features:", product_name, product_version ); for_each_table_entry ( feature, FEATURES ) printf ( " %s", feature->name ); printf ( "\n" ); diff --git a/roms/ipxe/src/usr/ifmgmt.c b/roms/ipxe/src/usr/ifmgmt.c index cab1cd917..3d05895c2 100644 --- a/roms/ipxe/src/usr/ifmgmt.c +++ b/roms/ipxe/src/usr/ifmgmt.c @@ -28,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/device.h> #include <ipxe/job.h> #include <ipxe/monojob.h> -#include <ipxe/nap.h> #include <ipxe/timer.h> #include <usr/ifmgmt.h> @@ -142,9 +141,6 @@ struct ifpoller { static int ifpoller_progress ( struct ifpoller *ifpoller, struct job_progress *progress __unused ) { - /* Reduce CPU utilisation */ - cpu_nap(); - /* Hand off to current progress checker */ return ifpoller->progress ( ifpoller ); } diff --git a/roms/ipxe/src/usr/lotest.c b/roms/ipxe/src/usr/lotest.c index 9e2ac331c..ad7a2fad7 100644 --- a/roms/ipxe/src/usr/lotest.c +++ b/roms/ipxe/src/usr/lotest.c @@ -39,8 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** Loopback testing in progress flag */ -static int lotest_active; +/** Current loopback test receiver */ +static struct net_device *lotest_receiver; /** Loopback testing received packets */ static LIST_HEAD ( lotest_queue ); @@ -56,13 +56,13 @@ static LIST_HEAD ( lotest_queue ); * @ret rc Return status code */ static int lotest_rx ( struct io_buffer *iobuf, - struct net_device *netdev __unused, + struct net_device *netdev, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused ) { /* Add to received packet queue if currently performing a test */ - if ( lotest_active ) { + if ( netdev == lotest_receiver ) { list_add_tail ( &iobuf->list, &lotest_queue ); } else { free_iob ( iobuf ); @@ -223,7 +223,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, /* Start loopback test */ lotest_flush(); - lotest_active = 1; + lotest_receiver = receiver; /* Perform loopback test */ for ( successes = 0 ; ; successes++ ) { @@ -261,7 +261,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, printf ( "\n"); /* Stop loopback testing */ - lotest_active = 0; + lotest_receiver = NULL; lotest_flush(); /* Dump final statistics */ diff --git a/roms/ipxe/src/usr/pingmgmt.c b/roms/ipxe/src/usr/pingmgmt.c index 2d4db491f..16b3ec994 100644 --- a/roms/ipxe/src/usr/pingmgmt.c +++ b/roms/ipxe/src/usr/pingmgmt.c @@ -36,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Display ping result * - * @v src Source socket address + * @v src Source socket address, or NULL * @v sequence Sequence number * @v len Payload length * @v rc Status code @@ -46,7 +46,7 @@ static void ping_callback ( struct sockaddr *peer, unsigned int sequence, /* Display ping response */ printf ( "%zd bytes from %s: seq=%d", - len, sock_ntoa ( peer ), sequence ); + len, ( peer ? sock_ntoa ( peer ) : "<none>" ), sequence ); if ( rc != 0 ) printf ( ": %s", strerror ( rc ) ); printf ( "\n" ); @@ -58,21 +58,25 @@ static void ping_callback ( struct sockaddr *peer, unsigned int sequence, * @v hostname Hostname * @v timeout Timeout between pings, in ticks * @v len Payload length + * @v count Number of packets to send (or zero for no limit) + * @v quiet Inhibit output * @ret rc Return status code */ -int ping ( const char *hostname, unsigned long timeout, size_t len ) { +int ping ( const char *hostname, unsigned long timeout, size_t len, + unsigned int count, int quiet ) { int rc; /* Create pinger */ - if ( ( rc = create_pinger ( &monojob, hostname, timeout, - len, ping_callback ) ) != 0 ) { + if ( ( rc = create_pinger ( &monojob, hostname, timeout, len, count, + ( quiet ? NULL : ping_callback ) ) ) != 0 ){ printf ( "Could not start ping: %s\n", strerror ( rc ) ); return rc; } /* Wait for ping to complete */ if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) { - printf ( "Finished: %s\n", strerror ( rc ) ); + if ( ! quiet ) + printf ( "Finished: %s\n", strerror ( rc ) ); return rc; } diff --git a/roms/ipxe/src/util/.gitignore b/roms/ipxe/src/util/.gitignore index 633ca322d..33bedefd0 100644 --- a/roms/ipxe/src/util/.gitignore +++ b/roms/ipxe/src/util/.gitignore @@ -5,5 +5,6 @@ prototester elf2efi32 elf2efi64 efirom +efifatbin iccfix einfo diff --git a/roms/ipxe/src/util/Option/ROM.pm b/roms/ipxe/src/util/Option/ROM.pm index fb37ce4b0..6c396730e 100644 --- a/roms/ipxe/src/util/Option/ROM.pm +++ b/roms/ipxe/src/util/Option/ROM.pm @@ -266,11 +266,10 @@ sub set { # Split out any data belonging to the next image delete $self->{next_image}; - my $length = ( $hash->{length} * 512 ); my $pci_header = $hash->pci_header(); - if ( ( $length < length $data ) && - ( defined $pci_header ) && + if ( ( defined $pci_header ) && ( ! ( $pci_header->{last_image} & PCI_LAST_IMAGE ) ) ) { + my $length = ( $pci_header->{image_length} * 512 ); my $remainder = substr ( $data, $length ); $data = substr ( $data, 0, $length ); $self->{next_image} = new Option::ROM; diff --git a/roms/ipxe/src/util/efifatbin.c b/roms/ipxe/src/util/efifatbin.c new file mode 100644 index 000000000..c02f750b6 --- /dev/null +++ b/roms/ipxe/src/util/efifatbin.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2014 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. + */ + +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <getopt.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/IndustryStandard/PeImage.h> + +#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) + +/** Command-line options */ +struct options { +}; + +/** EFI fat binary file header */ +struct efifatbin_file_header { + /** Signature */ + uint32_t signature; + /** Count */ + uint32_t count; +} __attribute__ (( packed )); + +/** EFI fat binary signature */ +#define EFIFATBIN_SIGNATURE 0x0ef1fab9 + +/** EFI fat binary image header */ +struct efifatbin_image_header { + /** Flags */ + uint64_t flags; + /** Offset */ + uint32_t offset; + /** Length */ + uint32_t len; + /** Padding */ + uint32_t pad; +} __attribute__ (( packed )); + +/** EFI fat binary default flags */ +#define EFIFATBIN_FLAGS 0x0000000300000007ULL + +/** EFI fat binary 64-bit flag */ +#define EFIFATBIN_64BIT 0x0000000001000000ULL + +/** + * 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; +} + +/** + * Generate EFI fat binary + * + * @v count Number of input files + * @v infile_names Input filenames + * @v outfile_name Output filename + */ +static void make_efifatbin ( unsigned int count, char **infile_names, + const char *outfile_name ) { + FILE *infile[count]; + FILE *outfile; + struct stat stat[count]; + void *buf[count]; + struct efifatbin_file_header file_header; + struct efifatbin_image_header header[count]; + size_t offset; + EFI_IMAGE_DOS_HEADER *dos; + union { + EFI_IMAGE_NT_HEADERS32 nt32; + EFI_IMAGE_NT_HEADERS64 nt64; + } *nt; + unsigned int i; + + /* Generate file header */ + file_header.signature = EFIFATBIN_SIGNATURE; + file_header.count = count; + offset = ( sizeof ( file_header ) + sizeof ( header ) ); + + /* Process input files */ + for ( i = 0 ; i < count ; i++ ) { + + /* Open input file */ + infile[i] = fopen ( infile_names[i], "r" ); + if ( ! infile[i] ) { + eprintf ( "Could not open %s for reading: %s\n", + infile_names[i], strerror ( errno ) ); + exit ( 1 ); + } + + /* Determine PE file size */ + if ( fstat ( fileno ( infile[i] ), &stat[i] ) != 0 ) { + eprintf ( "Could not stat %s: %s\n", + infile_names[i], strerror ( errno ) ); + exit ( 1 ); + } + + /* Allocate buffer and read in PE file */ + buf[i] = xmalloc ( stat[i].st_size ); + if ( fread ( buf[i], stat[i].st_size, 1, infile[i] ) != 1 ) { + eprintf ( "Could not read %s: %s\n", + infile_names[i], strerror ( errno ) ); + exit ( 1 ); + } + + /* Close input file */ + fclose ( infile[i] ); + + /* Generate image header */ + header[i].flags = EFIFATBIN_FLAGS; + header[i].offset = offset; + header[i].len = stat[i].st_size; + header[i].pad = 0; + + /* Determine architecture */ + dos = buf[i]; + nt = ( buf[i] + dos->e_lfanew ); + if ( nt->nt32.FileHeader.Machine == EFI_IMAGE_MACHINE_X64 ) + header[i].flags |= EFIFATBIN_64BIT; + + /* Allow space for this image */ + offset += stat[i].st_size; + } + + /* Open output file */ + outfile = fopen ( outfile_name, "w" ); + if ( ! outfile ) { + eprintf ( "Could not open %s for writing: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + + /* Write fat binary header */ + if ( fwrite ( &file_header, sizeof ( file_header ), 1, outfile ) != 1 ){ + eprintf ( "Could not write %s: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + for ( i = 0 ; i < count ; i++ ) { + if ( fwrite ( &header[i], sizeof ( header[i] ), 1, + outfile ) != 1 ) { + eprintf ( "Could not write %s: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + } + + /* Write images */ + for ( i = 0 ; i < count ; i++ ) { + if ( fwrite ( buf[i], stat[i].st_size, 1, outfile ) != 1 ) { + eprintf ( "Could not write %s: %s\n", + outfile_name, strerror ( errno ) ); + exit ( 1 ); + } + } + + /* Close output file */ + fclose ( outfile ); +} + +/** + * Print help + * + * @v program_name Program name + */ +static void print_help ( const char *program_name ) { + eprintf ( "Syntax: %s infile [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 __attribute__ (( unused )) ) { + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + + if ( ( c = getopt_long ( argc, argv, "h", + long_options, + &option_index ) ) == -1 ) { + break; + } + + switch ( c ) { + case 'h': + print_help ( argv[0] ); + exit ( 0 ); + case '?': + default: + exit ( 2 ); + } + } + return optind; +} + +int main ( int argc, char **argv ) { + struct options opts; + int infile_index; + int outfile_index; + int count; + + /* Parse command-line arguments */ + memset ( &opts, 0, sizeof ( opts ) ); + infile_index = parse_options ( argc, argv, &opts ); + outfile_index = ( argc - 1 ); + count = ( outfile_index - infile_index ); + if ( count <= 0 ) { + print_help ( argv[0] ); + exit ( 2 ); + } + + /* Generate fat binary */ + make_efifatbin ( count, &argv[infile_index], argv[outfile_index] ); + + return 0; +} diff --git a/roms/ipxe/src/util/geniso b/roms/ipxe/src/util/geniso index 4dc721927..521c929e1 100755 --- a/roms/ipxe/src/util/geniso +++ b/roms/ipxe/src/util/geniso @@ -1,80 +1,142 @@ #!/bin/bash # # Generate a isolinux ISO boot image -# -# geniso foo.iso foo.lkrn -# -# the ISO image is the first argument so that a list of .lkrn images -# to include can be specified -# -case $# in -0|1) - echo Usage: $0 foo.iso foo.lkrn ... - exit 1 - ;; -esac -# This should be the default location of the isolinux.bin file -isolinux_bin=${ISOLINUX_BIN:-util/isolinux.bin} -if [ ! -r $isolinux_bin ] -then - echo $0: $isolinux_bin not found, please install, or set ISOLINUX_BIN in arch/i386/Makefile correctly +function help() { + echo "usage: ${0} [OPTIONS] foo.lkrn [bar.lkrn,...]" + echo + echo "where OPTIONS are:" + echo " -h show this help" + echo " -l build legacy image with floppy emulation" + echo " -o FILE save iso image to file" +} + +LEGACY=0 +FIRST="" + +while getopts "hlo:" opt; do + case ${opt} in + h) + help + exit 0 + ;; + l) + LEGACY=1 + ;; + o) + OUT="${OPTARG}" + ;; + esac +done + +shift $((OPTIND - 1)) + +if [ -z "${OUT}" ]; then + echo "${0}: no output file given" >&2 + help exit 1 fi # There should either be mkisofs or the compatible genisoimage program -mkisofs=`which mkisofs genisoimage 2>/dev/null | head -n1` -if [ -z $mkisofs ] -then - echo $0: mkisofs or genisoimage not found, please install or set PATH +for command in genisoimage mkisofs; do + if ${command} --version >/dev/null 2>/dev/null; then + mkisofs=(${command}) + break + fi +done + +if [ -z "${mkisofs}" ]; then + echo "${0}: mkisofs or genisoimage not found, please install or set PATH" >&2 exit 1 fi -# isohybrid will be used if available -isohybrid=`which isohybrid 2>/dev/null` +dir=$(mktemp -d bin/iso.dir.XXXXXX) +cfg=${dir}/isolinux.cfg -out=$1 -shift -dir=`mktemp -d bin/iso.dir.XXXXXX` -cfg=$dir/isolinux.cfg -cp -p $isolinux_bin $dir +mkisofs+=(-quiet -l -volid "iPXE" -preparer "iPXE build system" + -appid "iPXE ${VERSION} - Open Source Network Boot Firmware" + -publisher "http://ipxe.org/" -c boot.cat) -# syslinux 6.x needs a file called ldlinux.c32 -ldlinux_c32=$(dirname ${isolinux_bin})/ldlinux.c32 -if [ -s ${ldlinux_c32} ] -then - cp -p ${ldlinux_c32} ${dir} -fi - -cat > $cfg <<EOF +# generate the config +cat > ${cfg} <<EOF # These default options can be changed in the geniso script SAY iPXE ISO boot image TIMEOUT 30 EOF -first= -for f -do - if [ ! -r $f ] - then - echo $f does not exist, skipping 1>&2 +for f; do + if [ ! -r ${f} ]; then + echo "${f} does not exist, skipping" >&2 continue fi - b=$(basename $f) + b=$(basename ${f}) g=${b%.lkrn} - g=${g//[^a-z0-9]}.krn - case "$first" in - "") - echo DEFAULT $b - ;; + g=${g//[^a-z0-9]} + g=${g:0:8}.krn + case "${FIRST}" in + "") + echo "DEFAULT ${b}" + FIRST=${g} + ;; esac - first=$g - echo LABEL $b - echo "" KERNEL $g - cp -p $f $dir/$g -done >> $cfg -$mkisofs -quiet -l -o $out -c boot.cat -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table $dir -rm -fr $dir -if [ -n "$isohybrid" ] -then - $isohybrid $out >/dev/null -fi + echo "LABEL ${b}" + echo " KERNEL ${g}" + cp ${f} ${dir}/${g} +done >> ${cfg} + +case "${LEGACY}" in + 1) + # check for mtools + case "$(mtools -V)" in + Mtools\ version\ 3.9.9*|Mtools\ version\ 3.9.1[0-9]*|[mM]tools\ *\ [4-9].*) + ;; + *) + echo "Mtools version 3.9.9 or later is required" >&2 + exit 1 + ;; + esac + + # generate floppy image + img=${dir}/boot.img + mformat -f 1440 -C -i ${img} :: + + # copy lkrn file to floppy image + for f in ${dir}/*.krn; do + mcopy -m -i ${img} ${f} ::$(basename ${g}) + rm -f ${f} + done + + # copy config file to floppy image + mcopy -i ${img} ${cfg} ::syslinux.cfg + rm -f ${cfg} + + # write syslinux bootloader to floppy image + if ! syslinux ${img}; then + echo "${0}: failed writing syslinux to floppy image ${img}" >&2 + exit 1 + fi + + # generate the iso image + "${mkisofs[@]}" -b boot.img -output ${OUT} ${dir} + ;; + 0) + # copy isolinux bootloader + cp ${ISOLINUX_BIN} ${dir} + + # syslinux 6.x needs a file called ldlinux.c32 + LDLINUX_C32=$(dirname ${ISOLINUX_BIN})/ldlinux.c32 + if [ -s ${LDLINUX_C32} ]; then + cp ${LDLINUX_C32} ${dir} + fi + + # generate the iso image + "${mkisofs[@]}" -b isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table -output ${OUT} ${dir} + + # isohybrid will be used if available + if isohybrid --version >/dev/null 2>/dev/null; then + isohybrid ${OUT} >/dev/null + fi + ;; +esac + +# clean up temporary dir +rm -fr ${dir} diff --git a/roms/ipxe/src/util/genliso b/roms/ipxe/src/util/genliso deleted file mode 100755 index 7a112a145..000000000 --- a/roms/ipxe/src/util/genliso +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -# -# Generate a legacy floppy emulation ISO boot image -# -# genliso foo.liso foo.lkrn bar.lkrn ... -# -# The .liso image filename is the first argument followed by -# a list of .lkrn images include in .liso image - -case $# in -0|1) - echo Usage: $0 foo.liso foo.lkrn ... - exit 1 - ;; -esac - -case "`mtools -V`" in -Mtools\ version\ 3.9.9*|Mtools\ version\ 3.9.1[0-9]*|[mM]tools\ *\ [4-9].*) - ;; -*) - echo Mtools version 3.9.9 or later is required - exit 1 - ;; -esac - -out=$1 -shift - -dir=`mktemp -d bin/liso.dir.XXXXXX` - -img=$dir/boot.img -mformat -f 1440 -C -i $img :: - -cfg=$dir/syslinux.cfg -cat > $cfg <<EOF -# These default options can be changed in the genliso script -SAY iPXE ISO boot image generated by genliso -TIMEOUT 30 -EOF - -first= -for f -do - if [ ! -r $f ] - then - echo $f does not exist, skipping 1>&2 - continue - fi - # shorten name for 8.3 filesystem - b=$(basename $f) - g=${b%.lkrn} - g=${g//[^a-z0-9]} - g=${g:0:8}.krn - case "$first" in - "") - echo DEFAULT $g - ;; - esac - first=$g - echo LABEL $g - echo "" KERNEL $g - mcopy -m -i $img $f ::$g -done >> $cfg - -mcopy -i $img $cfg ::syslinux.cfg - -if ! syslinux $img -then - exit 1 -fi - -mkisofs -q -o $out -c boot.cat -b boot.img $dir - -rm -fr $dir |