diff options
author | H. Peter Anvin <hpa@zytor.com> | 2010-02-02 22:41:00 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-02-02 22:41:00 -0800 |
commit | 702c7fbe7342403472e887508716add0c58c385c (patch) | |
tree | 639050b522cea25f4475d48da54380d61c7d10f3 | |
parent | 1e96e9cc1c3549c86dbf4e7caf880477e16e93e0 (diff) | |
download | syslinux.git-702c7fbe7342403472e887508716add0c58c385c.tar.gz syslinux.git-702c7fbe7342403472e887508716add0c58c385c.tar.xz syslinux.git-702c7fbe7342403472e887508716add0c58c385c.zip |
Update gPXE to version 1.0.0
683 files changed, 64099 insertions, 9709 deletions
diff --git a/gpxe/gpxe.diff b/gpxe/gpxe.diff new file mode 100644 index 00000000..3df08a21 --- /dev/null +++ b/gpxe/gpxe.diff @@ -0,0 +1,15 @@ +diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h +index 0a9e625..de51f9f 100644 +--- a/gpxe/src/config/general.h ++++ b/gpxe/src/config/general.h +@@ -55,8 +55,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); + + #define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */ + #define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ +-#undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ +-#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ ++#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ ++#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ + #undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ + #undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ + diff --git a/gpxe/src/Makefile b/gpxe/src/Makefile index a627d967..cc91d78f 100644 --- a/gpxe/src/Makefile +++ b/gpxe/src/Makefile @@ -22,7 +22,7 @@ ECHO := echo PRINTF := printf PERL := /usr/bin/perl CC := $(CROSS_COMPILE)gcc -CPP := $(CROSS_COMPILE)gcc -E -Wp,-Wall +CPP := $(CC) -E AS := $(CROSS_COMPILE)as LD := $(CROSS_COMPILE)ld SIZE := $(CROSS_COMPILE)size @@ -35,12 +35,17 @@ PARSEROM := $(PERL) ./util/parserom.pl MAKEROM := $(PERL) ./util/makerom.pl SYMCHECK := $(PERL) ./util/symcheck.pl SORTOBJDUMP := $(PERL) ./util/sortobjdump.pl +PADIMG := $(PERL) ./util/padimg.pl +LICENCE := $(PERL) ./util/licence.pl NRV2B := ./util/nrv2b ZBIN := ./util/zbin ELF2EFI32 := ./util/elf2efi32 ELF2EFI64 := ./util/elf2efi64 EFIROM := ./util/efirom +ICCFIX := ./util/iccfix DOXYGEN := doxygen +BINUTILS_DIR := /usr +BFD_DIR := $(BINUTILS_DIR) ############################################################################### # @@ -49,13 +54,14 @@ DOXYGEN := doxygen SRCDIRS := SRCDIRS += libgcc SRCDIRS += core -SRCDIRS += proto -SRCDIRS += net net/tcp net/udp +SRCDIRS += net net/tcp net/udp net/infiniband net/80211 SRCDIRS += image SRCDIRS += drivers/bus SRCDIRS += drivers/net SRCDIRS += drivers/net/e1000 SRCDIRS += drivers/net/phantom +SRCDIRS += drivers/net/rtl818x +SRCDIRS += drivers/net/ath5k SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash @@ -66,6 +72,7 @@ SRCDIRS += crypto crypto/axtls crypto/matrixssl SRCDIRS += hci hci/commands hci/tui SRCDIRS += hci/mucurses hci/mucurses/widgets SRCDIRS += usr +SRCDIRS += config # NON_AUTO_SRCS lists files that are excluded from the normal # automatic build system. @@ -73,6 +80,11 @@ SRCDIRS += usr NON_AUTO_SRCS := NON_AUTO_SRCS += drivers/net/prism2.c +# INCDIRS lists the include path +# +INCDIRS := +INCDIRS += include . + ############################################################################### # # Default build target: build the most common targets and print out a @@ -115,9 +127,9 @@ install : # # Version number calculations # -VERSION_MAJOR = 0 -VERSION_MINOR = 9 -VERSION_PATCH = 7 +VERSION_MAJOR = 1 +VERSION_MINOR = 0 +VERSION_PATCH = 0 EXTRAVERSION = MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR) VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION) diff --git a/gpxe/src/Makefile.housekeeping b/gpxe/src/Makefile.housekeeping index 2ab842e6..1f5e115f 100644 --- a/gpxe/src/Makefile.housekeeping +++ b/gpxe/src/Makefile.housekeeping @@ -54,6 +54,14 @@ echo : ############################################################################### # +# Generate a usable "seq" substitute +# +define seq + $(shell awk 'BEGIN { for ( i = $(1) ; i <= $(2) ; i++ ) print i }') +endef + +############################################################################### +# # Determine host OS # HOST_OS := $(shell uname -s) @@ -62,6 +70,22 @@ hostos : ############################################################################### # +# Determine compiler + +CCDEFS := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2) +ccdefs: + @$(ECHO) $(CCDEFS) + +ifeq ($(filter __ICC,$(CCDEFS)),__ICC) +CCTYPE := icc +else +CCTYPE := gcc +endif +cctype: + @$(ECHO) $(CCTYPE) + +############################################################################### +# # Check for tools that can cause failed builds # .toolcheck : @@ -103,10 +127,30 @@ oldgas : # default, even when -ffreestanding is specified. We therefore need # to disable -fstack-protector if the compiler supports it. # +ifeq ($(CCTYPE),gcc) SP_TEST = $(CC) -fno-stack-protector -x c -c /dev/null \ -o /dev/null >/dev/null 2>&1 SP_FLAGS := $(shell $(SP_TEST) && $(ECHO) '-fno-stack-protector') CFLAGS += $(SP_FLAGS) +endif + +# gcc 4.4 generates .eh_frame sections by default, which distort the +# output of "size". Inhibit this. +# +ifeq ($(CCTYPE),gcc) +CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -x c -c /dev/null \ + -o /dev/null >/dev/null 2>&1 +CFI_FLAGS := $(shell $(CFI_TEST) && $(ECHO) '-fno-dwarf2-cfi-asm') +CFLAGS += $(CFI_FLAGS) +endif + +# Some versions of gas choke on division operators, treating them as +# comment markers. Specifying --divide will work around this problem, +# but isn't available on older gas versions. +# +DIVIDE_TEST = $(AS) --divide /dev/null -o /dev/null 2>/dev/null +DIVIDE_FLAGS := $(shell $(DIVIDE_TEST) && $(ECHO) '--divide') +ASFLAGS += $(DIVIDE_FLAGS) ############################################################################### # @@ -248,6 +292,11 @@ MAKEDEPS += arch/$(ARCH)/Makefile include arch/$(ARCH)/Makefile endif +# Include architecture-specific include path +ifdef ARCH +INCDIRS += arch/$(ARCH)/include +endif + ############################################################################### # # Source file handling @@ -276,12 +325,45 @@ autosrcs : ifdef BIN +# INCDIRS lists the include path +incdirs : + @$(ECHO) $(INCDIRS) + # Common flags # -CFLAGS += -I include -I arch/$(ARCH)/include -I . -CFLAGS += -Os -ffreestanding -CFLAGS += -Wall -W -Wformat-nonliteral +CFLAGS += $(foreach INC,$(INCDIRS),-I$(INC)) +CFLAGS += -Os CFLAGS += -g +ifeq ($(CCTYPE),gcc) +CFLAGS += -ffreestanding +CFLAGS += -Wall -W -Wformat-nonliteral +endif +ifeq ($(CCTYPE),icc) +CFLAGS += -fno-builtin +CFLAGS += -no-ip +CFLAGS += -no-gcc +CFLAGS += -diag-disable 111 # Unreachable code +CFLAGS += -diag-disable 128 # Unreachable loop +CFLAGS += -diag-disable 170 # Array boundary checks +CFLAGS += -diag-disable 177 # Unused functions +CFLAGS += -diag-disable 181 # printf() format checks +CFLAGS += -diag-disable 188 # enum strictness +CFLAGS += -diag-disable 193 # Undefined preprocessor identifiers +CFLAGS += -diag-disable 280 # switch ( constant ) +CFLAGS += -diag-disable 310 # K&R parameter lists +CFLAGS += -diag-disable 424 # Extra semicolon +CFLAGS += -diag-disable 589 # Declarations mid-code +CFLAGS += -diag-disable 593 # Unused variables +CFLAGS += -diag-disable 810 # Casting ints to smaller ints +CFLAGS += -diag-disable 981 # Sequence point violations +CFLAGS += -diag-disable 1292 # Ignored attributes +CFLAGS += -diag-disable 1338 # void pointer arithmetic +CFLAGS += -diag-disable 1361 # Variable-length arrays +CFLAGS += -diag-disable 1418 # Missing prototypes +CFLAGS += -diag-disable 1419 # Missing prototypes +CFLAGS += -diag-disable 1599 # Hidden variables +CFLAGS += -Wall -Wmissing-declarations +endif CFLAGS += $(EXTRA_CFLAGS) ASFLAGS += $(EXTRA_ASFLAGS) LDFLAGS += $(EXTRA_LDFLAGS) @@ -314,11 +396,21 @@ OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) $(BIN)/%.flags : @$(ECHO) $(OBJ_CFLAGS) +# ICC requires postprocessing objects to fix up table alignments +# +ifeq ($(CCTYPE),icc) +POST_O = && $(ICCFIX) $@ +POST_O_DEPS := $(ICCFIX) +else +POST_O := +POST_O_DEPS := +endif + # Rules for specific object types. # COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) -RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ -RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(OBJECT)=$* -c $< -o $@ +RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O) +RULE_c_to_dbg%.o = $(Q)$(COMPILE_c) -Ddebug_$(subst -,_,$(OBJECT))=$* -c $< -o $@ $(POST_O) RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ @@ -346,39 +438,25 @@ define src_template @$(MKDIR) -p $(dir $(2)) @$(RM) $(2) @$(TOUCH) $(2) - $(foreach OBJ,$(if $(OBJS_$(4)),$(OBJS_$(4)),$(4)), \ - $(call obj_template,$(1),$(2),$(3),$(OBJ))) - @$(PARSEROM) $(1) >> $(2) - -endef - -# obj_template : generate Makefile rules for a given resultant object -# of a particular source file. (We can have multiple objects per -# source file via the OBJS_xxx list.) -# -# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") -# $(2) is the full path to the .d file (e.g. "bin/deps/drivers/net/rtl8139.d") -# $(3) is the source type (e.g. "c") -# $(4) is the object name (e.g. "rtl8139") -# -define obj_template - @$(CPP) $(CFLAGS) $(CFLAGS_$(3)) $(CFLAGS_$(4)) -DOBJECT=$(4) \ - -Wno-error -MM $(1) -MT "$(4)_DEPS" -MG -MP | \ - sed 's/_DEPS\s*:/_DEPS =/' >> $(2) - @$(ECHO_E) '\n$$(BIN)/$(4).o : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ + -Wno-error -MM $(1) -MG -MP | \ + sed 's/\.o\s*:/_DEPS =/' >> $(2) + @$(ECHO_E) '\n$$(BIN)/$(4).o :' \ + '$(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(4)_DEPS)' \ '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ '\n\t$$(RULE_$(3))\n' \ '\nBOBJS += $$(BIN)/$(4).o\n' \ $(foreach TGT,$(DEBUG_TARGETS), \ $(if $(RULE_$(3)_to_$(TGT)), \ - '\n$$(BIN)/$(4).$(TGT) : $(1) $$(MAKEDEPS) $$($(4)_DEPS)' \ + '\n$$(BIN)/$(4).$(TGT) :' \ + '$(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(4)_DEPS)' \ '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ '\n\t$$(RULE_$(3)_to_$(TGT))\n' \ '\n$(TGT)_OBJS += $$(BIN)/$(4).$(TGT)\n' ) ) \ '\n$(2) : $$($(4)_DEPS)\n' \ '\nTAGS : $$($(4)_DEPS)\n' \ >> $(2) + @$(PARSEROM) $(1) >> $(2) endef @@ -415,7 +493,7 @@ roms : # EMBEDDED_LIST := $(BIN)/.embedded.list ifeq ($(wildcard $(EMBEDDED_LIST)),) -EMBEDDED_LIST_IMAGE := +EMBEDDED_LIST_IMAGE := <invalid> else EMBEDDED_LIST_IMAGE := $(shell cat $(EMBEDDED_LIST)) endif @@ -428,7 +506,7 @@ $(EMBEDDED_LIST) : VERYCLEANUP += $(EMBEDDED_LIST) EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBEDDED_IMAGE)) -EMBED_ALL := $(foreach i,$(shell seq 1 $(words $(EMBEDDED_FILES))),\ +EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\ EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\ \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" )) @@ -550,7 +628,7 @@ $(BIN)/%.info : # BLIB_LIST := $(BIN)/.blib.list ifeq ($(wildcard $(BLIB_LIST)),) -BLIB_LIST_OBJS := +BLIB_LIST_OBJS := <invalid> else BLIB_LIST_OBJS := $(shell cat $(BLIB_LIST)) endif @@ -589,6 +667,55 @@ $(BIN)/%.tmp : $(BLIB) $(MAKEDEPS) $(LDSCRIPT) $(BIN)/%.map : $(BIN)/%.tmp @less $(BIN)/$*.tmp.map +# Get objects list for the specified target +# +define objs_list + $(sort $(foreach OBJ_SYMBOL,\ + $(filter obj_%,$(shell $(NM) $(1) | cut -d" " -f3)),\ + $(patsubst obj_%,%,$(OBJ_SYMBOL)))) +endef +$(BIN)/%.objs : $(BIN)/%.tmp + $(Q)$(ECHO) $(call objs_list,$<) +$(BIN)/%.sizes : $(BIN)/%.tmp + $(Q)$(SIZE) -t $(foreach OBJ,$(call objs_list,$<),$(wildcard $(BIN)/$(subst _,?,$(OBJ)).o)) | \ + sort -g + +# Get dependency list for the specified target +# +define deps_list + $(sort $(foreach OBJ,$(call objs_list,$(1)),$($(OBJ)_DEPS))) +endef +$(BIN)/%.deps : $(BIN)/%.tmp + $(Q)$(ECHO) $(call deps_list,$<) + +# Get unneeded source files for the specified target +# +define nodeps_list + $(sort $(filter-out $(call deps_list,$(1)),\ + $(foreach BOBJ,$(BOBJS),\ + $($(basename $(notdir $(BOBJ)))_DEPS)))) +endef +$(BIN)/%.nodeps : $(BIN)/%.tmp + $(Q)$(ECHO) $(call nodeps_list,$<) + +# Get licensing verdict for the specified target +# +define unlicensed_deps_list + $(shell grep -L FILE_LICENCE $(call deps_list,$(1))) +endef +define licence_list + $(patsubst __licence_%,%,\ + $(filter __licence_%,$(shell $(NM) $(1) | cut -d" " -f3))) +endef +$(BIN)/%.licence : $(BIN)/%.tmp + $(QM)$(ECHO) " [LICENCE] $@" + $(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\ + echo -n "Unable to determine licence because the following " ;\ + echo "files are missing a licence declaration:" ;\ + echo $(call unlicensed_deps_list,$<);\ + exit 1,\ + $(LICENCE) $(call licence_list,$<)) + # Extract compression information from intermediate object file # $(BIN)/%.zinfo : $(BIN)/%.tmp @@ -649,6 +776,7 @@ define media_template @$(ECHO_E) '$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin' \ '\n\t$$(QM)$(ECHO) " [FINISH] $$@"' \ '\n\t$$(Q)$$(CP) $$< $$@' \ + '\n\t$$(Q)$$(PAD_$(1))' \ '\n\t$$(Q)$$(FINALISE_$(1))' \ > $(2) @@ -702,6 +830,9 @@ endif # defined(BIN) # FINALISE_rom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ -i$(IDENT) -s 0 $@ +FINALISE_hrom = $(FINALISE_rom) +FINALISE_xrom = $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \ + -i$(IDENT) -n -s 0 $@ # Some ROMs require specific flags to be passed to makerom.pl # @@ -726,16 +857,18 @@ CLEANUP += $(ZBIN) # # The EFI image converter # +ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \ + -idirafter include -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib \ + -lbfd -liberty -lz + $(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -DMDE_CPU_IA32 -idirafter include -O2 \ - -o $@ $< -lbfd -liberty + $(Q)$(HOST_CC) $(ELF2EFI_CFLAGS) -DMDE_CPU_IA32 -O2 -o $@ $< CLEANUP += $(ELF2EFI32) $(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -DMDE_CPU_X64 -idirafter include -O2 \ - -o $@ $< -lbfd -liberty + $(Q)$(HOST_CC) $(ELF2EFI_CFLAGS) -DMDE_CPU_X64 -O2 -o $@ $< CLEANUP += $(ELF2EFI64) $(EFIROM) : util/efirom.c $(MAKEDEPS) @@ -745,6 +878,15 @@ CLEANUP += $(EFIROM) ############################################################################### # +# The ICC fixup utility +# +$(ICCFIX) : util/iccfix.c $(MAKEDEPS) + $(QM)$(ECHO) " [HOSTCC] $@" + $(Q)$(HOST_CC) -idirafter include -O2 -o $@ $< +CLEANUP += $(ICCFIX) + +############################################################################### +# # Auto-incrementing build serial number. Append "bs" to your list of # build targets to get a serial number printed at the end of the # build. Enable -DBUILD_SERIAL in order to see it when the code runs. @@ -823,20 +965,24 @@ endif # defined(BIN) ifdef BIN $(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS) - $(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \ + $(Q)$(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \ + -e 's{\@INCDIRS\@}{$(filter-out .,$(INCDIRS))}; ' \ -e 's{\@BIN\@}{$(BIN)}; ' \ -e 's{\@ARCH\@}{$(ARCH)}; ' \ $< > $@ $(BIN)/doc : $(BIN)/doxygen.cfg - $(DOXYGEN) $< + $(Q)$(DOXYGEN) $< .PHONY : $(BIN)/doc -VERYCLEANUP += $(BIN)/doc - doc : $(BIN)/doc +doc-clean : + $(Q)$(RM) -r $(BIN)/doc + +VERYCLEANUP += $(BIN)/doc + docview : @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc @if [ -n "$$BROWSER" ] ; then \ diff --git a/gpxe/src/README.pixify b/gpxe/src/README.pixify deleted file mode 100644 index 9aef25d9..00000000 --- a/gpxe/src/README.pixify +++ /dev/null @@ -1,90 +0,0 @@ -This file documents the driver changes needed to support use as part -of a PXE stack. - -PROPER WAY -========== - -1. The probe() routine. - -There are three additional fields that need to be filled in the nic -structure: ioaddr, irqno and irq. - - ioaddr is the base I/O address and seems to be for information only; - no use will be made of this value other than displaying it on the - screen. - - irqno must be the IRQ number for the NIC. For PCI NICs this can - simply be copied from pci->irq. - - irq is a function pointer, like poll and transmit. It must point to - the driver's irq() function. - -2. The poll() routine. - -This must take an additional parameter: "int retrieve". Calling -poll() with retrieve!=0 should function exactly as before. Calling -poll() with retrieve==0 indicates that poll() should check for the -presence of a packet to read, but must *not* read the packet. The -packet will be read by a subsequent call to poll() with retrieve!=0. - -The easiest way to implement this is to insert the line - if ( ! retrieve ) return 1; -between the "is there a packet ready" and the "fetch packet" parts of -the existing poll() routine. - -Care must be taken that a call to poll() with retrieve==0 does not -clear the NIC's "packet ready" status indicator, otherwise the -subsequent call to poll() with retrieve!=0 will fail because it will -think that there is no packet to read. - -poll() should also acknowledge and clear the NIC's "packet received" -interrupt. It does not need to worry about enabling/disabling -interrupts; this is taken care of by calls to the driver's irq() -routine. - -Etherboot will forcibly regenerate an interrupt if a packet remains -pending after all interrupts have been acknowledged. You can -therefore get away with having poll() just acknolwedge and clear all -NIC interrupts, without particularly worrying about exactly when this -should be done. - -3. The irq() routine. - -This is a new routine, with prototype - void DRIVER_irq ( struct nic *nic, irq_action_t action ); -"action" takes one of three possible values: ENABLE, DISABLE or FORCE. -ENABLE and DISABLE mean to enable/disable the NIC's "packet received" -interrupt. FORCE means that the NIC should be forced to generate a -fake "packet received" interrupt. - -If you are unable to implement FORCE, your NIC will not work when -being driven via the UNDI interface under heavy network traffic -conditions. Since Etherboot's UNDI driver (make bin/undi.zpxe) is the -only program known to use this interface, it probably doesn't really -matter. - - -QUICK AND DIRTY WAY -=================== - -It is possible to use the system timer interrupt (IRQ 0) rather than a -genuine NIC interrupt. Since there is a constant stream of timer -interrupts, the net upshot is a whole load of spurious "NIC" -interrupts that have no effect other than to cause unnecessary PXE API -calls. It's inefficient but it works. - -To achieve this, simply set nic->irqno=0 in probe() and point nic->irq -to a dummy routine that does nothing. Add the line - if ( ! retrieve ) return 1; -at the beginning of poll(), to prevent the packet being read (and -discarded) when poll() is called with retrieve==0; - - -UNCONVERTED DRIVERS -=================== - -Drivers that have not yet been converted should continue to function -when not used as part of a PXE stack, although there will be a -harmless compile-time warning about assignment from an incompatible -pointer type in the probe() function, since the prototype for the -poll() function is missing the "int retrieve" parameter. diff --git a/gpxe/src/arch/i386/Makefile b/gpxe/src/arch/i386/Makefile index 1392bbac..dd8da802 100644 --- a/gpxe/src/arch/i386/Makefile +++ b/gpxe/src/arch/i386/Makefile @@ -4,22 +4,33 @@ CFLAGS += -march=i386 # Code size reduction. # -CFLAGS += -fstrength-reduce -fomit-frame-pointer +CFLAGS += -fomit-frame-pointer + +# Code size reduction. +# +ifeq ($(CCTYPE),gcc) +CFLAGS += -fstrength-reduce +endif # Code size reduction. gcc3 needs a different syntax to gcc2 if you # want to avoid spurious warnings. # +ifeq ($(CCTYPE),gcc) GCC_VERSION := $(subst ., ,$(shell $(CC) -dumpversion)) GCC_MAJOR := $(firstword $(GCC_VERSION)) ifeq ($(GCC_MAJOR),2) CFLAGS += -malign-jumps=1 -malign-loops=1 -malign-functions=1 else CFLAGS += -falign-jumps=1 -falign-loops=1 -falign-functions=1 -endif +endif # gcc2 +endif # gcc -# Code size reduction. This is almost always a win. The kernel uses it, too. +# Code size reduction. This is almost always a win. The kernel uses +# it, too. # +ifeq ($(CCTYPE),gcc) CFLAGS += -mpreferred-stack-boundary=2 +endif # Code size reduction. Use regparm for all functions - C functions # called from assembly (or vice versa) need __asmcall now @@ -27,7 +38,9 @@ CFLAGS += -mpreferred-stack-boundary=2 CFLAGS += -mregparm=3 # Code size reduction. Use -mrtd (same __asmcall requirements as above) +ifeq ($(CCTYPE),gcc) CFLAGS += -mrtd +endif # Code size reduction. This is the logical complement to -mregparm=3. # It doesn't currently buy us anything, but if anything ever tries to @@ -67,7 +80,9 @@ SRCDIRS += arch/i386/drivers SRCDIRS += arch/i386/drivers/net SRCDIRS += arch/i386/interface/pcbios SRCDIRS += arch/i386/interface/pxe +SRCDIRS += arch/i386/interface/pxeparent SRCDIRS += arch/i386/interface/syslinux +SRCDIRS += arch/i386/hci/commands # The various xxx_loader.c files are #included into core/loader.c and # should not be compiled directly. @@ -76,11 +91,6 @@ NON_AUTO_SRCS += arch/i386/core/aout_loader.c NON_AUTO_SRCS += arch/i386/core/freebsd_loader.c NON_AUTO_SRCS += arch/i386/core/wince_loader.c -# unnrv2b.S is used to generate a 16-bit as well as a 32-bit object. -# -OBJS_unnrv2b = unnrv2b unnrv2b16 -CFLAGS_unnrv2b16 = -DCODE16 - # Include common x86 Makefile # MAKEDEPS += arch/x86/Makefile @@ -101,13 +111,6 @@ NON_AUTO_MEDIA += fd0 $(Q)dd if=$< bs=512 conv=sync of=/dev/fd0 $(Q)sync -# rule to create padded disk images -NON_AUTO_MEDIA += pdsk -%pdsk : %dsk - $(QM)$(ECHO) " [DSKPAD] $@" - $(Q)cp $< $@ - $(Q)$(PERL) ./util/dskpad.pl $@ - # Add NON_AUTO_MEDIA to the media list, so that they show up in the # output of "make" # diff --git a/gpxe/src/arch/i386/Makefile.pcbios b/gpxe/src/arch/i386/Makefile.pcbios index 64b3dac2..e38fbca0 100644 --- a/gpxe/src/arch/i386/Makefile.pcbios +++ b/gpxe/src/arch/i386/Makefile.pcbios @@ -11,21 +11,24 @@ LDFLAGS += -N --no-check-sections # Media types. # MEDIA += rom +MEDIA += hrom +MEDIA += xrom MEDIA += pxe MEDIA += kpxe MEDIA += kkpxe -MEDIA += elf -MEDIA += elfd -MEDIA += lmelf -MEDIA += lmelfd MEDIA += lkrn -MEDIA += bImage MEDIA += dsk MEDIA += nbi MEDIA += hd MEDIA += raw -MEDIA += com -MEDIA += exe + +# Padding rules +# +PAD_rom = $(PADIMG) --blksize=512 --byte=0xff $@ +PAD_hrom = $(PAD_rom) +PAD_xrom = $(PAD_rom) +PAD_dsk = $(PADIMG) --blksize=512 $@ +PAD_hd = $(PADIMG) --blksize=32768 $@ # rule to make a non-emulation ISO boot image NON_AUTO_MEDIA += iso @@ -39,6 +42,12 @@ NON_AUTO_MEDIA += liso $(QM)$(ECHO) " [GENLISO] $@" $(Q)bash util/genliso $@ $< +# rule to make a syslinux floppy image (mountable, bootable) +NON_AUTO_MEDIA += sdsk +%sdsk: %lkrn util/gensdsk + $(QM)$(ECHO) " [GENSDSK] $@" + $(Q)bash util/gensdsk $@ $< + # Special target for building Master Boot Record binary $(BIN)/mbr.bin : $(BIN)/mbr.o $(QM)$(ECHO) " [OBJCOPY] $@" @@ -53,3 +62,9 @@ NON_AUTO_MEDIA += usb %usb: $(BIN)/usbdisk.bin %hd $(QM)$(ECHO) " [FINISH] $@" $(Q)cat $^ > $@ + +# Padded floppy image (e.g. for iLO) +NON_AUTO_MEDIA += pdsk +%pdsk : %dsk + $(Q)cp $< $@ + $(Q)$(PADIMG) --blksize=1474560 $@ diff --git a/gpxe/src/arch/i386/core/basemem_packet.c b/gpxe/src/arch/i386/core/basemem_packet.c index 64e0bcc1..d487cce3 100644 --- a/gpxe/src/arch/i386/core/basemem_packet.c +++ b/gpxe/src/arch/i386/core/basemem_packet.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/arch/i386/core/etherboot.prefix.lds b/gpxe/src/arch/i386/core/etherboot.prefix.lds deleted file mode 100644 index 3550a2a3..00000000 --- a/gpxe/src/arch/i386/core/etherboot.prefix.lds +++ /dev/null @@ -1,100 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) - -ENTRY(_prefix_start) -SECTIONS { - /* Prefix */ - .prefix : { - _verbatim_start = . ; - _prefix_start = . ; - *(.prefix) - . = ALIGN(16); - _prefix_end = . ; - } = 0x9090 - _prefix_size = _prefix_end - _prefix_start; - - .text.nocompress : { - *(.prefix.udata) - } = 0x9090 - - decompress_to = . ; - .prefix.zdata : { - _compressed = . ; - *(.prefix.zdata) - _compressed_end = . ; - } - _compressed_size = _compressed_end - _compressed; - - . = ALIGN(16); - _verbatim_end = . ; - - - /* Size of the core of etherboot in memory */ - _base_size = _end - _text; - - /* _prefix_size is the length of the non-core etherboot prefix */ - _prefix_size = _prefix_end - _prefix_start; - - /* _verbatim_size is the actual amount that has to be copied to base memory */ - _verbatim_size = _verbatim_end - _verbatim_start; - - /* _image_size is the amount of base memory needed to run */ - _image_size = _base_size + _prefix_size; - - /* Standard sizes rounded up to paragraphs */ - _prefix_size_pgh = (_prefix_size + 15) / 16; - _verbatim_size_pgh = (_verbatim_size + 15) / 16; - _image_size_pgh = (_image_size + 15) / 16 ; - - /* Standard sizes in sectors */ - _prefix_size_sct = (_prefix_size + 511) / 512; - _verbatim_size_sct = (_verbatim_size + 511) / 512; - _image_size_sct = (_image_size + 511) / 512; - - /* Symbol offsets and sizes for the exe prefix */ - _exe_hdr_size = 32; - _exe_size = _verbatim_size; /* Should this be - 32 to exclude the header? */ - _exe_size_tail = (_exe_size) % 512; - _exe_size_pages = ((_exe_size) + 511) / 512; - _exe_bss_size = ((_image_size - _verbatim_size) + 15) / 16; - _exe_ss_offset = (_stack_offset + _prefix_size - _exe_hdr_size + 15) / 16 ; - - /* This is where we copy the compressed image before decompression. - * Prepare to decompress in place. The end mark is about 8.25 bytes long, - * and the worst case symbol is about 16.5 bytes long. Therefore - * We need to reserve at least 25 bytes of slack here. - * Currently I reserve 2048 bytes of just slack to be safe :) - * 2048 bytes easily falls within the BSS (the defualt stack is 4096 bytes) - * so we really are decompressing in place. - * - * Hmm. I missed a trick. In the very worst case (no compression) - * the encoded data is 9/8 the size as it started out so to be completely - * safe I need to be 1/8 of the uncompressed code size past the end. - * This will still fit compfortably into our bss in any conceivable scenario. - */ - _compressed_copy = _edata + _prefix_size - _compressed_size + - /* The amount to overflow _edata */ - MAX( ((_edata - _text + 7) / 8) , 2016 ) + 32; - _assert = ASSERT( ( _compressed_copy - _prefix_size ) < _ebss , "Cannot decompress in place" ) ; - - decompress = DEFINED(decompress) ? decompress : 0; - /DISCARD/ : { - *(.comment) - *(.note) - } - - /* Symbols used by the prefixes whose addresses are inconvinient - * to compute, at runtime in the code. - */ - image_basemem_size = DEFINED(image_basemem_size)? image_basemem_size : 65536; - image_basemem = DEFINED(image_basemem)? image_basemem : 65536; - _prefix_real_to_prot = _real_to_prot + _prefix_size ; - _prefix_prot_to_real = _prot_to_real + _prefix_size ; - _prefix_image_basemem_size = image_basemem_size + _prefix_size ; - _prefix_image_basemem = image_basemem + _prefix_size ; - _prefix_rm_in_call = _rm_in_call + _prefix_size ; - _prefix_in_call = _in_call + _prefix_size ; - _prefix_rom = rom + _prefix_size ; - _prefix_rm_etherboot_location = rm_etherboot_location + _prefix_size ; - _prefix_stack_end = _stack_end + _prefix_size ; -} diff --git a/gpxe/src/arch/i386/core/pic8259.c b/gpxe/src/arch/i386/core/pic8259.c index 8a0433dd..1e2d23c5 100644 --- a/gpxe/src/arch/i386/core/pic8259.c +++ b/gpxe/src/arch/i386/core/pic8259.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/io.h> #include <pic8259.h> diff --git a/gpxe/src/arch/i386/core/prefixudata.lds b/gpxe/src/arch/i386/core/prefixudata.lds deleted file mode 100644 index 1c76128e..00000000 --- a/gpxe/src/arch/i386/core/prefixudata.lds +++ /dev/null @@ -1,8 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) - -SECTIONS { - .prefix.udata : { - *(*) - } -} diff --git a/gpxe/src/arch/i386/core/prefixzdata.lds b/gpxe/src/arch/i386/core/prefixzdata.lds deleted file mode 100644 index bf6ea977..00000000 --- a/gpxe/src/arch/i386/core/prefixzdata.lds +++ /dev/null @@ -1,8 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) - -SECTIONS { - .prefix.zdata : { - *(*) - } -} diff --git a/gpxe/src/arch/i386/core/rdtsc_timer.c b/gpxe/src/arch/i386/core/rdtsc_timer.c index 443c8ada..76679173 100644 --- a/gpxe/src/arch/i386/core/rdtsc_timer.c +++ b/gpxe/src/arch/i386/core/rdtsc_timer.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** @file * * RDTSC timer diff --git a/gpxe/src/arch/i386/core/realmode.c b/gpxe/src/arch/i386/core/realmode.c deleted file mode 100644 index 9a77bd8a..00000000 --- a/gpxe/src/arch/i386/core/realmode.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Real-mode interface: C portions. - * - * Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004. - */ - -#include "realmode.h" - -/* - * Copy data to/from base memory. - * - */ - -#ifdef KEEP_IT_REAL - -void memcpy_to_real ( segoff_t dest, void *src, size_t n ) { - -} - -void memcpy_from_real ( void *dest, segoff_t src, size_t n ) { - -} - -#endif /* KEEP_IT_REAL */ diff --git a/gpxe/src/arch/i386/core/relocate.c b/gpxe/src/arch/i386/core/relocate.c index bdc8498e..44e764fe 100644 --- a/gpxe/src/arch/i386/core/relocate.c +++ b/gpxe/src/arch/i386/core/relocate.c @@ -9,6 +9,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + /* * The linker passes in the symbol _max_align, which is the alignment * that we must preserve, in bytes. diff --git a/gpxe/src/arch/i386/core/setjmp.S b/gpxe/src/arch/i386/core/setjmp.S index 59a1b7cb..03727148 100644 --- a/gpxe/src/arch/i386/core/setjmp.S +++ b/gpxe/src/arch/i386/core/setjmp.S @@ -1,5 +1,7 @@ /* setjmp and longjmp. Use of these functions is deprecated. */ +FILE_LICENCE ( GPL2_OR_LATER ) + .text .arch i386 .code32 diff --git a/gpxe/src/arch/i386/core/stack.S b/gpxe/src/arch/i386/core/stack.S index da66d239..737ec0ee 100644 --- a/gpxe/src/arch/i386/core/stack.S +++ b/gpxe/src/arch/i386/core/stack.S @@ -1,3 +1,5 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + .arch i386 /**************************************************************************** diff --git a/gpxe/src/arch/i386/core/stack16.S b/gpxe/src/arch/i386/core/stack16.S index d1251f06..523f0288 100644 --- a/gpxe/src/arch/i386/core/stack16.S +++ b/gpxe/src/arch/i386/core/stack16.S @@ -1,3 +1,5 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + .arch i386 /**************************************************************************** diff --git a/gpxe/src/arch/i386/core/start16.lds b/gpxe/src/arch/i386/core/start16.lds deleted file mode 100644 index 544fc78f..00000000 --- a/gpxe/src/arch/i386/core/start16.lds +++ /dev/null @@ -1,8 +0,0 @@ -/* When linking with an uncompressed image, these symbols are not - * defined so we provide them here. - */ - -__decompressor_uncompressed = 0 ; -__decompressor__start = 0 ; - -INCLUDE arch/i386/core/start16z.lds diff --git a/gpxe/src/arch/i386/core/start16z.lds b/gpxe/src/arch/i386/core/start16z.lds deleted file mode 100644 index 711bcf7b..00000000 --- a/gpxe/src/arch/i386/core/start16z.lds +++ /dev/null @@ -1,65 +0,0 @@ -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) - -/* Linker-generated symbols are prefixed with a double underscore. - * Decompressor symbols are prefixed with __decompressor_. All other - * symbols are the same as in the original object file, i.e. the - * runtime addresses. - */ - -ENTRY(_start16) - -SECTIONS { - .text : { - *(.text) - } - .payload : { - __payload_start = .; - *(.data) - __payload_end = .; - } - - /* _payload_size is the size of the binary image appended to - * start16, in bytes. - */ - __payload_size = __payload_end - __payload_start ; - - /* _size is the size of the runtime image - * (start32 + the C code), in bytes. - */ - __size = _end - _start ; - - /* _decompressor_size is the size of the decompressor, in - * bytes. For a non-compressed image, start16.lds sets - * _decompressor_uncompressed = _decompressor__start = 0. - */ - __decompressor_size = __decompressor_uncompressed - __decompressor__start ; - - /* image__size is the total size of the image, after - * decompression and including the decompressor if applicable. - * It is therefore the amount of memory that start16's payload - * needs in order to execute, in bytes. - */ - __image_size = __size + __decompressor_size ; - - /* Amount to add to runtime symbols to obtain the offset of - * that symbol within the image. - */ - __offset_adjust = __decompressor_size - _start ; - - /* Calculations for the stack - */ - __stack_size = _estack - _stack ; - __offset_stack = _stack + __offset_adjust ; - - /* Some symbols will be larger than 16 bits but guaranteed to - * be multiples of 16. We calculate them in paragraphs and - * export these symbols which can be used in 16-bit code - * without risk of overflow. - */ - __image_size_pgh = ( __image_size / 16 ); - __start_pgh = ( _start / 16 ); - __decompressor_size_pgh = ( __decompressor_size / 16 ); - __offset_stack_pgh = ( __offset_stack / 16 ); -} - diff --git a/gpxe/src/arch/i386/core/timer2.c b/gpxe/src/arch/i386/core/timer2.c index bb589ecc..6e76b2eb 100644 --- a/gpxe/src/arch/i386/core/timer2.c +++ b/gpxe/src/arch/i386/core/timer2.c @@ -11,6 +11,8 @@ * your option) any later version. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stddef.h> #include <gpxe/timer2.h> #include <gpxe/io.h> diff --git a/gpxe/src/arch/i386/core/virtaddr.S b/gpxe/src/arch/i386/core/virtaddr.S index cf6da4f6..aae1e1ed 100644 --- a/gpxe/src/arch/i386/core/virtaddr.S +++ b/gpxe/src/arch/i386/core/virtaddr.S @@ -4,6 +4,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ) + #include "librm.h" .arch i386 diff --git a/gpxe/src/arch/i386/core/x86_io.c b/gpxe/src/arch/i386/core/x86_io.c index 424a96cc..d2c363b9 100644 --- a/gpxe/src/arch/i386/core/x86_io.c +++ b/gpxe/src/arch/i386/core/x86_io.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/io.h> #include <gpxe/x86_io.h> diff --git a/gpxe/src/arch/i386/drivers/net/undi.c b/gpxe/src/arch/i386/drivers/net/undi.c index 1090cc94..c6e253c0 100644 --- a/gpxe/src/arch/i386/drivers/net/undi.c +++ b/gpxe/src/arch/i386/drivers/net/undi.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <stdio.h> @@ -135,7 +137,7 @@ static void undipci_remove ( struct pci_device *pci ) { } static struct pci_device_id undipci_nics[] = { -PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)" ), +PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ), }; struct pci_driver undipci_driver __pci_driver = { diff --git a/gpxe/src/arch/i386/drivers/net/undiisr.S b/gpxe/src/arch/i386/drivers/net/undiisr.S index 2b31b414..b27effe1 100644 --- a/gpxe/src/arch/i386/drivers/net/undiisr.S +++ b/gpxe/src/arch/i386/drivers/net/undiisr.S @@ -1,3 +1,5 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + #define PXENV_UNDI_ISR 0x0014 #define PXENV_UNDI_ISR_IN_START 1 #define PXENV_UNDI_ISR_OUT_OURS 0 @@ -29,7 +31,7 @@ undiisr: movw %ax, %ds /* Check that we have an UNDI entry point */ - cmpw $0, undinet_entry_point + cmpw $0, pxeparent_entry_point je chain /* Issue UNDI API call */ @@ -40,7 +42,7 @@ undiisr: pushw %es pushw %di pushw %bx - lcall *undinet_entry_point + lcall *pxeparent_entry_point cli /* Just in case */ addw $6, %sp cmpw $PXENV_UNDI_ISR_OUT_OURS, funcflag diff --git a/gpxe/src/arch/i386/drivers/net/undiload.c b/gpxe/src/arch/i386/drivers/net/undiload.c index dbd9e7c2..1d4e88d7 100644 --- a/gpxe/src/arch/i386/drivers/net/undiload.c +++ b/gpxe/src/arch/i386/drivers/net/undiload.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -90,11 +92,10 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { undi_loader_entry = undirom->loader_entry; __asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t" "pushw %%ax\n\t" - "lcall *%c2\n\t" + "lcall *undi_loader_entry\n\t" "addw $4, %%sp\n\t" ) : "=a" ( exit ) - : "a" ( __from_data16 ( &undi_loader ) ), - "p" ( __from_data16 ( &undi_loader_entry ) ) + : "a" ( __from_data16 ( &undi_loader ) ) : "ebx", "ecx", "edx", "esi", "edi", "ebp" ); /* UNDI API calls may rudely change the status of A20 and not diff --git a/gpxe/src/arch/i386/drivers/net/undinet.c b/gpxe/src/arch/i386/drivers/net/undinet.c index d6db6f7c..83b79e7f 100644 --- a/gpxe/src/arch/i386/drivers/net/undinet.c +++ b/gpxe/src/arch/i386/drivers/net/undinet.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <pxe.h> #include <realmode.h> @@ -30,6 +32,7 @@ #include <gpxe/ethernet.h> #include <undi.h> #include <undinet.h> +#include <pxeparent.h> /** @file @@ -60,179 +63,8 @@ struct undi_nic { static void undinet_close ( struct net_device *netdev ); -/***************************************************************************** - * - * UNDI API call - * - ***************************************************************************** - */ - -/** - * Name UNDI API call - * - * @v function API call number - * @ret name API call name - */ -static inline __attribute__ (( always_inline )) const char * -undinet_function_name ( unsigned int function ) { - switch ( function ) { - case PXENV_START_UNDI: - return "PXENV_START_UNDI"; - case PXENV_STOP_UNDI: - return "PXENV_STOP_UNDI"; - case PXENV_UNDI_STARTUP: - return "PXENV_UNDI_STARTUP"; - case PXENV_UNDI_CLEANUP: - return "PXENV_UNDI_CLEANUP"; - case PXENV_UNDI_INITIALIZE: - return "PXENV_UNDI_INITIALIZE"; - case PXENV_UNDI_RESET_ADAPTER: - return "PXENV_UNDI_RESET_ADAPTER"; - case PXENV_UNDI_SHUTDOWN: - return "PXENV_UNDI_SHUTDOWN"; - case PXENV_UNDI_OPEN: - return "PXENV_UNDI_OPEN"; - case PXENV_UNDI_CLOSE: - return "PXENV_UNDI_CLOSE"; - case PXENV_UNDI_TRANSMIT: - return "PXENV_UNDI_TRANSMIT"; - case PXENV_UNDI_SET_MCAST_ADDRESS: - return "PXENV_UNDI_SET_MCAST_ADDRESS"; - case PXENV_UNDI_SET_STATION_ADDRESS: - return "PXENV_UNDI_SET_STATION_ADDRESS"; - case PXENV_UNDI_SET_PACKET_FILTER: - return "PXENV_UNDI_SET_PACKET_FILTER"; - case PXENV_UNDI_GET_INFORMATION: - return "PXENV_UNDI_GET_INFORMATION"; - case PXENV_UNDI_GET_STATISTICS: - return "PXENV_UNDI_GET_STATISTICS"; - case PXENV_UNDI_CLEAR_STATISTICS: - return "PXENV_UNDI_CLEAR_STATISTICS"; - case PXENV_UNDI_INITIATE_DIAGS: - return "PXENV_UNDI_INITIATE_DIAGS"; - case PXENV_UNDI_FORCE_INTERRUPT: - return "PXENV_UNDI_FORCE_INTERRUPT"; - case PXENV_UNDI_GET_MCAST_ADDRESS: - return "PXENV_UNDI_GET_MCAST_ADDRESS"; - case PXENV_UNDI_GET_NIC_TYPE: - return "PXENV_UNDI_GET_NIC_TYPE"; - case PXENV_UNDI_GET_IFACE_INFO: - return "PXENV_UNDI_GET_IFACE_INFO"; - /* - * Duplicate case value; this is a bug in the PXE specification. - * - * case PXENV_UNDI_GET_STATE: - * return "PXENV_UNDI_GET_STATE"; - */ - case PXENV_UNDI_ISR: - return "PXENV_UNDI_ISR"; - default: - return "UNKNOWN API CALL"; - } -} - -/** - * UNDI parameter block - * - * Used as the paramter block for all UNDI API calls. Resides in base - * memory. - */ -static union u_PXENV_ANY __bss16 ( undinet_params ); -#define undinet_params __use_data16 ( undinet_params ) - -/** UNDI entry point - * - * Used as the indirection vector for all UNDI API calls. Resides in - * base memory. - */ -SEGOFF16_t __bss16 ( undinet_entry_point ); -#define undinet_entry_point __use_data16 ( undinet_entry_point ) - -/** - * Issue UNDI API call - * - * @v undinic UNDI NIC - * @v function API call number - * @v params UNDI parameter block - * @v params_len Length of UNDI parameter block - * @ret rc Return status code - */ -static int undinet_call ( struct undi_nic *undinic, unsigned int function, - void *params, size_t params_len ) { - PXENV_EXIT_t exit; - int discard_b, discard_D; - int rc; - - /* Copy parameter block and entry point */ - assert ( params_len <= sizeof ( undinet_params ) ); - memcpy ( &undinet_params, params, params_len ); - - /* Call real-mode entry point. This calling convention will - * work with both the !PXE and the PXENV+ entry points. - */ - __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t" - "pushw %%di\n\t" - "pushw %%bx\n\t" - "lcall *%c3\n\t" - "addw $6, %%sp\n\t" ) - : "=a" ( exit ), "=b" ( discard_b ), - "=D" ( discard_D ) - : "p" ( __from_data16 ( &undinet_entry_point )), - "b" ( function ), - "D" ( __from_data16 ( &undinet_params ) ) - : "ecx", "edx", "esi", "ebp" ); - - /* UNDI API calls may rudely change the status of A20 and not - * bother to restore it afterwards. Intel is known to be - * guilty of this. - * - * Note that we will return to this point even if A20 gets - * screwed up by the UNDI driver, because Etherboot always - * resides in an even megabyte of RAM. - */ - gateA20_set(); - - /* Determine return status code based on PXENV_EXIT and - * PXENV_STATUS - */ - if ( exit == PXENV_EXIT_SUCCESS ) { - rc = 0; - } else { - rc = -undinet_params.Status; - /* Paranoia; don't return success for the combination - * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS - */ - if ( rc == 0 ) - rc = -EIO; - } - - /* If anything goes wrong, print as much debug information as - * it's possible to give. - */ - if ( rc != 0 ) { - SEGOFF16_t rm_params = { - .segment = rm_ds, - .offset = __from_data16 ( &undinet_params ), - }; - - DBGC ( undinic, "UNDINIC %p %s failed: %s\n", undinic, - undinet_function_name ( function ), strerror ( rc ) ); - DBGC ( undinic, "UNDINIC %p parameters at %04x:%04x length " - "%#02zx, entry point at %04x:%04x\n", undinic, - rm_params.segment, rm_params.offset, params_len, - undinet_entry_point.segment, - undinet_entry_point.offset ); - DBGC ( undinic, "UNDINIC %p parameters provided:\n", undinic ); - DBGC_HDA ( undinic, rm_params, params, params_len ); - DBGC ( undinic, "UNDINIC %p parameters returned:\n", undinic ); - DBGC_HDA ( undinic, rm_params, &undinet_params, params_len ); - } - - /* Copy parameter block back */ - memcpy ( params, &undinet_params, params_len ); - - return rc; -} +/** Address of UNDI entry point */ +static SEGOFF16_t undinet_entry; /***************************************************************************** * @@ -335,7 +167,6 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd ); */ static int undinet_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct undi_nic *undinic = netdev->priv; struct s_PXENV_UNDI_TRANSMIT undi_transmit; size_t len = iob_len ( iobuf ); int rc; @@ -368,9 +199,9 @@ static int undinet_transmit ( struct net_device *netdev, undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet ); /* Issue PXE API call */ - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_TRANSMIT, - &undi_transmit, - sizeof ( undi_transmit ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT, + &undi_transmit, + sizeof ( undi_transmit ) ) ) != 0 ) goto done; /* Free I/O buffer */ @@ -440,8 +271,9 @@ static void undinet_poll ( struct net_device *netdev ) { /* Run through the ISR loop */ while ( 1 ) { - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr, - sizeof ( undi_isr ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR, + &undi_isr, + sizeof ( undi_isr ) ) ) != 0 ) break; switch ( undi_isr.FuncFlag ) { case PXENV_UNDI_ISR_OUT_TRANSMIT: @@ -537,8 +369,8 @@ static int undinet_open ( struct net_device *netdev ) { */ memcpy ( undi_set_address.StationAddress, netdev->ll_addr, sizeof ( undi_set_address.StationAddress ) ); - undinet_call ( undinic, PXENV_UNDI_SET_STATION_ADDRESS, - &undi_set_address, sizeof ( undi_set_address ) ); + pxeparent_call ( undinet_entry, PXENV_UNDI_SET_STATION_ADDRESS, + &undi_set_address, sizeof ( undi_set_address ) ); /* Open NIC. We ask for promiscuous operation, since it's the * only way to ask for all multicast addresses. On any @@ -547,8 +379,8 @@ static int undinet_open ( struct net_device *netdev ) { */ memset ( &undi_open, 0, sizeof ( undi_open ) ); undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS ); - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open, - sizeof ( undi_open ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_OPEN, + &undi_open, sizeof ( undi_open ) ) ) != 0 ) goto err; DBGC ( undinic, "UNDINIC %p opened\n", undinic ); @@ -573,8 +405,9 @@ static void undinet_close ( struct net_device *netdev ) { /* Ensure ISR has exited cleanly */ while ( undinic->isr_processing ) { undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr, - sizeof ( undi_isr ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR, + &undi_isr, + sizeof ( undi_isr ) ) ) != 0 ) break; switch ( undi_isr.FuncFlag ) { case PXENV_UNDI_ISR_OUT_TRANSMIT: @@ -589,8 +422,8 @@ static void undinet_close ( struct net_device *netdev ) { } /* Close NIC */ - undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close, - sizeof ( undi_close ) ); + pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE, + &undi_close, sizeof ( undi_close ) ); /* Disable interrupt and unhook ISR */ disable_irq ( undinic->irq ); @@ -650,7 +483,7 @@ int undinet_probe ( struct undi_device *undi ) { undi_set_drvdata ( undi, netdev ); netdev->dev = &undi->dev; memset ( undinic, 0, sizeof ( *undinic ) ); - undinet_entry_point = undi->entry; + undinet_entry = undi->entry; DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi ); /* Hook in UNDI stack */ @@ -661,9 +494,9 @@ int undinet_probe ( struct undi_device *undi ) { start_undi.DX = undi->isapnp_read_port; start_undi.ES = BIOS_SEG; start_undi.DI = find_pnp_bios(); - if ( ( rc = undinet_call ( undinic, PXENV_START_UNDI, - &start_undi, - sizeof ( start_undi ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_START_UNDI, + &start_undi, + sizeof ( start_undi ) ) ) != 0 ) goto err_start_undi; } undi->flags |= UNDI_FL_STARTED; @@ -671,24 +504,25 @@ int undinet_probe ( struct undi_device *undi ) { /* Bring up UNDI stack */ if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) { memset ( &undi_startup, 0, sizeof ( undi_startup ) ); - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP, - &undi_startup, - sizeof ( undi_startup ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_STARTUP, + &undi_startup, + sizeof ( undi_startup ) ) ) != 0 ) goto err_undi_startup; memset ( &undi_initialize, 0, sizeof ( undi_initialize ) ); - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE, - &undi_initialize, - sizeof ( undi_initialize ))) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, + PXENV_UNDI_INITIALIZE, + &undi_initialize, + sizeof ( undi_initialize ))) != 0 ) goto err_undi_initialize; } undi->flags |= UNDI_FL_INITIALIZED; /* Get device information */ memset ( &undi_info, 0, sizeof ( undi_info ) ); - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_INFORMATION, - &undi_info, sizeof ( undi_info ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_INFORMATION, + &undi_info, sizeof ( undi_info ) ) ) != 0 ) goto err_undi_get_information; - memcpy ( netdev->ll_addr, undi_info.PermNodeAddress, ETH_ALEN ); + memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN ); undinic->irq = undi_info.IntNumber; if ( undinic->irq > IRQ_MAX ) { DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n", @@ -696,16 +530,17 @@ int undinet_probe ( struct undi_device *undi ) { goto err_bad_irq; } DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n", - undinic, eth_ntoa ( netdev->ll_addr ), undinic->irq ); + undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq ); /* Get interface information */ memset ( &undi_iface, 0, sizeof ( undi_iface ) ); - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO, - &undi_iface, - sizeof ( undi_iface ) ) ) != 0 ) + if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_IFACE_INFO, + &undi_iface, + sizeof ( undi_iface ) ) ) != 0 ) goto err_undi_get_iface_info; - DBGC ( undinic, "UNDINIC %p has type %s and link speed %d\n", - undinic, undi_iface.IfaceType, undi_iface.LinkSpeed ); + DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n", + undinic, undi_iface.IfaceType, undi_iface.LinkSpeed, + undi_iface.ServiceFlags ); if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot", sizeof ( undi_iface.IfaceType ) ) == 0 ) { DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n", @@ -730,17 +565,17 @@ int undinet_probe ( struct undi_device *undi ) { err_undi_initialize: /* Shut down UNDI stack */ memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); - undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, - sizeof ( undi_shutdown ) ); + pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, &undi_shutdown, + sizeof ( undi_shutdown ) ); memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); - undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, - sizeof ( undi_cleanup ) ); + pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, &undi_cleanup, + sizeof ( undi_cleanup ) ); undi->flags &= ~UNDI_FL_INITIALIZED; err_undi_startup: /* Unhook UNDI stack */ memset ( &stop_undi, 0, sizeof ( stop_undi ) ); - undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, - sizeof ( stop_undi ) ); + pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi, + sizeof ( stop_undi ) ); undi->flags &= ~UNDI_FL_STARTED; err_start_undi: netdev_nullify ( netdev ); @@ -771,22 +606,22 @@ void undinet_remove ( struct undi_device *undi ) { /* Shut down UNDI stack */ memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); - undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown, - sizeof ( undi_shutdown ) ); + pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, + &undi_shutdown, sizeof ( undi_shutdown ) ); memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); - undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup, - sizeof ( undi_cleanup ) ); + pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, + &undi_cleanup, sizeof ( undi_cleanup ) ); undi->flags &= ~UNDI_FL_INITIALIZED; /* Unhook UNDI stack */ memset ( &stop_undi, 0, sizeof ( stop_undi ) ); - undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, - sizeof ( stop_undi ) ); + pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi, + sizeof ( stop_undi ) ); undi->flags &= ~UNDI_FL_STARTED; } /* Clear entry point */ - memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) ); + memset ( &undinet_entry, 0, sizeof ( undinet_entry ) ); /* Free network device */ netdev_nullify ( netdev ); diff --git a/gpxe/src/arch/i386/drivers/net/undionly.c b/gpxe/src/arch/i386/drivers/net/undionly.c index 4cdce677..7dfb5d15 100644 --- a/gpxe/src/arch/i386/drivers/net/undionly.c +++ b/gpxe/src/arch/i386/drivers/net/undionly.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> diff --git a/gpxe/src/arch/i386/drivers/net/undipreload.c b/gpxe/src/arch/i386/drivers/net/undipreload.c index e29d150a..a4b2f4ac 100644 --- a/gpxe/src/arch/i386/drivers/net/undipreload.c +++ b/gpxe/src/arch/i386/drivers/net/undipreload.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <realmode.h> #include <undipreload.h> diff --git a/gpxe/src/arch/i386/drivers/net/undirom.c b/gpxe/src/arch/i386/drivers/net/undirom.c index e5782781..2463d969 100644 --- a/gpxe/src/arch/i386/drivers/net/undirom.c +++ b/gpxe/src/arch/i386/drivers/net/undirom.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/basemem.c b/gpxe/src/arch/i386/firmware/pcbios/basemem.c index b126d2a7..1ba7d1f6 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/basemem.c +++ b/gpxe/src/arch/i386/firmware/pcbios/basemem.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <realmode.h> #include <bios.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/bios_console.c b/gpxe/src/arch/i386/firmware/pcbios/bios_console.c index 91363772..1d18e54c 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/bios_console.c +++ b/gpxe/src/arch/i386/firmware/pcbios/bios_console.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <assert.h> #include <realmode.h> #include <console.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S index decb0835..99ca519b 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/gpxe/src/arch/i386/firmware/pcbios/e820mangler.S @@ -15,7 +15,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + +FILE_LICENCE ( GPL2_OR_LATER ) + .text .arch i386 .code16 @@ -235,6 +237,7 @@ get_underlying_e820: popw %di incw %bx movl %edx, %eax + clc ret 2: /* If the requested region is earlier than the cached region, diff --git a/gpxe/src/arch/i386/firmware/pcbios/fakee820.c b/gpxe/src/arch/i386/firmware/pcbios/fakee820.c index 552bf41d..ea116fe5 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/fakee820.c +++ b/gpxe/src/arch/i386/firmware/pcbios/fakee820.c @@ -15,6 +15,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <realmode.h> #include <biosint.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c index 34e3ac52..1a71472d 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/gateA20.c +++ b/gpxe/src/arch/i386/firmware/pcbios/gateA20.c @@ -1,3 +1,5 @@ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdio.h> #include <realmode.h> #include <bios.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c index 620b62e0..17082c35 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/hidemem.c +++ b/gpxe/src/arch/i386/firmware/pcbios/hidemem.c @@ -15,6 +15,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <assert.h> #include <realmode.h> #include <biosint.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/memmap.c b/gpxe/src/arch/i386/firmware/pcbios/memmap.c index ff387d93..8a30dbae 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/memmap.c +++ b/gpxe/src/arch/i386/firmware/pcbios/memmap.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <errno.h> #include <realmode.h> diff --git a/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c b/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c index 420d2ae8..c572914f 100644 --- a/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c +++ b/gpxe/src/arch/i386/firmware/pcbios/pnpbios.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <errno.h> diff --git a/gpxe/src/arch/i386/hci/commands/pxe_cmd.c b/gpxe/src/arch/i386/hci/commands/pxe_cmd.c new file mode 100644 index 00000000..b5df2d1b --- /dev/null +++ b/gpxe/src/arch/i386/hci/commands/pxe_cmd.c @@ -0,0 +1,33 @@ +#include <gpxe/netdevice.h> +#include <gpxe/command.h> +#include <hci/ifmgmt_cmd.h> +#include <pxe_call.h> + +FILE_LICENCE ( GPL2_OR_LATER ); + +static int startpxe_payload ( struct net_device *netdev ) { + if ( netdev->state & NETDEV_OPEN ) + pxe_activate ( netdev ); + return 0; +} + +static int startpxe_exec ( int argc, char **argv ) { + return ifcommon_exec ( argc, argv, startpxe_payload, + "Activate PXE on" ); +} + +static int stoppxe_exec ( int argc __unused, char **argv __unused ) { + pxe_deactivate(); + return 0; +} + +struct command pxe_commands[] __command = { + { + .name = "startpxe", + .exec = startpxe_exec, + }, + { + .name = "stoppxe", + .exec = stoppxe_exec, + }, +}; diff --git a/gpxe/src/arch/i386/image/bootsector.c b/gpxe/src/arch/i386/image/bootsector.c index 0f297a26..f96cf201 100644 --- a/gpxe/src/arch/i386/image/bootsector.c +++ b/gpxe/src/arch/i386/image/bootsector.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/arch/i386/image/bzimage.c b/gpxe/src/arch/i386/image/bzimage.c index 47d46ca4..19450990 100644 --- a/gpxe/src/arch/i386/image/bzimage.c +++ b/gpxe/src/arch/i386/image/bzimage.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * @@ -42,9 +44,11 @@ FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 ); struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ); /** - * bzImage load context + * bzImage context */ -struct bzimage_load_context { +struct bzimage_context { + /** Boot protocol version */ + unsigned int version; /** Real-mode kernel portion load segment address */ unsigned int rm_kernel_seg; /** Real-mode kernel portion load address */ @@ -55,28 +59,14 @@ struct bzimage_load_context { size_t rm_heap; /** Command line (offset from rm_kernel) */ size_t rm_cmdline; + /** Command line maximum length */ + size_t cmdline_size; /** Real-mode kernel portion total memory size */ size_t rm_memsz; /** Non-real-mode kernel portion load address */ userptr_t pm_kernel; /** Non-real-mode kernel portion file and memory size */ size_t pm_sz; -}; - -/** - * bzImage execution context - */ -struct bzimage_exec_context { - /** Real-mode kernel portion load segment address */ - unsigned int rm_kernel_seg; - /** Real-mode kernel portion load address */ - userptr_t rm_kernel; - /** Real-mode heap top (offset from rm_kernel) */ - size_t rm_heap; - /** Command line (offset from rm_kernel) */ - size_t rm_cmdline; - /** Command line maximum length */ - size_t cmdline_size; /** Video mode */ unsigned int vid_mode; /** Memory limit */ @@ -85,18 +75,178 @@ struct bzimage_exec_context { physaddr_t ramdisk_image; /** Initrd size */ physaddr_t ramdisk_size; + + /** Command line magic block */ + struct bzimage_cmdline cmdline_magic; + /** bzImage header */ + struct bzimage_header bzhdr; }; /** + * Parse bzImage header + * + * @v image bzImage file + * @v bzimg bzImage context + * @v src bzImage to parse + * @ret rc Return status code + */ +static int bzimage_parse_header ( struct image *image, + struct bzimage_context *bzimg, + userptr_t src ) { + unsigned int syssize; + int is_bzimage; + + /* Sanity check */ + if ( image->len < ( BZI_HDR_OFFSET + sizeof ( bzimg->bzhdr ) ) ) { + DBGC ( image, "bzImage %p too short for kernel header\n", + image ); + return -ENOEXEC; + } + + /* Read in header structures */ + memset ( bzimg, 0, sizeof ( *bzimg ) ); + copy_from_user ( &bzimg->cmdline_magic, src, BZI_CMDLINE_OFFSET, + sizeof ( bzimg->cmdline_magic ) ); + copy_from_user ( &bzimg->bzhdr, src, BZI_HDR_OFFSET, + sizeof ( bzimg->bzhdr ) ); + + /* Calculate size of real-mode portion */ + bzimg->rm_filesz = + ( ( bzimg->bzhdr.setup_sects ? bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9; + if ( bzimg->rm_filesz > image->len ) { + DBGC ( image, "bzImage %p too short for %zd byte of setup\n", + image, bzimg->rm_filesz ); + return -ENOEXEC; + } + bzimg->rm_memsz = BZI_ASSUMED_RM_SIZE; + + /* Calculate size of protected-mode portion */ + bzimg->pm_sz = ( image->len - bzimg->rm_filesz ); + syssize = ( ( bzimg->pm_sz + 15 ) / 16 ); + + /* Check for signatures and determine version */ + if ( bzimg->bzhdr.boot_flag != BZI_BOOT_FLAG ) { + DBGC ( image, "bzImage %p missing 55AA signature\n", image ); + return -ENOEXEC; + } + if ( bzimg->bzhdr.header == BZI_SIGNATURE ) { + /* 2.00+ */ + bzimg->version = bzimg->bzhdr.version; + } else { + /* Pre-2.00. Check that the syssize field is correct, + * as a guard against accepting arbitrary binary data, + * since the 55AA check is pretty lax. Note that the + * syssize field is unreliable for protocols between + * 2.00 and 2.03 inclusive, so we should not always + * check this field. + */ + bzimg->version = 0x0100; + if ( bzimg->bzhdr.syssize != syssize ) { + DBGC ( image, "bzImage %p bad syssize %x (expected " + "%x)\n", image, bzimg->bzhdr.syssize, syssize ); + return -ENOEXEC; + } + } + + /* Determine image type */ + is_bzimage = ( ( bzimg->version >= 0x0200 ) ? + ( bzimg->bzhdr.loadflags & BZI_LOAD_HIGH ) : 0 ); + + /* Calculate load address of real-mode portion */ + bzimg->rm_kernel_seg = ( is_bzimage ? 0x1000 : 0x9000 ); + bzimg->rm_kernel = real_to_user ( bzimg->rm_kernel_seg, 0 ); + + /* Allow space for the stack and heap */ + bzimg->rm_memsz += BZI_STACK_SIZE; + bzimg->rm_heap = bzimg->rm_memsz; + + /* Allow space for the command line */ + bzimg->rm_cmdline = bzimg->rm_memsz; + bzimg->rm_memsz += BZI_CMDLINE_SIZE; + + /* Calculate load address of protected-mode portion */ + bzimg->pm_kernel = phys_to_user ( is_bzimage ? BZI_LOAD_HIGH_ADDR + : BZI_LOAD_LOW_ADDR ); + + /* Extract video mode */ + bzimg->vid_mode = bzimg->bzhdr.vid_mode; + + /* Extract memory limit */ + bzimg->mem_limit = ( ( bzimg->version >= 0x0203 ) ? + bzimg->bzhdr.initrd_addr_max : BZI_INITRD_MAX ); + + /* Extract command line size */ + bzimg->cmdline_size = ( ( bzimg->version >= 0x0206 ) ? + bzimg->bzhdr.cmdline_size : BZI_CMDLINE_SIZE ); + + DBGC ( image, "bzImage %p version %04x RM %#lx+%#zx PM %#lx+%#zx " + "cmdlen %zd\n", image, bzimg->version, + user_to_phys ( bzimg->rm_kernel, 0 ), bzimg->rm_filesz, + user_to_phys ( bzimg->pm_kernel, 0 ), bzimg->pm_sz, + bzimg->cmdline_size ); + + return 0; +} + +/** + * Update bzImage header in loaded kernel + * + * @v image bzImage file + * @v bzimg bzImage context + * @v dst bzImage to update + */ +static void bzimage_update_header ( struct image *image, + struct bzimage_context *bzimg, + userptr_t dst ) { + + /* Set loader type */ + if ( bzimg->version >= 0x0200 ) + bzimg->bzhdr.type_of_loader = BZI_LOADER_TYPE_GPXE; + + /* Set heap end pointer */ + if ( bzimg->version >= 0x0201 ) { + bzimg->bzhdr.heap_end_ptr = ( bzimg->rm_heap - 0x200 ); + bzimg->bzhdr.loadflags |= BZI_CAN_USE_HEAP; + } + + /* Set command line */ + if ( bzimg->version >= 0x0202 ) { + bzimg->bzhdr.cmd_line_ptr = user_to_phys ( bzimg->rm_kernel, + bzimg->rm_cmdline ); + } else { + bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC; + bzimg->cmdline_magic.offset = bzimg->rm_cmdline; + bzimg->bzhdr.setup_move_size = bzimg->rm_memsz; + } + + /* Set video mode */ + bzimg->bzhdr.vid_mode = bzimg->vid_mode; + + /* Set initrd address */ + if ( bzimg->version >= 0x0200 ) { + bzimg->bzhdr.ramdisk_image = bzimg->ramdisk_image; + bzimg->bzhdr.ramdisk_size = bzimg->ramdisk_size; + } + + /* Write out header structures */ + copy_to_user ( dst, BZI_CMDLINE_OFFSET, &bzimg->cmdline_magic, + sizeof ( bzimg->cmdline_magic ) ); + copy_to_user ( dst, BZI_HDR_OFFSET, &bzimg->bzhdr, + sizeof ( bzimg->bzhdr ) ); + + DBGC ( image, "bzImage %p vidmode %d\n", image, bzimg->vid_mode ); +} + +/** * Parse kernel command line for bootloader parameters * * @v image bzImage file - * @v exec_ctx Execution context + * @v bzimg bzImage context * @v cmdline Kernel command line * @ret rc Return status code */ static int bzimage_parse_cmdline ( struct image *image, - struct bzimage_exec_context *exec_ctx, + struct bzimage_context *bzimg, const char *cmdline ) { char *vga; char *mem; @@ -105,13 +255,13 @@ static int bzimage_parse_cmdline ( struct image *image, if ( ( vga = strstr ( cmdline, "vga=" ) ) ) { vga += 4; if ( strcmp ( vga, "normal" ) == 0 ) { - exec_ctx->vid_mode = BZI_VID_MODE_NORMAL; + bzimg->vid_mode = BZI_VID_MODE_NORMAL; } else if ( strcmp ( vga, "ext" ) == 0 ) { - exec_ctx->vid_mode = BZI_VID_MODE_EXT; + bzimg->vid_mode = BZI_VID_MODE_EXT; } else if ( strcmp ( vga, "ask" ) == 0 ) { - exec_ctx->vid_mode = BZI_VID_MODE_ASK; + bzimg->vid_mode = BZI_VID_MODE_ASK; } else { - exec_ctx->vid_mode = strtoul ( vga, &vga, 0 ); + bzimg->vid_mode = strtoul ( vga, &vga, 0 ); if ( *vga && ( *vga != ' ' ) ) { DBGC ( image, "bzImage %p strange \"vga=\"" "terminator '%c'\n", image, *vga ); @@ -122,17 +272,17 @@ static int bzimage_parse_cmdline ( struct image *image, /* Look for "mem=" */ if ( ( mem = strstr ( cmdline, "mem=" ) ) ) { mem += 4; - exec_ctx->mem_limit = strtoul ( mem, &mem, 0 ); + bzimg->mem_limit = strtoul ( mem, &mem, 0 ); switch ( *mem ) { case 'G': case 'g': - exec_ctx->mem_limit <<= 10; + bzimg->mem_limit <<= 10; case 'M': case 'm': - exec_ctx->mem_limit <<= 10; + bzimg->mem_limit <<= 10; case 'K': case 'k': - exec_ctx->mem_limit <<= 10; + bzimg->mem_limit <<= 10; break; case '\0': case ' ': @@ -142,7 +292,7 @@ static int bzimage_parse_cmdline ( struct image *image, "terminator '%c'\n", image, *mem ); break; } - exec_ctx->mem_limit -= 1; + bzimg->mem_limit -= 1; } return 0; @@ -152,20 +302,20 @@ static int bzimage_parse_cmdline ( struct image *image, * Set command line * * @v image bzImage image - * @v exec_ctx Execution context + * @v bzimg bzImage context * @v cmdline Kernel command line * @ret rc Return status code */ static int bzimage_set_cmdline ( struct image *image, - struct bzimage_exec_context *exec_ctx, + struct bzimage_context *bzimg, const char *cmdline ) { size_t cmdline_len; /* Copy command line down to real-mode portion */ cmdline_len = ( strlen ( cmdline ) + 1 ); - if ( cmdline_len > exec_ctx->cmdline_size ) - cmdline_len = exec_ctx->cmdline_size; - copy_to_user ( exec_ctx->rm_kernel, exec_ctx->rm_cmdline, + if ( cmdline_len > bzimg->cmdline_size ) + cmdline_len = bzimg->cmdline_size; + copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline, cmdline, cmdline_len ); DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline ); @@ -217,14 +367,16 @@ static size_t bzimage_load_initrd ( struct image *image, } /* Copy in initrd image body */ + if ( address ) + memcpy_user ( address, offset, initrd->data, 0, initrd->len ); + offset += initrd->len; if ( address ) { DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n", - image, initrd, address, ( address + offset ) ); - memcpy_user ( address, offset, initrd->data, 0, - initrd->len ); + image, initrd, user_to_phys ( address, 0 ), + user_to_phys ( address, offset ) ); } - offset += initrd->len; + /* Round up to 4-byte boundary */ offset = ( ( offset + 0x03 ) & ~0x03 ); return offset; } @@ -233,20 +385,19 @@ static size_t bzimage_load_initrd ( struct image *image, * Load initrds, if any * * @v image bzImage image - * @v exec_ctx Execution context + * @v bzimg bzImage context * @ret rc Return status code */ static int bzimage_load_initrds ( struct image *image, - struct bzimage_exec_context *exec_ctx ) { + struct bzimage_context *bzimg ) { struct image *initrd; size_t total_len = 0; physaddr_t address; int rc; /* Add up length of all initrd images */ - for_each_image ( initrd ) { + for_each_image ( initrd ) total_len += bzimage_load_initrd ( image, initrd, UNULL ); - } /* Give up if no initrd images found */ if ( ! total_len ) @@ -268,7 +419,7 @@ static int bzimage_load_initrds ( struct image *image, return -ENOBUFS; } /* Check that we are within the kernel's range */ - if ( ( address + total_len - 1 ) > exec_ctx->mem_limit ) + if ( ( address + total_len - 1 ) > bzimg->mem_limit ) continue; /* Prepare and verify segment */ if ( ( rc = prep_segment ( phys_to_user ( address ), 0, @@ -279,8 +430,8 @@ static int bzimage_load_initrds ( struct image *image, } /* Record initrd location */ - exec_ctx->ramdisk_image = address; - exec_ctx->ramdisk_size = total_len; + bzimg->ramdisk_image = address; + bzimg->ramdisk_size = total_len; /* Construct initrd */ DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n", @@ -300,60 +451,37 @@ static int bzimage_load_initrds ( struct image *image, * @ret rc Return status code */ static int bzimage_exec ( struct image *image ) { - struct bzimage_exec_context exec_ctx; - struct bzimage_header bzhdr; + struct bzimage_context bzimg; const char *cmdline = ( image->cmdline ? image->cmdline : "" ); int rc; - /* Initialise context */ - memset ( &exec_ctx, 0, sizeof ( exec_ctx ) ); - - /* Retrieve kernel header */ - exec_ctx.rm_kernel_seg = image->priv.ul; - exec_ctx.rm_kernel = real_to_user ( exec_ctx.rm_kernel_seg, 0 ); - copy_from_user ( &bzhdr, exec_ctx.rm_kernel, BZI_HDR_OFFSET, - sizeof ( bzhdr ) ); - exec_ctx.rm_cmdline = exec_ctx.rm_heap = - ( bzhdr.heap_end_ptr + 0x200 ); - exec_ctx.vid_mode = bzhdr.vid_mode; - if ( bzhdr.version >= 0x0203 ) { - exec_ctx.mem_limit = bzhdr.initrd_addr_max; - } else { - exec_ctx.mem_limit = BZI_INITRD_MAX; - } - if ( bzhdr.version >= 0x0206 ) { - exec_ctx.cmdline_size = bzhdr.cmdline_size; - } else { - exec_ctx.cmdline_size = BZI_CMDLINE_SIZE; - } - DBG ( "cmdline_size = %zd\n", exec_ctx.cmdline_size ); + /* Read and parse header from loaded kernel */ + if ( ( rc = bzimage_parse_header ( image, &bzimg, + image->priv.user ) ) != 0 ) + return rc; + assert ( bzimg.rm_kernel == image->priv.user ); /* Parse command line for bootloader parameters */ - if ( ( rc = bzimage_parse_cmdline ( image, &exec_ctx, cmdline ) ) != 0) + if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0) return rc; /* Store command line */ - if ( ( rc = bzimage_set_cmdline ( image, &exec_ctx, cmdline ) ) != 0 ) + if ( ( rc = bzimage_set_cmdline ( image, &bzimg, cmdline ) ) != 0 ) return rc; /* Load any initrds */ - if ( ( rc = bzimage_load_initrds ( image, &exec_ctx ) ) != 0 ) + if ( ( rc = bzimage_load_initrds ( image, &bzimg ) ) != 0 ) return rc; - /* Update and store kernel header */ - bzhdr.vid_mode = exec_ctx.vid_mode; - bzhdr.ramdisk_image = exec_ctx.ramdisk_image; - bzhdr.ramdisk_size = exec_ctx.ramdisk_size; - copy_to_user ( exec_ctx.rm_kernel, BZI_HDR_OFFSET, &bzhdr, - sizeof ( bzhdr ) ); + /* Update kernel header */ + bzimage_update_header ( image, &bzimg, bzimg.rm_kernel ); /* Prepare for exiting */ shutdown ( SHUTDOWN_BOOT ); DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 " - "(stack %04x:%04zx)\n", image, - ( exec_ctx.rm_kernel_seg + 0x20 ), - exec_ctx.rm_kernel_seg, exec_ctx.rm_heap ); + "(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ), + bzimg.rm_kernel_seg, bzimg.rm_heap ); /* Jump to the kernel */ __asm__ __volatile__ ( REAL_CODE ( "movw %w0, %%ds\n\t" @@ -365,9 +493,9 @@ static int bzimage_exec ( struct image *image ) { "pushw %w2\n\t" "pushw $0\n\t" "lret\n\t" ) - : : "r" ( exec_ctx.rm_kernel_seg ), - "r" ( exec_ctx.rm_heap ), - "r" ( exec_ctx.rm_kernel_seg + 0x20 ) ); + : : "r" ( bzimg.rm_kernel_seg ), + "r" ( bzimg.rm_heap ), + "r" ( bzimg.rm_kernel_seg + 0x20 ) ); /* There is no way for the image to return, since we provide * no return address. @@ -378,192 +506,49 @@ static int bzimage_exec ( struct image *image ) { } /** - * Load and parse bzImage header - * - * @v image bzImage file - * @v load_ctx Load context - * @v bzhdr Buffer for bzImage header - * @ret rc Return status code - */ -static int bzimage_load_header ( struct image *image, - struct bzimage_load_context *load_ctx, - struct bzimage_header *bzhdr ) { - - /* Sanity check */ - if ( image->len < ( BZI_HDR_OFFSET + sizeof ( *bzhdr ) ) ) { - DBGC ( image, "bzImage %p too short for kernel header\n", - image ); - return -ENOEXEC; - } - - /* Read and verify header */ - copy_from_user ( bzhdr, image->data, BZI_HDR_OFFSET, - sizeof ( *bzhdr ) ); - if ( bzhdr->header != BZI_SIGNATURE ) { - DBGC ( image, "bzImage %p bad signature %08x\n", - image, bzhdr->header ); - return -ENOEXEC; - } - - /* We don't support ancient kernels */ - if ( bzhdr->version < 0x0200 ) { - DBGC ( image, "bzImage %p version %04x not supported\n", - image, bzhdr->version ); - return -ENOTSUP; - } - - /* Calculate load address and size of real-mode portion */ - load_ctx->rm_kernel_seg = ( ( bzhdr->loadflags & BZI_LOAD_HIGH ) ? - 0x1000 : /* 1000:0000 (bzImage) */ - 0x9000 ); /* 9000:0000 (zImage) */ - load_ctx->rm_kernel = real_to_user ( load_ctx->rm_kernel_seg, 0 ); - load_ctx->rm_filesz = - ( ( bzhdr->setup_sects ? bzhdr->setup_sects : 4 ) + 1 ) << 9; - load_ctx->rm_memsz = BZI_ASSUMED_RM_SIZE; - if ( load_ctx->rm_filesz > image->len ) { - DBGC ( image, "bzImage %p too short for %zd byte of setup\n", - image, load_ctx->rm_filesz ); - return -ENOEXEC; - } - - /* Calculate load address and size of non-real-mode portion */ - load_ctx->pm_kernel = ( ( bzhdr->loadflags & BZI_LOAD_HIGH ) ? - phys_to_user ( BZI_LOAD_HIGH_ADDR ) : - phys_to_user ( BZI_LOAD_LOW_ADDR ) ); - load_ctx->pm_sz = ( image->len - load_ctx->rm_filesz ); - - DBGC ( image, "bzImage %p version %04x RM %#zx bytes PM %#zx bytes\n", - image, bzhdr->version, load_ctx->rm_filesz, load_ctx->pm_sz ); - return 0; -} - -/** - * Load real-mode portion of bzImage + * Load bzImage image into memory * * @v image bzImage file - * @v load_ctx Load context * @ret rc Return status code */ -static int bzimage_load_real ( struct image *image, - struct bzimage_load_context *load_ctx ) { +int bzimage_load ( struct image *image ) { + struct bzimage_context bzimg; int rc; - /* Allow space for the stack and heap */ - load_ctx->rm_memsz += BZI_STACK_SIZE; - load_ctx->rm_heap = load_ctx->rm_memsz; + /* Read and parse header from image */ + if ( ( rc = bzimage_parse_header ( image, &bzimg, + image->data ) ) != 0 ) + return rc; - /* Allow space for the command line */ - load_ctx->rm_cmdline = load_ctx->rm_memsz; - load_ctx->rm_memsz += BZI_CMDLINE_SIZE; + /* This is a bzImage image, valid or otherwise */ + if ( ! image->type ) + image->type = &bzimage_image_type; - /* Prepare, verify, and load the real-mode segment */ - if ( ( rc = prep_segment ( load_ctx->rm_kernel, load_ctx->rm_filesz, - load_ctx->rm_memsz ) ) != 0 ) { + /* Prepare segments */ + if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz, + bzimg.rm_memsz ) ) != 0 ) { DBGC ( image, "bzImage %p could not prepare RM segment: %s\n", image, strerror ( rc ) ); return rc; } - memcpy_user ( load_ctx->rm_kernel, 0, image->data, 0, - load_ctx->rm_filesz ); - - return 0; -} - -/** - * Load non-real-mode portion of bzImage - * - * @v image bzImage file - * @v load_ctx Load context - * @ret rc Return status code - */ -static int bzimage_load_non_real ( struct image *image, - struct bzimage_load_context *load_ctx ) { - int rc; - - /* Prepare, verify and load the non-real-mode segment */ - if ( ( rc = prep_segment ( load_ctx->pm_kernel, load_ctx->pm_sz, - load_ctx->pm_sz ) ) != 0 ) { + if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz, + bzimg.pm_sz ) ) != 0 ) { DBGC ( image, "bzImage %p could not prepare PM segment: %s\n", image, strerror ( rc ) ); return rc; } - memcpy_user ( load_ctx->pm_kernel, 0, image->data, load_ctx->rm_filesz, - load_ctx->pm_sz ); - - return 0; -} - -/** - * Update and store bzImage header - * - * @v image bzImage file - * @v load_ctx Load context - * @v bzhdr Original bzImage header - * @ret rc Return status code - */ -static int bzimage_write_header ( struct image *image __unused, - struct bzimage_load_context *load_ctx, - struct bzimage_header *bzhdr ) { - struct bzimage_cmdline cmdline; - - /* Update the header and copy it into the loaded kernel */ - bzhdr->type_of_loader = BZI_LOADER_TYPE_GPXE; - if ( bzhdr->version >= 0x0201 ) { - bzhdr->heap_end_ptr = ( load_ctx->rm_heap - 0x200 ); - bzhdr->loadflags |= BZI_CAN_USE_HEAP; - } - if ( bzhdr->version >= 0x0202 ) { - bzhdr->cmd_line_ptr = user_to_phys ( load_ctx->rm_kernel, - load_ctx->rm_cmdline ); - } else { - cmdline.magic = BZI_CMDLINE_MAGIC; - cmdline.offset = load_ctx->rm_cmdline; - copy_to_user ( load_ctx->rm_kernel, BZI_CMDLINE_OFFSET, - &cmdline, sizeof ( cmdline ) ); - bzhdr->setup_move_size = load_ctx->rm_memsz; - } - copy_to_user ( load_ctx->rm_kernel, BZI_HDR_OFFSET, - bzhdr, sizeof ( *bzhdr ) ); - - return 0; -} - -/** - * Load bzImage image into memory - * - * @v image bzImage file - * @ret rc Return status code - */ -int bzimage_load ( struct image *image ) { - struct bzimage_load_context load_ctx; - struct bzimage_header bzhdr; - int rc; - - /* Initialise context */ - memset ( &load_ctx, 0, sizeof ( load_ctx ) ); - /* Load and verify header */ - if ( ( rc = bzimage_load_header ( image, &load_ctx, &bzhdr ) ) != 0 ) - return rc; - - /* This is a bzImage image, valid or otherwise */ - if ( ! image->type ) - image->type = &bzimage_image_type; - - /* Load real-mode portion */ - if ( ( rc = bzimage_load_real ( image, &load_ctx ) ) != 0 ) - return rc; - - /* Load non-real-mode portion */ - if ( ( rc = bzimage_load_non_real ( image, &load_ctx ) ) != 0 ) - return rc; + /* Load segments */ + memcpy_user ( bzimg.rm_kernel, 0, image->data, + 0, bzimg.rm_filesz ); + memcpy_user ( bzimg.pm_kernel, 0, image->data, + bzimg.rm_filesz, bzimg.pm_sz ); /* Update and write out header */ - if ( ( rc = bzimage_write_header ( image, &load_ctx, &bzhdr ) ) != 0 ) - return rc; + bzimage_update_header ( image, &bzimg, bzimg.rm_kernel ); /* Record real-mode segment in image private data field */ - image->priv.ul = load_ctx.rm_kernel_seg; + image->priv.user = bzimg.rm_kernel; return 0; } diff --git a/gpxe/src/arch/i386/image/com32.c b/gpxe/src/arch/i386/image/com32.c index d1b9a59f..6ab347c1 100644 --- a/gpxe/src/arch/i386/image/com32.c +++ b/gpxe/src/arch/i386/image/com32.c @@ -23,6 +23,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> diff --git a/gpxe/src/arch/i386/image/comboot.c b/gpxe/src/arch/i386/image/comboot.c index 40e32185..a00b2b95 100644 --- a/gpxe/src/arch/i386/image/comboot.c +++ b/gpxe/src/arch/i386/image/comboot.c @@ -23,6 +23,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> diff --git a/gpxe/src/arch/i386/image/elfboot.c b/gpxe/src/arch/i386/image/elfboot.c index c8daf72b..a41040e8 100644 --- a/gpxe/src/arch/i386/image/elfboot.c +++ b/gpxe/src/arch/i386/image/elfboot.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <errno.h> #include <elf.h> #include <gpxe/image.h> diff --git a/gpxe/src/arch/i386/image/eltorito.c b/gpxe/src/arch/i386/image/eltorito.c index 9d573106..53eb2c02 100644 --- a/gpxe/src/arch/i386/image/eltorito.c +++ b/gpxe/src/arch/i386/image/eltorito.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/arch/i386/image/multiboot.c b/gpxe/src/arch/i386/image/multiboot.c index 52bb10f6..5b620956 100644 --- a/gpxe/src/arch/i386/image/multiboot.c +++ b/gpxe/src/arch/i386/image/multiboot.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * @@ -139,10 +141,11 @@ static void multiboot_build_memmap ( struct image *image, /** * Add command line in base memory * + * @v imgname Image name * @v cmdline Command line * @ret physaddr Physical address of command line */ -physaddr_t multiboot_add_cmdline ( const char *cmdline ) { +physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) { char *mb_cmdline; if ( ! cmdline ) @@ -153,7 +156,7 @@ physaddr_t multiboot_add_cmdline ( const char *cmdline ) { mb_cmdline_offset += ( snprintf ( mb_cmdline, ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ), - "%s", cmdline ) + 1 ); + "%s %s", imgname, cmdline ) + 1 ); /* Truncate to terminating NUL in buffer if necessary */ if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) ) @@ -208,8 +211,8 @@ multiboot_build_module_list ( struct image *image, ( ( count - insert ) * sizeof ( *module ) ) ); module->mod_start = start; module->mod_end = end; - module->string = - multiboot_add_cmdline ( module_image->cmdline ); + module->string = multiboot_add_cmdline ( module_image->name, + module_image->cmdline ); module->reserved = 0; /* We promise to page-align modules */ @@ -264,10 +267,8 @@ static int multiboot_exec ( struct image *image ) { memset ( &mbinfo, 0, sizeof ( mbinfo ) ); mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP | MBI_FLAG_CMDLINE | MBI_FLAG_MODS ); - multiboot_build_memmap ( image, &mbinfo, mbmemmap, - ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) ); mb_cmdline_offset = 0; - mbinfo.cmdline = multiboot_add_cmdline ( image->cmdline ); + mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline ); mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules, ( sizeof(mbmodules) / sizeof(mbmodules[0]) ) ); mbinfo.mods_addr = virt_to_phys ( mbmodules ); @@ -279,6 +280,12 @@ static int multiboot_exec ( struct image *image ) { */ shutdown ( SHUTDOWN_BOOT ); + /* Build memory map after unhiding bootloader memory regions as part of + * shutting everything down. + */ + multiboot_build_memmap ( image, &mbinfo, mbmemmap, + ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) ); + /* Jump to OS with flat physical addressing */ DBGC ( image, "MULTIBOOT %p starting execution at %lx\n", image, entry ); @@ -360,6 +367,13 @@ static int multiboot_load_raw ( struct image *image, userptr_t buffer; int rc; + /* Sanity check */ + if ( ! ( hdr->mb.flags & MB_FLAG_RAW ) ) { + DBGC ( image, "MULTIBOOT %p is not flagged as a raw image\n", + image ); + return -EINVAL; + } + /* Verify and prepare segment */ offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr ); filesz = ( hdr->mb.load_end_addr ? @@ -432,14 +446,14 @@ static int multiboot_load ( struct image *image ) { return -ENOTSUP; } - /* Load the actual image */ - if ( hdr.mb.flags & MB_FLAG_RAW ) { - if ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) - return rc; - } else { - if ( ( rc = multiboot_load_elf ( image ) ) != 0 ) - return rc; - } + /* There is technically a bit MB_FLAG_RAW to indicate whether + * this is an ELF or a raw image. In practice, grub will use + * the ELF header if present, and Solaris relies on this + * behaviour. + */ + if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) && + ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) ) + return rc; return 0; } diff --git a/gpxe/src/arch/i386/image/pxe_image.c b/gpxe/src/arch/i386/image/pxe_image.c index 90550d83..63429f87 100644 --- a/gpxe/src/arch/i386/image/pxe_image.c +++ b/gpxe/src/arch/i386/image/pxe_image.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * @@ -42,28 +44,24 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE ); * @ret rc Return status code */ static int pxe_exec ( struct image *image ) { + struct net_device *netdev; int rc; - /* Ensure that PXE stack is ready to use */ - pxe_init_structures(); - pxe_hook_int1a(); - /* Arbitrarily pick the most recently opened network device */ - pxe_set_netdev ( last_opened_netdev() ); - - /* Many things will break if pxe_netdev is NULL */ - if ( ! pxe_netdev ) { + if ( ( netdev = last_opened_netdev() ) == NULL ) { DBGC ( image, "IMAGE %p could not locate PXE net device\n", image ); return -ENODEV; } + /* Activate PXE */ + pxe_activate ( netdev ); + /* Start PXE NBP */ rc = pxe_start_nbp(); /* Deactivate PXE */ - pxe_set_netdev ( NULL ); - pxe_unhook_int1a(); + pxe_deactivate(); return rc; } diff --git a/gpxe/src/arch/i386/include/basemem.h b/gpxe/src/arch/i386/include/basemem.h index cd5668e0..c477c7fe 100644 --- a/gpxe/src/arch/i386/include/basemem.h +++ b/gpxe/src/arch/i386/include/basemem.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <realmode.h> #include <bios.h> diff --git a/gpxe/src/arch/i386/include/basemem_packet.h b/gpxe/src/arch/i386/include/basemem_packet.h index e4d4f49c..3cb47767 100644 --- a/gpxe/src/arch/i386/include/basemem_packet.h +++ b/gpxe/src/arch/i386/include/basemem_packet.h @@ -1,6 +1,8 @@ #ifndef BASEMEM_PACKET_H #define BASEMEM_PACKET_H +FILE_LICENCE ( GPL2_OR_LATER ); + #include <realmode.h> /** Maximum length of base memory packet buffer */ diff --git a/gpxe/src/arch/i386/include/bios.h b/gpxe/src/arch/i386/include/bios.h index 979a092c..70bb73da 100644 --- a/gpxe/src/arch/i386/include/bios.h +++ b/gpxe/src/arch/i386/include/bios.h @@ -1,6 +1,8 @@ #ifndef BIOS_H #define BIOS_H +FILE_LICENCE ( GPL2_OR_LATER ); + #define BDA_SEG 0x0040 #define BDA_FBMS 0x0013 #define BDA_NUM_DRIVES 0x0075 diff --git a/gpxe/src/arch/i386/include/biosint.h b/gpxe/src/arch/i386/include/biosint.h index d365cf01..ab466af3 100644 --- a/gpxe/src/arch/i386/include/biosint.h +++ b/gpxe/src/arch/i386/include/biosint.h @@ -6,6 +6,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <realmode.h> struct segoff; diff --git a/gpxe/src/arch/i386/include/bits/byteswap.h b/gpxe/src/arch/i386/include/bits/byteswap.h index 98418c29..ddbd40ed 100644 --- a/gpxe/src/arch/i386/include/bits/byteswap.h +++ b/gpxe/src/arch/i386/include/bits/byteswap.h @@ -1,6 +1,8 @@ #ifndef ETHERBOOT_BITS_BYTESWAP_H #define ETHERBOOT_BITS_BYTESWAP_H +FILE_LICENCE ( GPL2_OR_LATER ); + static inline __attribute__ ((always_inline, const)) uint16_t __bswap_variable_16(uint16_t x) { diff --git a/gpxe/src/arch/i386/include/bits/compiler.h b/gpxe/src/arch/i386/include/bits/compiler.h index 119a9a21..000db0c1 100644 --- a/gpxe/src/arch/i386/include/bits/compiler.h +++ b/gpxe/src/arch/i386/include/bits/compiler.h @@ -1,6 +1,8 @@ #ifndef _BITS_COMPILER_H #define _BITS_COMPILER_H +FILE_LICENCE ( GPL2_OR_LATER ); + #ifndef ASSEMBLY /** Declare a function with standard calling conventions */ diff --git a/gpxe/src/arch/i386/include/bits/endian.h b/gpxe/src/arch/i386/include/bits/endian.h index 413e702d..84188542 100644 --- a/gpxe/src/arch/i386/include/bits/endian.h +++ b/gpxe/src/arch/i386/include/bits/endian.h @@ -1,6 +1,8 @@ #ifndef ETHERBOOT_BITS_ENDIAN_H #define ETHERBOOT_BITS_ENDIAN_H +FILE_LICENCE ( GPL2_OR_LATER ); + #define __BYTE_ORDER __LITTLE_ENDIAN #endif /* ETHERBOOT_BITS_ENDIAN_H */ diff --git a/gpxe/src/arch/i386/include/bits/errfile.h b/gpxe/src/arch/i386/include/bits/errfile.h index 5ea8a318..32b8a085 100644 --- a/gpxe/src/arch/i386/include/bits/errfile.h +++ b/gpxe/src/arch/i386/include/bits/errfile.h @@ -1,6 +1,8 @@ #ifndef _BITS_ERRFILE_H #define _BITS_ERRFILE_H +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @addtogroup errfile Error file identifiers * @{ @@ -12,6 +14,7 @@ #define ERRFILE_bios_smbios ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) #define ERRFILE_biosint ( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 ) #define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 ) +#define ERRFILE_pxeparent ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/gpxe/src/arch/i386/include/bits/io.h b/gpxe/src/arch/i386/include/bits/io.h index dd0ee444..eded9778 100644 --- a/gpxe/src/arch/i386/include/bits/io.h +++ b/gpxe/src/arch/i386/include/bits/io.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/x86_io.h> #endif /* _BITS_IO_H */ diff --git a/gpxe/src/arch/i386/include/bits/nap.h b/gpxe/src/arch/i386/include/bits/nap.h index f8ba7a7c..1354f6bb 100644 --- a/gpxe/src/arch/i386/include/bits/nap.h +++ b/gpxe/src/arch/i386/include/bits/nap.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/bios_nap.h> #include <gpxe/efi/efix86_nap.h> diff --git a/gpxe/src/arch/i386/include/bits/smbios.h b/gpxe/src/arch/i386/include/bits/smbios.h index 647ea19e..a68413aa 100644 --- a/gpxe/src/arch/i386/include/bits/smbios.h +++ b/gpxe/src/arch/i386/include/bits/smbios.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/bios_smbios.h> #endif /* _BITS_SMBIOS_H */ diff --git a/gpxe/src/arch/i386/include/bits/stdint.h b/gpxe/src/arch/i386/include/bits/stdint.h index 6ccf0971..8edf1319 100644 --- a/gpxe/src/arch/i386/include/bits/stdint.h +++ b/gpxe/src/arch/i386/include/bits/stdint.h @@ -1,8 +1,10 @@ #ifndef _BITS_STDINT_H #define _BITS_STDINT_H -typedef unsigned int size_t; -typedef signed int ssize_t; +FILE_LICENCE ( GPL2_OR_LATER ); + +typedef __SIZE_TYPE__ size_t; +typedef signed long ssize_t; typedef signed long off_t; typedef unsigned char uint8_t; diff --git a/gpxe/src/arch/i386/include/bits/timer.h b/gpxe/src/arch/i386/include/bits/timer.h index 99666d84..32e6bd47 100644 --- a/gpxe/src/arch/i386/include/bits/timer.h +++ b/gpxe/src/arch/i386/include/bits/timer.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/bios_timer.h> #include <gpxe/rdtsc_timer.h> diff --git a/gpxe/src/arch/i386/include/bits/uaccess.h b/gpxe/src/arch/i386/include/bits/uaccess.h index 0ecc5028..2bb52e02 100644 --- a/gpxe/src/arch/i386/include/bits/uaccess.h +++ b/gpxe/src/arch/i386/include/bits/uaccess.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <librm.h> #endif /* _BITS_UACCESS_H */ diff --git a/gpxe/src/arch/i386/include/bits/umalloc.h b/gpxe/src/arch/i386/include/bits/umalloc.h index dcbd0a6b..17ba2cb2 100644 --- a/gpxe/src/arch/i386/include/bits/umalloc.h +++ b/gpxe/src/arch/i386/include/bits/umalloc.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/memtop_umalloc.h> #endif /* _BITS_UMALLOC_H */ diff --git a/gpxe/src/arch/i386/include/bootsector.h b/gpxe/src/arch/i386/include/bootsector.h index e9071052..8730fbfc 100644 --- a/gpxe/src/arch/i386/include/bootsector.h +++ b/gpxe/src/arch/i386/include/bootsector.h @@ -6,6 +6,8 @@ * x86 bootsector image format */ +FILE_LICENCE ( GPL2_OR_LATER ); + extern int call_bootsector ( unsigned int segment, unsigned int offset, unsigned int drive ); diff --git a/gpxe/src/arch/i386/include/bzimage.h b/gpxe/src/arch/i386/include/bzimage.h index aee058ae..42b31fe4 100644 --- a/gpxe/src/arch/i386/include/bzimage.h +++ b/gpxe/src/arch/i386/include/bzimage.h @@ -1,6 +1,8 @@ #ifndef _BZIMAGE_H #define _BZIMAGE_H +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> /** @@ -75,6 +77,9 @@ struct bzimage_header { /** Offset of bzImage header within kernel image */ #define BZI_HDR_OFFSET 0x1f1 +/** bzImage boot flag value */ +#define BZI_BOOT_FLAG 0xaa55 + /** bzImage magic signature value */ #define BZI_SIGNATURE 0x53726448 diff --git a/gpxe/src/arch/i386/include/callbacks_arch.h b/gpxe/src/arch/i386/include/callbacks_arch.h deleted file mode 100644 index f9cba488..00000000 --- a/gpxe/src/arch/i386/include/callbacks_arch.h +++ /dev/null @@ -1,243 +0,0 @@ -/* Callout/callback interface for Etherboot - * - * This file provides the mechanisms for making calls from Etherboot - * to external programs and vice-versa. - * - * Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004. - * - * $Id$ - */ - -#ifndef CALLBACKS_ARCH_H -#define CALLBACKS_ARCH_H - -/* Skip the definitions that won't make sense to the assembler */ -#ifndef ASSEMBLY - -/* Struct to hold general-purpose register values. PUSHAL and POPAL - * can work directly with this structure; do not change the order of - * registers. - */ -typedef struct { - union { - uint16_t di; - uint32_t edi; - }; - union { - uint16_t si; - uint32_t esi; - }; - union { - uint16_t bp; - uint32_t ebp; - }; - union { - uint16_t sp; - uint32_t esp; - }; - union { - struct { - uint8_t bl; - uint8_t bh; - } PACKED; - uint16_t bx; - uint32_t ebx; - }; - union { - struct { - uint8_t dl; - uint8_t dh; - } PACKED; - uint16_t dx; - uint32_t edx; - }; - union { - struct { - uint8_t cl; - uint8_t ch; - } PACKED; - uint16_t cx; - uint32_t ecx; - }; - union { - struct { - uint8_t al; - uint8_t ah; - } PACKED; - uint16_t ax; - uint32_t eax; - }; -} regs_t; - -/* Struct to hold segment register values. Don't change the order; - * many bits of assembly code rely on it. - */ -typedef struct { - uint16_t cs; - uint16_t ss; - uint16_t ds; - uint16_t es; - uint16_t fs; - uint16_t gs; -} PACKED seg_regs_t; - -/* Struct for a GDT descriptor */ -typedef struct { - uint16_t limit; - uint32_t address; - uint16_t padding; -} PACKED gdt_descriptor_t; - -/* Struct for a GDT entry. Use GDT_SEGMENT() to fill it in. - */ -typedef struct { - uint16_t limit_0_15; - uint16_t base_0_15; - uint8_t base_16_23; - uint8_t accessed__type__sflag__dpl__present; - uint8_t limit_16_19__avl__size__granularity; - uint8_t base_24_31; -} PACKED gdt_segment_t; - -#define GDT_SEGMENT(base,limit,type,sflag,dpl,avl,size,granularity) \ - ( (gdt_segment_t) { \ - ( (limit) & 0xffff ), \ - ( (base) & 0xffff ), \ - ( ( (base) >> 16 ) & 0xff ), \ - ( ( 1 << 0 ) | ( (type) << 1 ) | \ - ( (sflag) << 4 ) | ( (dpl) << 5 ) | ( 1 << 7 ) ), \ - ( ( (limit) >> 16 ) | \ - ( (avl) << 4 ) | ( (size) << 5 ) | ( (granularity) << 7 ) ),\ - ( (base) >> 24 ) \ - } ) -#define GDT_SEGMENT_BASE(gdt_segment) \ - ( (gdt_segment)->base_0_15 | \ - (gdt_segment)->base_16_23 << 16 | \ - (gdt_segment)->base_24_31 << 24 ) -#define GDT_SEGMENT_LIMIT(gdt_segment) \ - ( (gdt_segment)->limit_0_15 | \ - ( ( (gdt_segment)->limit_16_19__avl__size__granularity \ - & 0xf ) << 16 ) ) -#define GDT_SEGMENT_GRANULARITY(gdt_segment) \ - ( ( (gdt_segment)->limit_16_19__avl__size__granularity \ - & 0x80 ) >> 7 ) -#define GDT_SEGMENT_TYPE(gdt_segment) \ - ( ( (gdt_segment)->accessed__type__sflag__dpl__present & 0x0e ) >> 1 ) -#define GDT_SEGMENT_SIZE(gdt_segment) \ - ( ( (gdt_segment)->limit_16_19__avl__size__granularity \ - & 0x60 ) >> 5 ) - -#define GDT_TYPE_DATA (0x0) -#define GDT_TYPE_STACK (0x2) -#define GDT_TYPE_WRITEABLE (0x1) -#define GDT_TYPE_CODE (0x6) -#define GDT_TYPE_EXEC_ONLY_CODE (0x4) -#define GDT_TYPE_CONFORMING (0x1) -#define GDT_SFLAG_SYSTEM (0) -#define GDT_SFLAG_NORMAL (1) -#define GDT_AVL_NORMAL (0) -#define GDT_SIZE_16BIT (0x0) -#define GDT_SIZE_32BIT (0x2) -#define GDT_SIZE_64BIT (0x1) -#define GDT_SIZE_UNKNOWN (0x3) -#define GDT_GRANULARITY_SMALL (0) -#define GDT_GRANULARITY_LARGE (1) -#define GDT_SEGMENT_NORMAL(base,limit,type,size,granularity) \ - GDT_SEGMENT ( base, limit, type, \ - GDT_SFLAG_NORMAL, 0, GDT_AVL_NORMAL, \ - size, granularity ) - -/* Protected mode code segment */ -#define GDT_SEGMENT_PMCS(base) GDT_SEGMENT_NORMAL ( \ - base, 0xfffff, GDT_TYPE_CODE | GDT_TYPE_CONFORMING, \ - GDT_SIZE_32BIT, GDT_GRANULARITY_LARGE ) -#define GDT_SEGMENT_PMCS_PHYS GDT_SEGMENT_PMCS(0) -/* Protected mode data segment */ -#define GDT_SEGMENT_PMDS(base) GDT_SEGMENT_NORMAL ( \ - base, 0xfffff, GDT_TYPE_DATA | GDT_TYPE_WRITEABLE, \ - GDT_SIZE_32BIT, GDT_GRANULARITY_LARGE ) -#define GDT_SEGMENT_PMDS_PHYS GDT_SEGMENT_PMDS(0) -/* Real mode code segment */ -/* Not sure if there's any reason to use GDT_TYPE_EXEC_ONLY_CODE - * instead of just GDT_TYPE_CODE, but that's what our old GDT did and - * it worked, so I'm not changing it. - */ -#define GDT_SEGMENT_RMCS(base) GDT_SEGMENT_NORMAL ( \ - base, 0xffff, GDT_TYPE_EXEC_ONLY_CODE | GDT_TYPE_CONFORMING, \ - GDT_SIZE_16BIT, GDT_GRANULARITY_SMALL ) -/* Real mode data segment */ -#define GDT_SEGMENT_RMDS(base) GDT_SEGMENT_NORMAL ( \ - base, 0xffff, GDT_TYPE_DATA | GDT_TYPE_WRITEABLE, \ - GDT_SIZE_16BIT, GDT_GRANULARITY_SMALL ) -/* Long mode code segment */ -#define GDT_SEGMENT_LMCS(base) GDT_SEGMENT_NORMAL ( \ - base, 0xfffff, GDT_TYPE_CODE | GDT_TYPE_CONFORMING, \ - GDT_SIZE_64BIT, GDT_GRANULARITY_LARGE ) -#define GDT_SEGMENT_LMCS_PHYS GDT_SEGMENT_LMCS(0) -/* Long mode data segment */ -/* AFIACT, GDT_SIZE_64BIT applies only to code segments */ -#define GDT_SEGMENT_LMDS(base) GDT_SEGMENT_NORMAL ( \ - base, 0xfffff, GDT_TYPE_DATA | GDT_TYPE_WRITEABLE, \ - GDT_SIZE_32BIT, GDT_GRANULARITY_LARGE ) -#define GDT_SEGMENT_LMDS_PHYS GDT_SEGMENT_LMDS(0) - -/* Template for creating GDT structures (including segment register - * lists), suitable for passing as parameters to external_call(). - */ -#define GDT_STRUCT_t(num_segments) \ - struct { \ - gdt_descriptor_t descriptor; \ - gdt_segment_t segments[num_segments]; \ - } PACKED -/* And utility function for filling it in */ -#define GDT_ADJUST(structure) { \ - (structure)->descriptor.address = \ - virt_to_phys(&((structure)->descriptor.limit)); \ - (structure)->descriptor.limit = \ - sizeof((structure)->segments) + 8 - 1; \ - (structure)->descriptor.padding = 0; \ -} - -/* Data passed in to in_call() by assembly wrapper. - */ -typedef struct { - regs_t regs; - seg_regs_t seg_regs; - gdt_descriptor_t gdt_desc; - uint32_t flags; - struct { - uint32_t offset; - uint32_t segment; - } ret_addr; -} PACKED i386_pm_in_call_data_t; - -typedef struct { - seg_regs_t seg_regs; - union { - uint16_t pad; - uint16_t prefix_sp; - }; - uint16_t flags; - struct { - uint16_t offset; - uint16_t segment; - } ret_addr; - uint32_t orig_opcode; -} PACKED i386_rm_in_call_data_t; - -typedef struct { - i386_pm_in_call_data_t *pm; - i386_rm_in_call_data_t *rm; -} i386_in_call_data_t; -#define in_call_data_t i386_in_call_data_t - -/* Function prototypes - */ -extern int install_rm_callback_interface ( void *address, size_t available ); - -#endif /* ASSEMBLY */ - -#define RM_IN_CALL (0) -#define RM_IN_CALL_FAR (2) - -#endif /* CALLBACKS_ARCH_H */ diff --git a/gpxe/src/arch/i386/include/comboot.h b/gpxe/src/arch/i386/include/comboot.h index 56661a80..1232f0a7 100644 --- a/gpxe/src/arch/i386/include/comboot.h +++ b/gpxe/src/arch/i386/include/comboot.h @@ -7,6 +7,8 @@ * SYSLINUX COMBOOT */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <setjmp.h> #include <gpxe/in.h> diff --git a/gpxe/src/arch/i386/include/fakee820.h b/gpxe/src/arch/i386/include/fakee820.h index f1fe8aff..9d00fb67 100644 --- a/gpxe/src/arch/i386/include/fakee820.h +++ b/gpxe/src/arch/i386/include/fakee820.h @@ -1,6 +1,8 @@ #ifndef _FAKEE820_H #define _FAKEE820_H +FILE_LICENCE ( GPL2_OR_LATER ); + extern void fake_e820 ( void ); extern void unfake_e820 ( void ); diff --git a/gpxe/src/arch/i386/include/gpxe/abft.h b/gpxe/src/arch/i386/include/gpxe/abft.h index 1c651ef1..9065e61a 100644 --- a/gpxe/src/arch/i386/include/gpxe/abft.h +++ b/gpxe/src/arch/i386/include/gpxe/abft.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <gpxe/acpi.h> #include <gpxe/if_ether.h> diff --git a/gpxe/src/arch/i386/include/gpxe/bios_nap.h b/gpxe/src/arch/i386/include/gpxe/bios_nap.h index f1c721e9..c32429b9 100644 --- a/gpxe/src/arch/i386/include/gpxe/bios_nap.h +++ b/gpxe/src/arch/i386/include/gpxe/bios_nap.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef NAP_PCBIOS #define NAP_PREFIX_pcbios #else diff --git a/gpxe/src/arch/i386/include/gpxe/bios_smbios.h b/gpxe/src/arch/i386/include/gpxe/bios_smbios.h index 0a6f277a..83726b11 100644 --- a/gpxe/src/arch/i386/include/gpxe/bios_smbios.h +++ b/gpxe/src/arch/i386/include/gpxe/bios_smbios.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef SMBIOS_PCBIOS #define SMBIOS_PREFIX_pcbios #else diff --git a/gpxe/src/arch/i386/include/gpxe/bios_timer.h b/gpxe/src/arch/i386/include/gpxe/bios_timer.h index 7e3caa3c..ed9df522 100644 --- a/gpxe/src/arch/i386/include/gpxe/bios_timer.h +++ b/gpxe/src/arch/i386/include/gpxe/bios_timer.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef TIMER_PCBIOS #define TIMER_PREFIX_pcbios #else diff --git a/gpxe/src/arch/i386/include/gpxe/ibft.h b/gpxe/src/arch/i386/include/gpxe/ibft.h index 5eef547b..c41e2e40 100644 --- a/gpxe/src/arch/i386/include/gpxe/ibft.h +++ b/gpxe/src/arch/i386/include/gpxe/ibft.h @@ -28,6 +28,8 @@ * */ +FILE_LICENCE ( BSD2 ); + /** @file * * iSCSI boot firmware table diff --git a/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h index a3cd2c01..eaf7025b 100644 --- a/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h +++ b/gpxe/src/arch/i386/include/gpxe/memtop_umalloc.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef UMALLOC_MEMTOP #define UMALLOC_PREFIX_memtop #else diff --git a/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h index 0e03d707..67ba22f0 100644 --- a/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h +++ b/gpxe/src/arch/i386/include/gpxe/rdtsc_timer.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef TIMER_RDTSC #define TIMER_PREFIX_rdtsc #else diff --git a/gpxe/src/arch/i386/include/gpxe/sbft.h b/gpxe/src/arch/i386/include/gpxe/sbft.h new file mode 100644 index 00000000..30038436 --- /dev/null +++ b/gpxe/src/arch/i386/include/gpxe/sbft.h @@ -0,0 +1,125 @@ +#ifndef _GPXE_SBFT_H +#define _GPXE_SBFT_H + +/* + * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +FILE_LICENCE ( BSD2 ); + +/** @file + * + * SRP boot firmware table + * + * The working draft specification for the SRP boot firmware table can + * be found at + * + * http://etherboot.org/wiki/srp/sbft + * + */ + +#include <stdint.h> +#include <gpxe/acpi.h> +#include <gpxe/scsi.h> +#include <gpxe/srp.h> +#include <gpxe/ib_srp.h> + +/** SRP Boot Firmware Table signature */ +#define SBFT_SIG "sBFT" + +/** An offset from the start of the sBFT */ +typedef uint16_t sbft_off_t; + +/** + * SRP Boot Firmware Table + */ +struct sbft_table { + /** ACPI header */ + struct acpi_description_header acpi; + /** Offset to SCSI subtable */ + sbft_off_t scsi_offset; + /** Offset to SRP subtable */ + sbft_off_t srp_offset; + /** Offset to IB subtable, if present */ + sbft_off_t ib_offset; + /** Reserved */ + uint8_t reserved[6]; +} __attribute__ (( packed )); + +/** + * sBFT SCSI subtable + */ +struct sbft_scsi_subtable { + /** LUN */ + struct scsi_lun lun; +} __attribute__ (( packed )); + +/** + * sBFT SRP subtable + */ +struct sbft_srp_subtable { + /** Initiator and target ports */ + struct srp_port_ids port_ids; +} __attribute__ (( packed )); + +/** + * sBFT IB subtable + */ +struct sbft_ib_subtable { + /** Source GID */ + struct ib_gid sgid; + /** Destination GID */ + struct ib_gid dgid; + /** Service ID */ + struct ib_gid_half service_id; + /** Partition key */ + uint16_t pkey; + /** Reserved */ + uint8_t reserved[6]; +} __attribute__ (( packed )); + +/** + * An sBFT created by gPXE + */ +struct gpxe_sbft { + /** The table header */ + struct sbft_table table; + /** The SCSI subtable */ + struct sbft_scsi_subtable scsi; + /** The SRP subtable */ + struct sbft_srp_subtable srp; + /** The IB subtable */ + struct sbft_ib_subtable ib; +} __attribute__ (( packed, aligned ( 16 ) )); + +struct srp_device; + +extern int sbft_fill_data ( struct srp_device *srp ); + +#endif /* _GPXE_SBFT_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/timer2.h b/gpxe/src/arch/i386/include/gpxe/timer2.h index 59705fa2..8f119515 100644 --- a/gpxe/src/arch/i386/include/gpxe/timer2.h +++ b/gpxe/src/arch/i386/include/gpxe/timer2.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + extern void timer2_udelay ( unsigned long usecs ); #endif /* _GPXE_TIMER2_H */ diff --git a/gpxe/src/arch/i386/include/gpxe/x86_io.h b/gpxe/src/arch/i386/include/gpxe/x86_io.h index b1ae3bac..beb5b22a 100644 --- a/gpxe/src/arch/i386/include/gpxe/x86_io.h +++ b/gpxe/src/arch/i386/include/gpxe/x86_io.h @@ -15,6 +15,8 @@ * into a machine with such an old CPU anyway. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef IOAPI_X86 #define IOAPI_PREFIX_x86 #else diff --git a/gpxe/src/arch/i386/include/int13.h b/gpxe/src/arch/i386/include/int13.h index bf6d0318..e1884d94 100644 --- a/gpxe/src/arch/i386/include/int13.h +++ b/gpxe/src/arch/i386/include/int13.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <gpxe/list.h> #include <realmode.h> diff --git a/gpxe/src/arch/i386/include/librm.h b/gpxe/src/arch/i386/include/librm.h index 9eb2767a..f193f5e3 100755..100644 --- a/gpxe/src/arch/i386/include/librm.h +++ b/gpxe/src/arch/i386/include/librm.h @@ -1,6 +1,8 @@ #ifndef LIBRM_H #define LIBRM_H +FILE_LICENCE ( GPL2_OR_LATER ); + /* Segment selectors as used in our protected-mode GDTs. * * Don't change these unless you really know what you're doing. diff --git a/gpxe/src/arch/i386/include/limits.h b/gpxe/src/arch/i386/include/limits.h index f13db267..031b6c57 100644 --- a/gpxe/src/arch/i386/include/limits.h +++ b/gpxe/src/arch/i386/include/limits.h @@ -1,6 +1,8 @@ #ifndef LIMITS_H #define LIMITS_H 1 +FILE_LICENCE ( GPL2_OR_LATER ); + /* Number of bits in a `char' */ #define CHAR_BIT 8 diff --git a/gpxe/src/arch/i386/include/memsizes.h b/gpxe/src/arch/i386/include/memsizes.h index 6222fd66..7b217494 100644 --- a/gpxe/src/arch/i386/include/memsizes.h +++ b/gpxe/src/arch/i386/include/memsizes.h @@ -1,6 +1,8 @@ #ifndef _MEMSIZES_H #define _MEMSIZES_H +FILE_LICENCE ( GPL2_OR_LATER ); + #include <basemem.h> /** diff --git a/gpxe/src/arch/i386/include/multiboot.h b/gpxe/src/arch/i386/include/multiboot.h index 4ca7089b..44614c73 100644 --- a/gpxe/src/arch/i386/include/multiboot.h +++ b/gpxe/src/arch/i386/include/multiboot.h @@ -8,6 +8,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> /** The magic number for the Multiboot header */ diff --git a/gpxe/src/arch/i386/include/pic8259.h b/gpxe/src/arch/i386/include/pic8259.h index 0c501a9c..f8e20c4c 100644 --- a/gpxe/src/arch/i386/include/pic8259.h +++ b/gpxe/src/arch/i386/include/pic8259.h @@ -4,6 +4,8 @@ * Initially written by Michael Brown (mcb30). */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifndef PIC8259_H #define PIC8259_H diff --git a/gpxe/src/arch/i386/include/pnpbios.h b/gpxe/src/arch/i386/include/pnpbios.h index ab31c699..4c20e73e 100644 --- a/gpxe/src/arch/i386/include/pnpbios.h +++ b/gpxe/src/arch/i386/include/pnpbios.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + /* BIOS segment address */ #define BIOS_SEG 0xf000 diff --git a/gpxe/src/arch/i386/include/pxe.h b/gpxe/src/arch/i386/include/pxe.h index 6d332ac7..041ee7ba 100644 --- a/gpxe/src/arch/i386/include/pxe.h +++ b/gpxe/src/arch/i386/include/pxe.h @@ -1,6 +1,8 @@ #ifndef PXE_H #define PXE_H +FILE_LICENCE ( GPL2_OR_LATER ); + #include "pxe_types.h" #include "pxe_api.h" #include <gpxe/device.h> @@ -65,6 +67,7 @@ union u_PXENV_ANY { struct s_PXENV_GET_FILE_SIZE get_file_size; struct s_PXENV_FILE_EXEC file_exec; struct s_PXENV_FILE_API_CHECK file_api_check; + struct s_PXENV_FILE_EXIT_HOOK file_exit_hook; }; typedef union u_PXENV_ANY PXENV_ANY_t; diff --git a/gpxe/src/arch/i386/include/pxe_api.h b/gpxe/src/arch/i386/include/pxe_api.h index b3d4bca8..92f046f7 100644 --- a/gpxe/src/arch/i386/include/pxe_api.h +++ b/gpxe/src/arch/i386/include/pxe_api.h @@ -15,6 +15,31 @@ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As an alternative, at your option, you may use this file under the + * following terms, known as the "MIT license": + * + * Copyright (c) 2005-2009 Michael Brown <mbrown@fensystems.co.uk> + * + * 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. */ /** @file @@ -23,6 +48,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include "pxe_types.h" /** @addtogroup pxe Preboot eXecution Environment (PXE) API @@ -1415,6 +1442,25 @@ extern PXENV_EXIT_t pxenv_undi_get_nic_type ( /** PXE API function code for pxenv_undi_get_iface_info() */ #define PXENV_UNDI_GET_IFACE_INFO 0x0013 +/** Broadcast supported */ +#define SUPPORTED_BROADCAST 0x0001 +/** Multicast supported */ +#define SUPPORTED_MULTICAST 0x0002 +/** Functional/group addressing supported */ +#define SUPPORTED_GROUP 0x0004 +/** Promiscuous mode supported */ +#define SUPPORTED_PROMISCUOUS 0x0008 +/** Software settable station address */ +#define SUPPORTED_SET_STATION_ADDRESS 0x0010 +/** InitiateDiagnostics supported */ +#define SUPPORTED_DIAGNOSTICS 0x0040 +/** Reset MAC supported */ +#define SUPPORTED_RESET 0x0400 +/** Open / Close Adapter supported */ +#define SUPPORTED_OPEN_CLOSE 0x0800 +/** Interrupt Request supported */ +#define SUPPORTED_IRQ 0x1000 + /** Parameter block for pxenv_undi_get_iface_info() */ struct s_PXENV_UNDI_GET_IFACE_INFO { PXENV_STATUS_t Status; /**< PXE status code */ @@ -1732,6 +1778,28 @@ extern PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_a /** @} */ /* pxenv_file_api_check */ +/** @defgroup pxenv_file_exit_hook PXENV_FILE_EXIT_HOOK + * + * FILE EXIT HOOK + * + * @{ + */ + +/** PXE API function code for pxenv_file_exit_hook() */ +#define PXENV_FILE_EXIT_HOOK 0x00e7 + +/** Parameter block for pxenv_file_exit_hook() */ +struct s_PXENV_FILE_EXIT_HOOK { + PXENV_STATUS_t Status; /**< PXE status code */ + SEGOFF16_t Hook; /**< SEG16:OFF16 to jump to */ +} PACKED; + +typedef struct s_PXENV_FILE_EXIT_HOOK PXENV_FILE_EXIT_HOOK_t; + +extern PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook ); + +/** @} */ /* pxenv_file_exit_hook */ + /** @} */ /* pxe_file_api */ /** @defgroup pxe_loader_api PXE Loader API diff --git a/gpxe/src/arch/i386/include/pxe_call.h b/gpxe/src/arch/i386/include/pxe_call.h index 2f3ea15a..4d245616 100644 --- a/gpxe/src/arch/i386/include/pxe_call.h +++ b/gpxe/src/arch/i386/include/pxe_call.h @@ -6,9 +6,13 @@ * PXE API entry point */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <pxe_api.h> #include <realmode.h> +struct net_device; + /** PXE load address segment */ #define PXE_LOAD_SEGMENT 0 @@ -26,10 +30,28 @@ extern struct s_PXE __text16 ( ppxe ); extern struct s_PXENV __text16 ( pxenv ); #define pxenv __use_text16 ( pxenv ) -extern void pxe_hook_int1a ( void ); -extern int pxe_unhook_int1a ( void ); -extern void pxe_init_structures ( void ); +extern void pxe_activate ( struct net_device *netdev ); +extern int pxe_deactivate ( void ); extern int pxe_start_nbp ( void ); extern __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ); +extern int _pxe_api_call_weak ( struct i386_all_regs *ix86 ) + __attribute__ (( weak )); + +/** + * Dispatch PXE API call weakly + * + * @v ix86 Registers for PXE call + * @ret present Zero if the PXE stack is present, nonzero if not + * + * A successful return only indicates that the PXE stack was available + * for dispatching the call; it says nothing about the success of + * whatever the call asked for. + */ +static inline int pxe_api_call_weak ( struct i386_all_regs *ix86 ) +{ + if ( _pxe_api_call_weak != NULL ) + return _pxe_api_call_weak ( ix86 ); + return -1; +} #endif /* _PXE_CALL_H */ diff --git a/gpxe/src/arch/i386/include/pxe_types.h b/gpxe/src/arch/i386/include/pxe_types.h index dd9092ef..a6516d25 100644 --- a/gpxe/src/arch/i386/include/pxe_types.h +++ b/gpxe/src/arch/i386/include/pxe_types.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <errno.h> /* PXE status codes */ diff --git a/gpxe/src/arch/i386/include/pxeparent.h b/gpxe/src/arch/i386/include/pxeparent.h new file mode 100644 index 00000000..b31e24a7 --- /dev/null +++ b/gpxe/src/arch/i386/include/pxeparent.h @@ -0,0 +1,11 @@ +#ifndef PXEPARENT_H +#define PXEPARENT_H + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <pxe_types.h> + +extern int pxeparent_call ( SEGOFF16_t entry, unsigned int function, + void *params, size_t params_len ); + +#endif diff --git a/gpxe/src/arch/i386/include/realmode.h b/gpxe/src/arch/i386/include/realmode.h index 26e6dd77..a0a830b9 100644 --- a/gpxe/src/arch/i386/include/realmode.h +++ b/gpxe/src/arch/i386/include/realmode.h @@ -10,6 +10,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + /* * Declaration of variables in .data16 * diff --git a/gpxe/src/arch/i386/include/registers.h b/gpxe/src/arch/i386/include/registers.h index e68fa85a..2839e2bd 100644 --- a/gpxe/src/arch/i386/include/registers.h +++ b/gpxe/src/arch/i386/include/registers.h @@ -10,6 +10,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> /** diff --git a/gpxe/src/arch/i386/include/setjmp.h b/gpxe/src/arch/i386/include/setjmp.h index c18d03e1..5d3c11b6 100644 --- a/gpxe/src/arch/i386/include/setjmp.h +++ b/gpxe/src/arch/i386/include/setjmp.h @@ -1,6 +1,8 @@ #ifndef ETHERBOOT_SETJMP_H #define ETHERBOOT_SETJMP_H +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <realmode.h> diff --git a/gpxe/src/arch/i386/include/undi.h b/gpxe/src/arch/i386/include/undi.h index c6253d0a..de6925b6 100644 --- a/gpxe/src/arch/i386/include/undi.h +++ b/gpxe/src/arch/i386/include/undi.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifndef ASSEMBLY #include <gpxe/device.h> diff --git a/gpxe/src/arch/i386/include/undiload.h b/gpxe/src/arch/i386/include/undiload.h index bfc11874..426830e8 100644 --- a/gpxe/src/arch/i386/include/undiload.h +++ b/gpxe/src/arch/i386/include/undiload.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + struct undi_device; struct undi_rom; diff --git a/gpxe/src/arch/i386/include/undinet.h b/gpxe/src/arch/i386/include/undinet.h index 1a4a385e..c3c17c11 100644 --- a/gpxe/src/arch/i386/include/undinet.h +++ b/gpxe/src/arch/i386/include/undinet.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + struct undi_device; extern int undinet_probe ( struct undi_device *undi ); diff --git a/gpxe/src/arch/i386/include/undipreload.h b/gpxe/src/arch/i386/include/undipreload.h index d9bc8cb9..de9b8fb5 100644 --- a/gpxe/src/arch/i386/include/undipreload.h +++ b/gpxe/src/arch/i386/include/undipreload.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <realmode.h> #include <undi.h> diff --git a/gpxe/src/arch/i386/include/undirom.h b/gpxe/src/arch/i386/include/undirom.h index a2636007..86d7077b 100644 --- a/gpxe/src/arch/i386/include/undirom.h +++ b/gpxe/src/arch/i386/include/undirom.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <pxe_types.h> /** An UNDI PCI device ID */ diff --git a/gpxe/src/arch/i386/interface/pcbios/abft.c b/gpxe/src/arch/i386/interface/pcbios/abft.c index af28bbcf..86941728 100644 --- a/gpxe/src/arch/i386/interface/pcbios/abft.c +++ b/gpxe/src/arch/i386/interface/pcbios/abft.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <realmode.h> #include <gpxe/aoe.h> #include <gpxe/netdevice.h> diff --git a/gpxe/src/arch/i386/interface/pcbios/aoeboot.c b/gpxe/src/arch/i386/interface/pcbios/aoeboot.c index 6e1e51cb..2670b15d 100644 --- a/gpxe/src/arch/i386/interface/pcbios/aoeboot.c +++ b/gpxe/src/arch/i386/interface/pcbios/aoeboot.c @@ -1,58 +1,74 @@ #include <stdint.h> #include <string.h> +#include <stdlib.h> #include <stdio.h> -#include <byteswap.h> +#include <errno.h> #include <gpxe/aoe.h> #include <gpxe/ata.h> #include <gpxe/netdevice.h> -#include <gpxe/settings.h> #include <gpxe/sanboot.h> #include <gpxe/abft.h> #include <int13.h> +FILE_LICENCE ( GPL2_OR_LATER ); + static int aoeboot ( const char *root_path ) { - struct ata_device ata; - struct int13_drive drive; + struct ata_device *ata; + struct int13_drive *drive; int rc; - memset ( &ata, 0, sizeof ( ata ) ); - memset ( &drive, 0, sizeof ( drive ) ); - - printf ( "AoE booting from %s\n", root_path ); + ata = zalloc ( sizeof ( *ata ) ); + if ( ! ata ) { + rc = -ENOMEM; + goto err_alloc_ata; + } + drive = zalloc ( sizeof ( *drive ) ); + if ( ! drive ) { + rc = -ENOMEM; + goto err_alloc_drive; + } /* FIXME: ugly, ugly hack */ struct net_device *netdev = last_opened_netdev(); - if ( ( rc = aoe_attach ( &ata, netdev, root_path ) ) != 0 ) { + if ( ( rc = aoe_attach ( ata, netdev, root_path ) ) != 0 ) { printf ( "Could not attach AoE device: %s\n", strerror ( rc ) ); - goto error_attach; + goto err_attach; } - if ( ( rc = init_atadev ( &ata ) ) != 0 ) { + if ( ( rc = init_atadev ( ata ) ) != 0 ) { printf ( "Could not initialise AoE device: %s\n", strerror ( rc ) ); - goto error_init; + goto err_init; } /* FIXME: ugly, ugly hack */ struct aoe_session *aoe = - container_of ( ata.backend, struct aoe_session, refcnt ); + container_of ( ata->backend, struct aoe_session, refcnt ); abft_fill_data ( aoe ); - drive.blockdev = &ata.blockdev; + drive->blockdev = &ata->blockdev; - register_int13_drive ( &drive ); - printf ( "Registered as BIOS drive %#02x\n", drive.drive ); - printf ( "Booting from BIOS drive %#02x\n", drive.drive ); - rc = int13_boot ( drive.drive ); + register_int13_drive ( drive ); + printf ( "Registered as BIOS drive %#02x\n", drive->drive ); + printf ( "Booting from BIOS drive %#02x\n", drive->drive ); + rc = int13_boot ( drive->drive ); printf ( "Boot failed\n" ); - printf ( "Unregistering BIOS drive %#02x\n", drive.drive ); - unregister_int13_drive ( &drive ); + /* Leave drive registered, if instructed to do so */ + if ( keep_san() ) + return rc; + + printf ( "Unregistering BIOS drive %#02x\n", drive->drive ); + unregister_int13_drive ( drive ); - error_init: - aoe_detach ( &ata ); - error_attach: + err_init: + aoe_detach ( ata ); + err_attach: + free ( drive ); + err_alloc_drive: + free ( ata ); + err_alloc_ata: return rc; } diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_nap.c b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c index 2f4a0513..e38cac7a 100644 --- a/gpxe/src/arch/i386/interface/pcbios/bios_nap.c +++ b/gpxe/src/arch/i386/interface/pcbios/bios_nap.c @@ -1,6 +1,8 @@ #include <gpxe/nap.h> #include <realmode.h> +FILE_LICENCE ( GPL2_OR_LATER ); + /** * Save power by halting the CPU until the next interrupt * diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c b/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c index efaaef0d..094214bd 100644 --- a/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c +++ b/gpxe/src/arch/i386/interface/pcbios/bios_smbios.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <errno.h> diff --git a/gpxe/src/arch/i386/interface/pcbios/bios_timer.c b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c index 0b475ea3..8ecf7c12 100644 --- a/gpxe/src/arch/i386/interface/pcbios/bios_timer.c +++ b/gpxe/src/arch/i386/interface/pcbios/bios_timer.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** @file * * BIOS timer diff --git a/gpxe/src/arch/i386/interface/pcbios/biosint.c b/gpxe/src/arch/i386/interface/pcbios/biosint.c index 1306f918..a193defa 100644 --- a/gpxe/src/arch/i386/interface/pcbios/biosint.c +++ b/gpxe/src/arch/i386/interface/pcbios/biosint.c @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * Hook INT vector * diff --git a/gpxe/src/arch/i386/interface/pcbios/ib_srpboot.c b/gpxe/src/arch/i386/interface/pcbios/ib_srpboot.c new file mode 100644 index 00000000..b1cbc337 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/ib_srpboot.c @@ -0,0 +1,73 @@ +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <gpxe/sanboot.h> +#include <int13.h> +#include <gpxe/srp.h> +#include <gpxe/sbft.h> + +FILE_LICENCE ( GPL2_OR_LATER ); + +static int ib_srpboot ( const char *root_path ) { + struct scsi_device *scsi; + struct int13_drive *drive; + int rc; + + scsi = zalloc ( sizeof ( *scsi ) ); + if ( ! scsi ) { + rc = -ENOMEM; + goto err_alloc_scsi; + } + drive = zalloc ( sizeof ( *drive ) ); + if ( ! drive ) { + rc = -ENOMEM; + goto err_alloc_drive; + } + + if ( ( rc = srp_attach ( scsi, root_path ) ) != 0 ) { + printf ( "Could not attach IB_SRP device: %s\n", + strerror ( rc ) ); + goto err_attach; + } + if ( ( rc = init_scsidev ( scsi ) ) != 0 ) { + printf ( "Could not initialise IB_SRP device: %s\n", + strerror ( rc ) ); + goto err_init; + } + + drive->blockdev = &scsi->blockdev; + + /* FIXME: ugly, ugly hack */ + struct srp_device *srp = + container_of ( scsi->backend, struct srp_device, refcnt ); + sbft_fill_data ( srp ); + + register_int13_drive ( drive ); + printf ( "Registered as BIOS drive %#02x\n", drive->drive ); + printf ( "Booting from BIOS drive %#02x\n", drive->drive ); + rc = int13_boot ( drive->drive ); + printf ( "Boot failed\n" ); + + /* Leave drive registered, if instructed to do so */ + if ( keep_san() ) + return rc; + + printf ( "Unregistering BIOS drive %#02x\n", drive->drive ); + unregister_int13_drive ( drive ); + + err_init: + srp_detach ( scsi ); + err_attach: + free ( drive ); + err_alloc_drive: + free ( scsi ); + err_alloc_scsi: + return rc; +} + +struct sanboot_protocol ib_srp_sanboot_protocol __sanboot_protocol = { + .prefix = "ib_srp:", + .boot = ib_srpboot, +}; diff --git a/gpxe/src/arch/i386/interface/pcbios/ibft.c b/gpxe/src/arch/i386/interface/pcbios/ibft.c index 43d1f85f..adf8e6b9 100644 --- a/gpxe/src/arch/i386/interface/pcbios/ibft.c +++ b/gpxe/src/arch/i386/interface/pcbios/ibft.c @@ -25,6 +25,8 @@ * */ +FILE_LICENCE ( BSD2 ); + #include <stdint.h> #include <stdio.h> #include <string.h> @@ -35,6 +37,7 @@ #include <gpxe/acpi.h> #include <gpxe/in.h> #include <gpxe/netdevice.h> +#include <gpxe/ethernet.h> #include <gpxe/dhcp.h> #include <gpxe/iscsi.h> #include <gpxe/ibft.h> @@ -234,7 +237,8 @@ static int ibft_set_string_option ( struct ibft_string_block *strings, */ static const char * ibft_string ( struct ibft_string_block *strings, struct ibft_string *string ) { - return ( ( ( char * ) strings->table ) + string->offset ); + return ( string->offset ? + ( ( ( char * ) strings->table ) + string->offset ) : NULL ); } /** @@ -248,6 +252,7 @@ static const char * ibft_string ( struct ibft_string_block *strings, static int ibft_fill_nic ( struct ibft_nic *nic, struct ibft_string_block *strings, struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; struct in_addr netmask_addr = { 0 }; unsigned int netmask_count = 0; int rc; @@ -276,10 +281,12 @@ static int ibft_fill_nic ( struct ibft_nic *nic, DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix ); /* Extract values from net-device configuration */ - memcpy ( nic->mac_address, netdev->ll_addr, - sizeof ( nic->mac_address ) ); - DBG ( "iBFT NIC MAC = %s\n", - netdev->ll_protocol->ntoa ( nic->mac_address ) ); + if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, + nic->mac_address ) ) != 0 ) { + DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) ); + return rc; + } + DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) ); nic->pci_bus_dev_func = netdev->dev->desc.location; DBG ( "iBFT NIC PCI = %04x\n", nic->pci_bus_dev_func ); diff --git a/gpxe/src/arch/i386/interface/pcbios/int13.c b/gpxe/src/arch/i386/interface/pcbios/int13.c index 2e9de5cb..87b613a8 100644 --- a/gpxe/src/arch/i386/interface/pcbios/int13.c +++ b/gpxe/src/arch/i386/interface/pcbios/int13.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <limits.h> #include <byteswap.h> @@ -50,6 +52,48 @@ extern void int13_wrapper ( void ); static LIST_HEAD ( drives ); /** + * Number of BIOS drives + * + * Note that this is the number of drives in the system as a whole + * (i.e. a mirror of the counter at 40:75), rather than a count of the + * number of emulated drives. + */ +static uint8_t num_drives; + +/** + * Update BIOS drive count + */ +static void int13_set_num_drives ( void ) { + struct int13_drive *drive; + + /* Get current drive count */ + get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); + + /* Ensure count is large enough to cover all of our emulated drives */ + list_for_each_entry ( drive, &drives, list ) { + if ( num_drives <= ( drive->drive & 0x7f ) ) + num_drives = ( ( drive->drive & 0x7f ) + 1 ); + } + + /* Update current drive count */ + put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); +} + +/** + * Check number of drives + */ +static void int13_check_num_drives ( void ) { + uint8_t check_num_drives; + + get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES ); + if ( check_num_drives != num_drives ) { + int13_set_num_drives(); + DBG ( "INT13 fixing up number of drives from %d to %d\n", + check_num_drives, num_drives ); + } +} + +/** * INT 13, 00 - Reset disk system * * @v drive Emulated drive @@ -98,6 +142,7 @@ static int int13_rw_sectors ( struct int13_drive *drive, unsigned long lba; unsigned int count; userptr_t buffer; + int rc; /* Validate blocksize */ if ( blockdev->blksize != INT13_BLKSIZE ) { @@ -122,8 +167,10 @@ static int int13_rw_sectors ( struct int13_drive *drive, head, sector, lba, ix86->segs.es, ix86->regs.bx, count ); /* Read from / write to block device */ - if ( io ( blockdev, lba, count, buffer ) != 0 ) + if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { + DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); return -INT13_STATUS_READ_ERROR; + } return 0; } @@ -202,9 +249,13 @@ static int int13_get_parameters ( struct int13_drive *drive, */ static int int13_get_disk_type ( struct int13_drive *drive, struct i386_all_regs *ix86 ) { + uint32_t blocks; + DBG ( "Get disk type\n" ); - ix86->regs.cx = ( drive->cylinders >> 16 ); - ix86->regs.dx = ( drive->cylinders & 0xffff ); + blocks = ( ( drive->blockdev->blocks <= 0xffffffffUL ) ? + drive->blockdev->blocks : 0xffffffffUL ); + ix86->regs.cx = ( blocks >> 16 ); + ix86->regs.dx = ( blocks & 0xffff ); return INT13_DISK_TYPE_HDD; } @@ -248,6 +299,7 @@ static int int13_extended_rw ( struct int13_drive *drive, uint64_t lba; unsigned long count; userptr_t buffer; + int rc; /* Read parameters from disk address structure */ copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr )); @@ -259,8 +311,10 @@ static int int13_extended_rw ( struct int13_drive *drive, addr.buffer.segment, addr.buffer.offset, count ); /* Read from / write to block device */ - if ( io ( blockdev, lba, count, buffer ) != 0 ) + if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) { + DBG ( "INT 13 failed: %s\n", strerror ( rc ) ); return -INT13_STATUS_READ_ERROR; + } return 0; } @@ -328,6 +382,9 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) { struct int13_drive *drive; int status; + /* Check BIOS hasn't killed off our drive */ + int13_check_num_drives(); + list_for_each_entry ( drive, &drives, list ) { if ( bios_drive != drive->drive ) { @@ -387,7 +444,7 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) { /* Negative status indicates an error */ if ( status < 0 ) { status = -status; - DBG ( "INT13 failed with status %x\n", status ); + DBG ( "INT 13 returning failure status %x\n", status ); } else { ix86->flags &= ~CF; } @@ -543,7 +600,6 @@ void register_int13_drive ( struct int13_drive *drive ) { /* Assign natural drive number */ get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); drive->natural_drive = ( num_drives | 0x80 ); - num_drives++; /* Assign drive number */ if ( ( drive->drive & 0xff ) == 0xff ) { @@ -552,13 +608,8 @@ void register_int13_drive ( struct int13_drive *drive ) { } else { /* Use specified drive number (+0x80 if necessary) */ drive->drive |= 0x80; - if ( num_drives <= ( drive->drive & 0x7f ) ) - num_drives = ( ( drive->drive & 0x7f ) + 1 ); } - /* Update BIOS drive count */ - put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); - DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S " "geometry %d/%d/%d\n", drive->drive, drive->natural_drive, drive->cylinders, drive->heads, drive->sectors_per_track ); @@ -569,6 +620,9 @@ void register_int13_drive ( struct int13_drive *drive ) { /* Add to list of emulated drives */ list_add ( &drive->list, &drives ); + + /* Update BIOS drive count */ + int13_set_num_drives(); } /** @@ -652,7 +706,8 @@ int int13_boot ( unsigned int drive ) { /* Jump to boot sector */ if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) { - DBG ( "INT 13 drive %02x boot returned\n", drive ); + DBG ( "INT 13 drive %02x boot returned: %s\n", + drive, strerror ( rc ) ); return rc; } diff --git a/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c b/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c index 02aec4ba..00efd8ff 100644 --- a/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c +++ b/gpxe/src/arch/i386/interface/pcbios/iscsiboot.c @@ -4,26 +4,16 @@ #include <stdio.h> #include <errno.h> #include <gpxe/iscsi.h> -#include <gpxe/settings.h> -#include <gpxe/dhcp.h> #include <gpxe/netdevice.h> #include <gpxe/ibft.h> -#include <gpxe/init.h> #include <gpxe/sanboot.h> #include <int13.h> -#include <usr/autoboot.h> -struct setting keep_san_setting __setting = { - .name = "keep-san", - .description = "Preserve SAN connection", - .tag = DHCP_EB_KEEP_SAN, - .type = &setting_type_int8, -}; +FILE_LICENCE ( GPL2_OR_LATER ); static int iscsiboot ( const char *root_path ) { struct scsi_device *scsi; struct int13_drive *drive; - int keep_san; int rc; scsi = zalloc ( sizeof ( *scsi ) ); @@ -37,8 +27,6 @@ static int iscsiboot ( const char *root_path ) { goto err_alloc_drive; } - printf ( "iSCSI booting from %s\n", root_path ); - if ( ( rc = iscsi_attach ( scsi, root_path ) ) != 0 ) { printf ( "Could not attach iSCSI device: %s\n", strerror ( rc ) ); @@ -65,12 +53,8 @@ static int iscsiboot ( const char *root_path ) { printf ( "Boot failed\n" ); /* Leave drive registered, if instructed to do so */ - keep_san = fetch_intz_setting ( NULL, &keep_san_setting ); - if ( keep_san ) { - printf ( "Preserving connection to SAN disk\n" ); - shutdown_exit_flags |= SHUTDOWN_KEEP_DEVICES; + if ( keep_san() ) return rc; - } printf ( "Unregistering BIOS drive %#02x\n", drive->drive ); unregister_int13_drive ( drive ); diff --git a/gpxe/src/arch/i386/interface/pcbios/keepsan.c b/gpxe/src/arch/i386/interface/pcbios/keepsan.c new file mode 100644 index 00000000..904e017d --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/keepsan.c @@ -0,0 +1,26 @@ +#include <stdint.h> +#include <stdio.h> +#include <gpxe/settings.h> +#include <gpxe/dhcp.h> +#include <gpxe/init.h> +#include <gpxe/sanboot.h> +#include <usr/autoboot.h> + +struct setting keep_san_setting __setting = { + .name = "keep-san", + .description = "Preserve SAN connection", + .tag = DHCP_EB_KEEP_SAN, + .type = &setting_type_int8, +}; + +int keep_san ( void ) { + int keep_san; + + keep_san = fetch_intz_setting ( NULL, &keep_san_setting ); + if ( ! keep_san ) + return 0; + + printf ( "Preserving connection to SAN disk\n" ); + shutdown_exit_flags |= SHUTDOWN_KEEP_DEVICES; + return 1; +} diff --git a/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c index 744d8e30..0645fe63 100644 --- a/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c +++ b/gpxe/src/arch/i386/interface/pcbios/memtop_umalloc.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/arch/i386/interface/pcbios/pcibios.c b/gpxe/src/arch/i386/interface/pcbios/pcibios.c index 81b4fd3c..f2c3880c 100644 --- a/gpxe/src/arch/i386/interface/pcbios/pcibios.c +++ b/gpxe/src/arch/i386/interface/pcbios/pcibios.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <gpxe/pci.h> #include <realmode.h> diff --git a/gpxe/src/arch/i386/interface/pcbios/sbft.c b/gpxe/src/arch/i386/interface/pcbios/sbft.c new file mode 100644 index 00000000..12927c77 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pcbios/sbft.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2009 Fen Systems Ltd <mbrown@fensystems.co.uk>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +FILE_LICENCE ( BSD2 ); + +/** @file + * + * SRP boot firmware table + * + */ + +#include <assert.h> +#include <realmode.h> +#include <gpxe/srp.h> +#include <gpxe/ib_srp.h> +#include <gpxe/acpi.h> +#include <gpxe/sbft.h> + +#define sbftab __use_data16 ( sbftab ) +/** The sBFT used by gPXE */ +struct gpxe_sbft __data16 ( sbftab ) = { + /* Table header */ + .table = { + /* ACPI header */ + .acpi = { + .signature = SBFT_SIG, + .length = sizeof ( sbftab ), + .revision = 1, + .oem_id = "FENSYS", + .oem_table_id = "gPXE", + }, + .scsi_offset = offsetof ( typeof ( sbftab ), scsi ), + .srp_offset = offsetof ( typeof ( sbftab ), srp ), + .ib_offset = offsetof ( typeof ( sbftab ), ib ), + }, +}; + +/** + * Fill in all variable portions of sBFT + * + * @v srp SRP device + * @ret rc Return status code + */ +int sbft_fill_data ( struct srp_device *srp ) { + struct sbft_scsi_subtable *sbft_scsi = &sbftab.scsi; + struct sbft_srp_subtable *sbft_srp = &sbftab.srp; + struct sbft_ib_subtable *sbft_ib = &sbftab.ib; + struct ib_srp_parameters *ib_params; + struct segoff rm_sbftab = { + .segment = rm_ds, + .offset = __from_data16 ( &sbftab ), + }; + + /* Fill in the SCSI subtable */ + memcpy ( &sbft_scsi->lun, &srp->lun, sizeof ( sbft_scsi->lun ) ); + + /* Fill in the SRP subtable */ + memcpy ( &sbft_srp->port_ids, &srp->port_ids, + sizeof ( sbft_srp->port_ids ) ); + + /* Fill in the IB subtable */ + assert ( srp->transport == &ib_srp_transport ); + ib_params = ib_srp_params ( srp ); + memcpy ( &sbft_ib->sgid, &ib_params->sgid, sizeof ( sbft_ib->sgid ) ); + memcpy ( &sbft_ib->dgid, &ib_params->dgid, sizeof ( sbft_ib->dgid ) ); + memcpy ( &sbft_ib->service_id, &ib_params->service_id, + sizeof ( sbft_ib->service_id ) ); + sbft_ib->pkey = ib_params->pkey; + + /* Update checksum */ + acpi_fix_checksum ( &sbftab.table.acpi ); + + DBGC ( &sbftab, "SRP Boot Firmware Table at %04x:%04x:\n", + rm_sbftab.segment, rm_sbftab.offset ); + DBGC_HDA ( &sbftab, rm_sbftab, &sbftab, sizeof ( sbftab ) ); + + return 0; +} diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_call.c b/gpxe/src/arch/i386/interface/pxe/pxe_call.c index 06dee25c..66a9b1e2 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_call.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_call.c @@ -16,7 +16,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/uaccess.h> +#include <gpxe/init.h> #include <registers.h> #include <biosint.h> #include <pxe.h> @@ -34,6 +37,9 @@ extern struct segoff __text16 ( pxe_int_1a_vector ); /** INT 1A handler */ extern void pxe_int_1a ( void ); +/** INT 1A hooked flag */ +static int int_1a_hooked = 0; + /** A function pointer to hold any PXE API call * * Used by pxe_api_call() to avoid large swathes of duplicated code. @@ -98,6 +104,7 @@ union pxenv_call { PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * ); PXENV_EXIT_t ( * file_exec ) ( struct s_PXENV_FILE_EXEC * ); PXENV_EXIT_t ( * file_api_check ) ( struct s_PXENV_FILE_API_CHECK * ); + PXENV_EXIT_t ( * file_exit_hook ) ( struct s_PXENV_FILE_EXIT_HOOK * ); }; /** @@ -304,6 +311,10 @@ __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) { pxenv_call.file_api_check = pxenv_file_api_check; param_len = sizeof ( pxenv_any.file_api_check ); break; + case PXENV_FILE_EXIT_HOOK: + pxenv_call.file_exit_hook = pxenv_file_exit_hook; + param_len = sizeof ( pxenv_any.file_exit_hook ); + break; default: DBG ( "PXENV_UNKNOWN_%hx", opcode ); pxenv_call.unknown = pxenv_unknown; @@ -334,6 +345,18 @@ __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) { } /** + * Dispatch weak PXE API call with PXE stack available + * + * @v ix86 Registers for PXE call + * @ret present Zero (PXE stack present) + */ +int _pxe_api_call_weak ( struct i386_all_regs *ix86 ) +{ + pxe_api_call ( ix86 ); + return 0; +} + +/** * Dispatch PXE loader call * * @v es:di Address of PXE parameter block @@ -362,25 +385,6 @@ __asmcall void pxe_loader_call ( struct i386_all_regs *ix86 ) { } /** - * Hook INT 1A for PXE - * - */ -void pxe_hook_int1a ( void ) { - hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a, - &pxe_int_1a_vector ); -} - -/** - * Unhook INT 1A for PXE - * - * @ret rc Return status code - */ -int pxe_unhook_int1a ( void ) { - return unhook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a, - &pxe_int_1a_vector ); -} - -/** * Calculate byte checksum as used by PXE * * @v data Data @@ -401,7 +405,7 @@ static uint8_t pxe_checksum ( void *data, size_t size ) { * Initialise !PXE and PXENV+ structures * */ -void pxe_init_structures ( void ) { +static void pxe_init_structures ( void ) { uint32_t rm_cs_phys = ( rm_cs << 4 ); uint32_t rm_ds_phys = ( rm_ds << 4 ); @@ -427,6 +431,55 @@ void pxe_init_structures ( void ) { pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) ); } +/** PXE structure initialiser */ +struct init_fn pxe_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = pxe_init_structures, +}; + +/** + * Activate PXE stack + * + * @v netdev Net device to use as PXE net device + */ +void pxe_activate ( struct net_device *netdev ) { + + /* Ensure INT 1A is hooked */ + if ( ! int_1a_hooked ) { + hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a, + &pxe_int_1a_vector ); + int_1a_hooked = 1; + } + + /* Set PXE network device */ + pxe_set_netdev ( netdev ); +} + +/** + * Deactivate PXE stack + * + * @ret rc Return status code + */ +int pxe_deactivate ( void ) { + int rc; + + /* Clear PXE network device */ + pxe_set_netdev ( NULL ); + + /* Ensure INT 1A is unhooked, if possible */ + if ( int_1a_hooked ) { + if ( ( rc = unhook_bios_interrupt ( 0x1a, + (unsigned int) pxe_int_1a, + &pxe_int_1a_vector ))!= 0){ + DBG ( "Could not unhook INT 1A: %s\n", + strerror ( rc ) ); + return rc; + } + int_1a_hooked = 0; + } + + return 0; +} + /** * Start PXE NBP at 0000:7c00 * diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S index 0e8c8e2d..0d3a57cd 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_entry.S +++ b/gpxe/src/arch/i386/interface/pxe/pxe_entry.S @@ -17,6 +17,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ) + .arch i386 /**************************************************************************** diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_file.c b/gpxe/src/arch/i386/interface/pxe/pxe_file.c index 41674588..8d832123 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_file.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_file.c @@ -12,9 +12,12 @@ #include <gpxe/posix_io.h> #include <gpxe/features.h> #include <pxe.h> +#include <realmode.h> /* * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. + * Portions (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>. + * [PXE exit hook logic] * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -31,6 +34,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 ); /** @@ -228,6 +233,9 @@ PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) { return PXENV_EXIT_SUCCESS; } +segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 }; +#define pxe_exit_hook __use_data16 ( pxe_exit_hook ) + /** * FILE API CHECK * @@ -258,7 +266,41 @@ PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_chec file_api_check->Magic = 0xe9c17b20; file_api_check->Provider = 0x45585067; /* "gPXE" */ file_api_check->APIMask = 0x0000007f; /* Functions e0-e6 */ + /* Check to see if we have a PXE exit hook */ + if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) + /* Function e7, also */ + file_api_check->APIMask |= 0x00000080; file_api_check->Flags = 0; /* None defined */ return PXENV_EXIT_SUCCESS; } } + +/** + * FILE EXIT HOOK + * + * @v file_exit_hook Pointer to a struct + * s_PXENV_FILE_EXIT_HOOK + * @v s_PXENV_FILE_EXIT_HOOK::Hook SEG16:OFF16 to jump to + * @ret #PXENV_EXIT_SUCCESS Successfully set hook + * @ret #PXENV_EXIT_FAILURE We're not an NBP build + * @ret s_PXENV_FILE_EXIT_HOOK::Status PXE status code + * + */ +PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK + *file_exit_hook ) { + DBG ( "PXENV_FILE_EXIT_HOOK" ); + + /* Check to see if we have a PXE exit hook */ + if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) { + /* We'll jump to the specified SEG16:OFF16 during exit */ + pxe_exit_hook.segment = file_exit_hook->Hook.segment; + pxe_exit_hook.offset = file_exit_hook->Hook.offset; + file_exit_hook->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; + } + + DBG ( " not NBP" ); + file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED; + return PXENV_EXIT_FAILURE; +} + diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_loader.c b/gpxe/src/arch/i386/interface/pxe/pxe_loader.c index d228a36d..b35caf77 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_loader.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_loader.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/init.h> #include "pxe.h" #include "pxe_call.h" @@ -37,9 +39,6 @@ PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) { DBG ( "[PXENV_UNDI_LOADER to CS %04x DS %04x]", undi_loader->UNDI_CS, undi_loader->UNDI_DS ); - /* Set up PXE data structures */ - pxe_init_structures(); - /* Fill in UNDI loader structure */ undi_loader->PXEptr.segment = rm_cs; undi_loader->PXEptr.offset = __from_text16 ( &ppxe ); diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c b/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c index 193abc3d..3939c7bf 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_preboot.c @@ -23,6 +23,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <stdlib.h> @@ -35,6 +37,7 @@ #include <gpxe/init.h> #include <gpxe/if_ether.h> #include <basemem_packet.h> +#include <biosint.h> #include "pxe.h" #include "pxe_call.h" @@ -294,11 +297,8 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { } DBG ( " using netdev %s", netdev->name ); - /* Save as PXE net device */ - pxe_set_netdev ( netdev ); - - /* Hook INT 1A */ - pxe_hook_int1a(); + /* Activate PXE */ + pxe_activate ( netdev ); start_undi->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -311,15 +311,20 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) { DBG ( "PXENV_STOP_UNDI" ); - /* Unhook INT 1A */ - pxe_unhook_int1a(); - - /* Clear PXE net device */ - pxe_set_netdev ( NULL ); + /* Deactivate PXE */ + pxe_deactivate(); /* Prepare for unload */ shutdown ( SHUTDOWN_BOOT ); + /* Check to see if we still have any hooked interrupts */ + if ( hooked_bios_interrupts != 0 ) { + DBG ( "PXENV_STOP_UNDI failed: %d interrupts still hooked\n", + hooked_bios_interrupts ); + stop_undi->Status = PXENV_STATUS_KEEP_UNDI; + return PXENV_EXIT_FAILURE; + } + stop_undi->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c b/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c index 715a0b61..0e3ca3c5 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_tftp.c @@ -22,6 +22,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <stdio.h> #include <errno.h> @@ -138,7 +140,7 @@ static void pxe_tftp_xfer_close ( struct xfer_interface *xfer __unused, static struct xfer_interface_operations pxe_tftp_xfer_ops = { .close = pxe_tftp_xfer_close, - .vredirect = xfer_vopen, + .vredirect = xfer_vreopen, .window = unlimited_xfer_window, .alloc_iob = default_xfer_alloc_iob, .deliver_iob = pxe_tftp_xfer_deliver_iob, @@ -163,7 +165,8 @@ static struct xfer_interface_operations pxe_tftp_xfer_ops = { * @ret rc Return status code */ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port, - const unsigned char *filename, size_t blksize ) { + const unsigned char *filename, size_t blksize, + int sizeonly ) { char uri_string[PXE_TFTP_URI_LEN]; struct in_addr address; int rc; @@ -183,7 +186,8 @@ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port, if ( blksize < TFTP_DEFAULT_BLKSIZE ) blksize = TFTP_DEFAULT_BLKSIZE; snprintf ( uri_string, sizeof ( uri_string ), - "tftp://%s:%d%s%s?blksize=%zd", + "tftp%s://%s:%d%s%s?blksize=%zd", + sizeonly ? "size" : "", inet_ntoa ( address ), ntohs ( port ), ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize ); DBG ( " %s", uri_string ); @@ -252,7 +256,8 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) { if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress, tftp_open->TFTPPort, tftp_open->FileName, - tftp_open->PacketSize ) ) != 0 ) { + tftp_open->PacketSize, + 0) ) != 0 ) { tftp_open->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } @@ -486,7 +491,7 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE /* Open TFTP file */ if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0, - tftp_read_file->FileName, 0 ) ) != 0 ) { + tftp_read_file->FileName, 0, 0 ) ) != 0 ) { tftp_read_file->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } @@ -556,7 +561,7 @@ PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE /* Open TFTP file */ if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0, - tftp_get_fsize->FileName, 0 ) ) != 0 ) { + tftp_get_fsize->FileName, 0, 1 ) ) != 0 ) { tftp_get_fsize->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_udp.c b/gpxe/src/arch/i386/interface/pxe/pxe_udp.c index 033b1ad9..f4702201 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_udp.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_udp.c @@ -30,6 +30,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** A PXE UDP connection */ struct pxe_udp_connection { /** Data transfer interface to UDP stack */ diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_undi.c b/gpxe/src/arch/i386/interface/pxe/pxe_undi.c index 4e4a3da0..c9b67c06 100644 --- a/gpxe/src/arch/i386/interface/pxe/pxe_undi.c +++ b/gpxe/src/arch/i386/interface/pxe/pxe_undi.c @@ -22,6 +22,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdio.h> #include <string.h> @@ -88,12 +90,26 @@ static void pxe_netdev_close ( void ) { undi_tx_count = 0; } +/** + * Dump multicast address list + * + * @v mcast PXE multicast address list + */ +static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) { + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; + unsigned int i; + + for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) { + DBG ( " %s", ll_protocol->ntoa ( mcast->McastAddr[i] ) ); + } +} + /* PXENV_UNDI_STARTUP * * Status: working */ PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) { - DBG ( "PXENV_UNDI_STARTUP" ); + DBG ( "PXENV_UNDI_STARTUP\n" ); undi_startup->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -104,7 +120,7 @@ PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) { * Status: working */ PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) { - DBG ( "PXENV_UNDI_CLEANUP" ); + DBG ( "PXENV_UNDI_CLEANUP\n" ); pxe_netdev_close(); @@ -118,7 +134,8 @@ PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) { */ PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE *undi_initialize ) { - DBG ( "PXENV_UNDI_INITIALIZE" ); + DBG ( "PXENV_UNDI_INITIALIZE protocolini %08x\n", + undi_initialize->ProtocolIni ); undi_initialize->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -133,9 +150,13 @@ PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET int rc; DBG ( "PXENV_UNDI_RESET_ADAPTER" ); + pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf ); + DBG ( "\n" ); pxe_netdev_close(); if ( ( rc = pxe_netdev_open() ) != 0 ) { + DBG ( "PXENV_UNDI_RESET_ADAPTER could not reopen %s: %s\n", + pxe_netdev->name, strerror ( rc ) ); undi_reset_adapter->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } @@ -150,7 +171,7 @@ PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET */ PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN *undi_shutdown ) { - DBG ( "PXENV_UNDI_SHUTDOWN" ); + DBG ( "PXENV_UNDI_SHUTDOWN\n" ); pxe_netdev_close(); @@ -165,9 +186,14 @@ PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) { int rc; - DBG ( "PXENV_UNDI_OPEN" ); + DBG ( "PXENV_UNDI_OPEN flag %04x filter %04x", + undi_open->OpenFlag, undi_open->PktFilter ); + pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf ); + DBG ( "\n" ); if ( ( rc = pxe_netdev_open() ) != 0 ) { + DBG ( "PXENV_UNDI_OPEN could not open %s: %s\n", + pxe_netdev->name, strerror ( rc ) ); undi_open->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } @@ -181,7 +207,7 @@ PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) { * Status: working */ PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) { - DBG ( "PXENV_UNDI_CLOSE" ); + DBG ( "PXENV_UNDI_CLOSE\n" ); pxe_netdev_close(); @@ -207,7 +233,13 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT unsigned int i; int rc; - DBG ( "PXENV_UNDI_TRANSMIT" ); + DBG2 ( "PXENV_UNDI_TRANSMIT" ); + + /* Forcibly enable interrupts at this point, to work around + * callers that never call PXENV_UNDI_OPEN before attempting + * to use the UNDI API. + */ + netdev_irq ( pxe_netdev, 1 ); /* Identify network-layer protocol */ switch ( undi_transmit->Protocol ) { @@ -219,25 +251,29 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT ll_hlen = 0; break; default: + DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol ); undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; return PXENV_EXIT_FAILURE; } - DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); + DBG2 ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); /* Calculate total packet length */ copy_from_real ( &tbd, undi_transmit->TBD.segment, undi_transmit->TBD.offset, sizeof ( tbd ) ); len = tbd.ImmedLength; - DBG ( " %d", tbd.ImmedLength ); + DBG2 ( " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset, + tbd.ImmedLength ); for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { datablk = &tbd.DataBlock[i]; len += datablk->TDDataLen; - DBG ( "+%d", datablk->TDDataLen ); + DBG2 ( " %04x:%04x+%x", datablk->TDDataPtr.segment, + datablk->TDDataPtr.offset, datablk->TDDataLen ); } /* Allocate and fill I/O buffer */ iobuf = alloc_iob ( ll_hlen + len ); if ( ! iobuf ) { + DBG2 ( " could not allocate iobuf\n" ); undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES; return PXENV_EXIT_FAILURE; } @@ -262,45 +298,57 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT undi_transmit->DestAddr.offset, ll_protocol->ll_addr_len ); ll_dest = destaddr; + DBG2 ( " DEST %s", ll_protocol->ntoa ( ll_dest ) ); } else { - DBG ( " BCAST" ); - ll_dest = ll_protocol->ll_broadcast; + ll_dest = pxe_netdev->ll_broadcast; + DBG2 ( " BCAST" ); } /* Add link-layer header */ - if ( ( rc = ll_protocol->push ( iobuf, ll_dest, + if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest, pxe_netdev->ll_addr, net_protocol->net_proto ))!=0){ + DBG2 ( " could not add link-layer header: %s\n", + strerror ( rc ) ); free_iob ( iobuf ); undi_transmit->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } } + /* Flag transmission as in-progress. Do this before starting + * to transmit the packet, because the ISR may trigger before + * we return from netdev_tx(). + */ + undi_tx_count++; + /* Transmit packet */ + DBG2 ( "\n" ); if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) { + DBG2 ( "PXENV_UNDI_TRANSMIT could not transmit: %s\n", + strerror ( rc ) ); + undi_tx_count--; undi_transmit->Status = PXENV_STATUS ( rc ); return PXENV_EXIT_FAILURE; } - /* Flag transmission as in-progress */ - undi_tx_count++; - undi_transmit->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } /* PXENV_UNDI_SET_MCAST_ADDRESS * - * Status: stub (no PXE multicast support) + * Status: working (for NICs that support receive-all-multicast) */ PXENV_EXIT_t pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address ) { DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" ); + pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf ); + DBG ( "\n" ); - undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; + undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; } /* PXENV_UNDI_SET_STATION_ADDRESS @@ -310,13 +358,16 @@ pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS PXENV_EXIT_t pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address ) { + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; - DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" ); + DBG ( "PXENV_UNDI_SET_STATION_ADDRESS %s", + ll_protocol->ntoa ( undi_set_station_address->StationAddress ) ); /* If adapter is open, the change will have no effect; return * an error */ if ( pxe_netdev->state & NETDEV_OPEN ) { + DBG ( " failed: netdev is open\n" ); undi_set_station_address->Status = PXENV_STATUS_UNDI_INVALID_STATE; return PXENV_EXIT_FAILURE; @@ -325,8 +376,9 @@ pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS /* Update MAC address */ memcpy ( pxe_netdev->ll_addr, &undi_set_station_address->StationAddress, - pxe_netdev->ll_protocol->ll_addr_len ); + ll_protocol->ll_addr_len ); + DBG ( "\n" ); undi_set_station_address->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } @@ -339,10 +391,17 @@ pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS PXENV_EXIT_t pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter ) { - DBG ( "PXENV_UNDI_SET_PACKET_FILTER" ); - undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; + DBG ( "PXENV_UNDI_SET_PACKET_FILTER %02x\n", + undi_set_packet_filter->filter ); + + /* Pretend that we succeeded, otherwise the 3Com DOS UNDI + * driver refuses to load. (We ignore the filter value in the + * PXENV_UNDI_OPEN call anyway.) + */ + undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS; + + return PXENV_EXIT_SUCCESS; } /* PXENV_UNDI_GET_INFORMATION @@ -353,6 +412,7 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information ) { struct device *dev = pxe_netdev->dev; struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; + size_t ll_addr_len = ll_protocol->ll_addr_len; DBG ( "PXENV_UNDI_GET_INFORMATION" ); @@ -361,17 +421,14 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION /* Cheat: assume all cards can cope with this */ undi_get_information->MaxTranUnit = ETH_MAX_MTU; undi_get_information->HwType = ntohs ( ll_protocol->ll_proto ); - undi_get_information->HwAddrLen = ll_protocol->ll_addr_len; - /* Cheat: assume card is always configured with its permanent - * node address. This is a valid assumption within Etherboot - * at the time of writing. - */ + undi_get_information->HwAddrLen = ll_addr_len; + assert ( ll_addr_len <= + sizeof ( undi_get_information->CurrentNodeAddress ) ); memcpy ( &undi_get_information->CurrentNodeAddress, pxe_netdev->ll_addr, sizeof ( undi_get_information->CurrentNodeAddress ) ); - memcpy ( &undi_get_information->PermNodeAddress, - pxe_netdev->ll_addr, - sizeof ( undi_get_information->PermNodeAddress ) ); + ll_protocol->init_addr ( pxe_netdev->hw_addr, + &undi_get_information->PermNodeAddress ); undi_get_information->ROMAddress = 0; /* nic.rom_info->rom_segment; */ /* We only provide the ability to receive or transmit a single @@ -380,6 +437,10 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION undi_get_information->RxBufCt = 1; undi_get_information->TxBufCt = 1; + DBG ( " io %04x irq %d mtu %d %s %s\n", + undi_get_information->BaseIo, undi_get_information->IntNumber, + undi_get_information->MaxTranUnit, ll_protocol->name, + ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress )); undi_get_information->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } @@ -397,6 +458,11 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad; undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad; + DBG ( " txok %d rxok %d rxcrc %d rxrsrc %d\n", + undi_get_statistics->XmtGoodFrames, + undi_get_statistics->RcvGoodFrames, + undi_get_statistics->RcvCRCErrors, + undi_get_statistics->RcvResourceErrors ); undi_get_statistics->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } @@ -407,7 +473,7 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS */ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics ) { - DBG ( "PXENV_UNDI_CLEAR_STATISTICS" ); + DBG ( "PXENV_UNDI_CLEAR_STATISTICS\n" ); memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) ); memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) ); @@ -423,7 +489,7 @@ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS */ PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags ) { - DBG ( "PXENV_UNDI_INITIATE_DIAGS" ); + DBG ( "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" ); undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED; return PXENV_EXIT_FAILURE; @@ -436,7 +502,7 @@ PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS */ PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt ) { - DBG ( "PXENV_UNDI_FORCE_INTERRUPT" ); + DBG ( "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" ); undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED; return PXENV_EXIT_FAILURE; @@ -444,15 +510,28 @@ PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT /* PXENV_UNDI_GET_MCAST_ADDRESS * - * Status: stub (no PXE multicast support) + * Status: working */ PXENV_EXIT_t pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address ) { - DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" ); + struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol; + struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr }; + int rc; - undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; + DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS %s", inet_ntoa ( ip ) ); + + if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip, + undi_get_mcast_address->MediaAddr ))!=0){ + DBG ( " failed: %s\n", strerror ( rc ) ); + undi_get_mcast_address->Status = PXENV_STATUS ( rc ); + return PXENV_EXIT_FAILURE; + } + DBG ( "=>%s\n", + ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) ); + + undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; } /* PXENV_UNDI_GET_NIC_TYPE @@ -484,6 +563,13 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE */ undi_get_nic_type->info.pci.SubVendor_ID = 0xffff; undi_get_nic_type->info.pci.SubDevice_ID = 0xffff; + DBG ( " PCI %02x:%02x.%x %04x:%04x (%04x:%04x) %02x%02x%02x " + "rev %02x\n", PCI_BUS ( info->BusDevFunc ), + PCI_SLOT ( info->BusDevFunc ), + PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID, + info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID, + info->Base_Class, info->Sub_Class, info->Prog_Intf, + info->Rev ); break; } case BUS_TYPE_ISAPNP: { struct pnp_nic_info *info = &undi_get_nic_type->info.pnp; @@ -495,8 +581,12 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE /* Cheat: remaining fields are probably unnecessary, * and would require adding extra code to isapnp.c. */ + DBG ( " ISAPnP CSN %04x %08x %02x%02x%02x\n", + info->CardSelNum, info->EISA_Dev_ID, + info->Base_Class, info->Sub_Class, info->Prog_Intf ); break; } default: + DBG ( " failed: unknown bus type\n" ); undi_get_nic_type->Status = PXENV_STATUS_FAILURE; return PXENV_EXIT_FAILURE; } @@ -517,12 +607,18 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO * Most PXE stacks seem to take this approach. */ snprintf ( ( char * ) undi_get_iface_info->IfaceType, - sizeof ( undi_get_iface_info->IfaceType ), "gPXE" ); + sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" ); undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */ - undi_get_iface_info->ServiceFlags = 0; + undi_get_iface_info->ServiceFlags = + ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST | + SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET | + SUPPORTED_OPEN_CLOSE | SUPPORTED_IRQ ); memset ( undi_get_iface_info->Reserved, 0, sizeof(undi_get_iface_info->Reserved) ); + DBG ( " %s %dbps flags %08x\n", undi_get_iface_info->IfaceType, + undi_get_iface_info->LinkSpeed, + undi_get_iface_info->ServiceFlags ); undi_get_iface_info->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } @@ -533,7 +629,7 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO */ PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE *undi_get_state ) { - DBG ( "PXENV_UNDI_GET_STATE" ); + DBG ( "PXENV_UNDI_GET_STATE failed: unsupported\n" ); undi_get_state->Status = PXENV_STATUS_UNSUPPORTED; return PXENV_EXIT_FAILURE; @@ -555,7 +651,10 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { unsigned int prottype; int rc; - DBG ( "PXENV_UNDI_ISR" ); + /* Use coloured debug, since UNDI ISR messages are likely to + * be interspersed amongst other UNDI messages. + */ + DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" ); /* Just in case some idiot actually looks at these fields when * we weren't meant to fill them in... @@ -568,7 +667,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { switch ( undi_isr->FuncFlag ) { case PXENV_UNDI_ISR_IN_START : - DBG ( " START" ); + DBGC2 ( &pxenv_undi_isr, " START" ); /* Call poll(). This should acknowledge the device * interrupt and queue up any received packet. @@ -579,13 +678,14 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { netdev_irq ( pxe_netdev, 0 ); /* Always say it was ours for the sake of simplicity */ + DBGC2 ( &pxenv_undi_isr, " OURS" ); undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; break; case PXENV_UNDI_ISR_IN_PROCESS : - DBG ( " PROCESS" ); - /* Fall through */ case PXENV_UNDI_ISR_IN_GET_NEXT : - DBG ( " GET_NEXT" ); + DBGC2 ( &pxenv_undi_isr, " %s", + ( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ? + "PROCESS" : "GET_NEXT" ) ); /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START; @@ -600,7 +700,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { * netdev TX queue is empty, report the TX completion. */ if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) { - DBG ( " TXC" ); + DBGC2 ( &pxenv_undi_isr, " TXC" ); undi_tx_count--; undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT; break; @@ -609,7 +709,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Remove first packet from netdev RX queue */ iobuf = netdev_rx_dequeue ( pxe_netdev ); if ( ! iobuf ) { - DBG ( " DONE" ); + DBGC2 ( &pxenv_undi_isr, " DONE" ); /* No more packets remaining */ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; /* Re-enable interrupts */ @@ -619,17 +719,18 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Copy packet to base memory buffer */ len = iob_len ( iobuf ); - DBG ( " RX %zd", len ); + DBGC2 ( &pxenv_undi_isr, " RX" ); if ( len > sizeof ( basemem_packet ) ) { /* Should never happen */ + DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len ); len = sizeof ( basemem_packet ); } memcpy ( basemem_packet, iobuf->data, len ); /* Strip link-layer header */ ll_protocol = pxe_netdev->ll_protocol; - if ( ( rc = ll_protocol->pull ( iobuf, &ll_dest, &ll_source, - &net_proto ) ) != 0 ) { + if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest, + &ll_source, &net_proto )) !=0){ /* Assume unknown net_proto and no ll_source */ net_proto = 0; ll_source = NULL; @@ -655,7 +756,6 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { prottype = P_UNKNOWN; break; } - DBG ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) ); /* Fill in UNDI_ISR structure */ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; @@ -666,12 +766,18 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { undi_isr->Frame.offset = __from_data16 ( basemem_packet ); undi_isr->ProtType = prottype; undi_isr->PktType = XMT_DESTADDR; + DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d", + undi_isr->Frame.segment, undi_isr->Frame.offset, + undi_isr->BufferLength, undi_isr->FrameLength, + ( net_protocol ? net_protocol->name : "RAW" ), + undi_isr->FrameHeaderLength ); /* Free packet */ free_iob ( iobuf ); break; default : - DBG ( " INVALID(%04x)", undi_isr->FuncFlag ); + DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n", + undi_isr->FuncFlag ); /* Should never happen */ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; @@ -679,6 +785,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { return PXENV_EXIT_FAILURE; } + DBGC2 ( &pxenv_undi_isr, "\n" ); undi_isr->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } diff --git a/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c b/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c new file mode 100644 index 00000000..582db5d2 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/dhcp.h> +#include <pxeparent.h> +#include <pxe_api.h> +#include <pxe_types.h> +#include <pxe.h> + +/** @file + * + * Call interface to parent PXE stack + * + */ + +/** + * Name PXE API call + * + * @v function API call number + * @ret name API call name + */ +static inline __attribute__ (( always_inline )) const char * +pxeparent_function_name ( unsigned int function ) { + switch ( function ) { + case PXENV_START_UNDI: + return "PXENV_START_UNDI"; + case PXENV_STOP_UNDI: + return "PXENV_STOP_UNDI"; + case PXENV_UNDI_STARTUP: + return "PXENV_UNDI_STARTUP"; + case PXENV_UNDI_CLEANUP: + return "PXENV_UNDI_CLEANUP"; + case PXENV_UNDI_INITIALIZE: + return "PXENV_UNDI_INITIALIZE"; + case PXENV_UNDI_RESET_ADAPTER: + return "PXENV_UNDI_RESET_ADAPTER"; + case PXENV_UNDI_SHUTDOWN: + return "PXENV_UNDI_SHUTDOWN"; + case PXENV_UNDI_OPEN: + return "PXENV_UNDI_OPEN"; + case PXENV_UNDI_CLOSE: + return "PXENV_UNDI_CLOSE"; + case PXENV_UNDI_TRANSMIT: + return "PXENV_UNDI_TRANSMIT"; + case PXENV_UNDI_SET_MCAST_ADDRESS: + return "PXENV_UNDI_SET_MCAST_ADDRESS"; + case PXENV_UNDI_SET_STATION_ADDRESS: + return "PXENV_UNDI_SET_STATION_ADDRESS"; + case PXENV_UNDI_SET_PACKET_FILTER: + return "PXENV_UNDI_SET_PACKET_FILTER"; + case PXENV_UNDI_GET_INFORMATION: + return "PXENV_UNDI_GET_INFORMATION"; + case PXENV_UNDI_GET_STATISTICS: + return "PXENV_UNDI_GET_STATISTICS"; + case PXENV_UNDI_CLEAR_STATISTICS: + return "PXENV_UNDI_CLEAR_STATISTICS"; + case PXENV_UNDI_INITIATE_DIAGS: + return "PXENV_UNDI_INITIATE_DIAGS"; + case PXENV_UNDI_FORCE_INTERRUPT: + return "PXENV_UNDI_FORCE_INTERRUPT"; + case PXENV_UNDI_GET_MCAST_ADDRESS: + return "PXENV_UNDI_GET_MCAST_ADDRESS"; + case PXENV_UNDI_GET_NIC_TYPE: + return "PXENV_UNDI_GET_NIC_TYPE"; + case PXENV_UNDI_GET_IFACE_INFO: + return "PXENV_UNDI_GET_IFACE_INFO"; + /* + * Duplicate case value; this is a bug in the PXE specification. + * + * case PXENV_UNDI_GET_STATE: + * return "PXENV_UNDI_GET_STATE"; + */ + case PXENV_UNDI_ISR: + return "PXENV_UNDI_ISR"; + case PXENV_GET_CACHED_INFO: + return "PXENV_GET_CACHED_INFO"; + default: + return "UNKNOWN API CALL"; + } +} + +/** + * PXE parent parameter block + * + * Used as the paramter block for all parent PXE API calls. Resides in base + * memory. + */ +static union u_PXENV_ANY __bss16 ( pxeparent_params ); +#define pxeparent_params __use_data16 ( pxeparent_params ) + +/** PXE parent entry point + * + * Used as the indirection vector for all parent PXE API calls. Resides in + * base memory. + */ +SEGOFF16_t __bss16 ( pxeparent_entry_point ); +#define pxeparent_entry_point __use_data16 ( pxeparent_entry_point ) + +/** + * Issue parent PXE API call + * + * @v entry Parent PXE stack entry point + * @v function API call number + * @v params PXE parameter block + * @v params_len Length of PXE parameter block + * @ret rc Return status code + */ +int pxeparent_call ( SEGOFF16_t entry, unsigned int function, + void *params, size_t params_len ) { + PXENV_EXIT_t exit; + int discard_b, discard_D; + int rc; + + /* Copy parameter block and entry point */ + assert ( params_len <= sizeof ( pxeparent_params ) ); + memcpy ( &pxeparent_params, params, params_len ); + memcpy ( &pxeparent_entry_point, &entry, sizeof ( entry ) ); + + /* Call real-mode entry point. This calling convention will + * work with both the !PXE and the PXENV+ entry points. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t" + "pushw %%di\n\t" + "pushw %%bx\n\t" + "lcall *pxeparent_entry_point\n\t" + "addw $6, %%sp\n\t" ) + : "=a" ( exit ), "=b" ( discard_b ), + "=D" ( discard_D ) + : "b" ( function ), + "D" ( __from_data16 ( &pxeparent_params ) ) + : "ecx", "edx", "esi", "ebp" ); + + /* PXE API calls may rudely change the status of A20 and not + * bother to restore it afterwards. Intel is known to be + * guilty of this. + * + * Note that we will return to this point even if A20 gets + * screwed up by the parent PXE stack, because Etherboot always + * resides in an even megabyte of RAM. + */ + gateA20_set(); + + /* Determine return status code based on PXENV_EXIT and + * PXENV_STATUS + */ + if ( exit == PXENV_EXIT_SUCCESS ) { + rc = 0; + } else { + rc = -pxeparent_params.Status; + /* Paranoia; don't return success for the combination + * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS + */ + if ( rc == 0 ) + rc = -EIO; + } + + /* If anything goes wrong, print as much debug information as + * it's possible to give. + */ + if ( rc != 0 ) { + SEGOFF16_t rm_params = { + .segment = rm_ds, + .offset = __from_data16 ( &pxeparent_params ), + }; + + DBG ( "PXEPARENT %s failed: %s\n", + pxeparent_function_name ( function ), strerror ( rc ) ); + DBG ( "PXEPARENT parameters at %04x:%04x length " + "%#02zx, entry point at %04x:%04x\n", + rm_params.segment, rm_params.offset, params_len, + pxeparent_entry_point.segment, + pxeparent_entry_point.offset ); + DBG ( "PXEPARENT parameters provided:\n" ); + DBG_HDA ( rm_params, params, params_len ); + DBG ( "PXEPARENT parameters returned:\n" ); + DBG_HDA ( rm_params, &pxeparent_params, params_len ); + } + + /* Copy parameter block back */ + memcpy ( params, &pxeparent_params, params_len ); + + return rc; +} + diff --git a/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c b/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c new file mode 100644 index 00000000..66059437 --- /dev/null +++ b/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <gpxe/dhcp.h> +#include <gpxe/netdevice.h> +#include <undipreload.h> +#include <pxeparent.h> +#include <realmode.h> +#include <pxe_api.h> + +/** + * Present cached DHCP packet if it exists + */ +void __weak_impl ( get_cached_dhcpack ) ( void ) { + struct undi_device *undi; + struct s_PXENV_GET_CACHED_INFO get_cached_info; + int rc; + + /* Use preloaded UNDI device to get at PXE entry point */ + undi = &preloaded_undi; + if ( ! undi->entry.segment ) { + DBG ( "PXEDHCP no preloaded UNDI device found\n" ); + return; + } + + /* Check that stack is available to get cached info */ + if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) { + DBG ( "PXEDHCP stack was unloaded, no cache available\n" ); + return; + } + + /* Obtain cached DHCP packet */ + memset ( &get_cached_info, 0, sizeof ( get_cached_info ) ); + get_cached_info.PacketType = PXENV_PACKET_TYPE_DHCP_ACK; + + if ( ( rc = pxeparent_call ( undi->entry, PXENV_GET_CACHED_INFO, + &get_cached_info, + sizeof ( get_cached_info ) ) ) != 0 ) { + DBG ( "PXEDHCP GET_CACHED_INFO failed: %s\n", strerror ( rc ) ); + return; + } + + DBG ( "PXEDHCP got cached info at %04x:%04x length %d\n", + get_cached_info.Buffer.segment, get_cached_info.Buffer.offset, + get_cached_info.BufferSize ); + + /* Present cached DHCP packet */ + store_cached_dhcpack ( real_to_user ( get_cached_info.Buffer.segment, + get_cached_info.Buffer.offset ), + get_cached_info.BufferSize ); +} diff --git a/gpxe/src/arch/i386/interface/syslinux/com32_call.c b/gpxe/src/arch/i386/interface/syslinux/com32_call.c index 4a782dce..d2c3f918 100644 --- a/gpxe/src/arch/i386/interface/syslinux/com32_call.c +++ b/gpxe/src/arch/i386/interface/syslinux/com32_call.c @@ -21,6 +21,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <realmode.h> #include <comboot.h> diff --git a/gpxe/src/arch/i386/interface/syslinux/com32_wrapper.S b/gpxe/src/arch/i386/interface/syslinux/com32_wrapper.S index 08d7398a..5c5bd139 100644 --- a/gpxe/src/arch/i386/interface/syslinux/com32_wrapper.S +++ b/gpxe/src/arch/i386/interface/syslinux/com32_wrapper.S @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ) + .text .arch i386 .code32 diff --git a/gpxe/src/arch/i386/interface/syslinux/comboot_call.c b/gpxe/src/arch/i386/interface/syslinux/comboot_call.c index bf6c4c66..0a17bf13 100644 --- a/gpxe/src/arch/i386/interface/syslinux/comboot_call.c +++ b/gpxe/src/arch/i386/interface/syslinux/comboot_call.c @@ -21,6 +21,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <errno.h> #include <realmode.h> #include <biosint.h> @@ -37,6 +39,8 @@ #include <gpxe/init.h> #include <gpxe/image.h> #include <usr/imgmgmt.h> +#include "config/console.h" +#include "config/serial.h" /** The "SYSLINUX" version string */ static char __data16_array ( syslinux_version, [] ) = "gPXE " VERSION; @@ -324,7 +328,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { case 0x0001: /* Get Version */ /* Number of INT 22h API functions available */ - ix86->regs.ax = 0x001B; + ix86->regs.ax = 0x001D; /* SYSLINUX version number */ ix86->regs.ch = 0; /* major */ @@ -441,8 +445,10 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { break; case 0x0009: /* Call PXE Stack */ - pxe_api_call ( ix86 ); - ix86->flags &= ~CF; + if ( pxe_api_call_weak ( ix86 ) != 0 ) + ix86->flags |= CF; + else + ix86->flags &= ~CF; break; case 0x000A: /* Get Derivative-Specific Information */ @@ -454,8 +460,14 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { break; case 0x000B: /* Get Serial Console Configuration */ - /* FIXME: stub */ +#if defined(CONSOLE_SERIAL) && !defined(COMPRESERVE) + ix86->regs.dx = COMCONSOLE; + ix86->regs.cx = 115200 / COMSPEED; + ix86->regs.bx = 0; +#else ix86->regs.dx = 0; +#endif + ix86->flags &= ~CF; break; @@ -629,6 +641,17 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) { break; + case 0x001C: /* Get pointer to auxilliary data vector */ + /* FIXME: stub */ + ix86->regs.cx = 0; /* Size of the ADV */ + ix86->flags &= ~CF; + break; + + case 0x001D: /* Write auxilliary data vector */ + /* FIXME: stub */ + ix86->flags &= ~CF; + break; + default: DBG ( "COMBOOT unknown int22 function %04x\n", ix86->regs.ax ); break; diff --git a/gpxe/src/arch/i386/interface/syslinux/comboot_resolv.c b/gpxe/src/arch/i386/interface/syslinux/comboot_resolv.c index 41c3af7a..30ac502e 100644 --- a/gpxe/src/arch/i386/interface/syslinux/comboot_resolv.c +++ b/gpxe/src/arch/i386/interface/syslinux/comboot_resolv.c @@ -5,6 +5,8 @@ #include <gpxe/process.h> #include <gpxe/resolv.h> +FILE_LICENCE ( GPL2_OR_LATER ); + static int comboot_resolv_rc; static struct in_addr comboot_resolv_addr; diff --git a/gpxe/src/arch/i386/prefix/bImageprefix.S b/gpxe/src/arch/i386/prefix/bImageprefix.S deleted file mode 100644 index 30020f73..00000000 --- a/gpxe/src/arch/i386/prefix/bImageprefix.S +++ /dev/null @@ -1,611 +0,0 @@ -/* - Copyright (C) 2000, Entity Cyber, Inc. - - Authors: Gary Byers (gb@thinguin.org) - Marty Connor (mdc@thinguin.org) - Eric Biederman (ebiederman@lnxi.com) - - This code also derives a lot from arch/i386/boot/setup.S in - the linux kernel. - - 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 an Etherboot ROM image in order to allow LILO 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 LILO 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.) LILO's only interested in knowing the - number of setup sectors advertised in the table (at offset 497 in - the first sector.) - - Etherboot doesn't require much in the way of setup code. - Historically, the Linux kernel required at least 4 sectors of - setup code. Current versions of LILO look at the byte at - offset 497 in the first sector to indicate how many sectors - of setup code are contained in the image. - - The setup code that is present here does a lot of things - exactly the way the linux kernel does them instead of in - ways more typical of etherboot. Generally this is so - the code can be strongly compatible with the linux kernel. - In addition the general etherboot technique of enabling the a20 - after we switch into protected mode does not work if etherboot - is being loaded at 1MB. -*/ - - .equ CR0_PE,1 - -#ifdef GAS291 -#define DATA32 data32; -#define ADDR32 addr32; -#define LJMPI(x) ljmp x -#else -#define DATA32 data32 -#define ADDR32 addr32 -/* newer GAS295 require #define LJMPI(x) ljmp *x */ -#define LJMPI(x) ljmp x -#endif - -/* Simple and small GDT entries for booting only */ -#define GDT_ENTRY_BOOT_CS 2 -#define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1) -#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8) -#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8) - - -#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 DELTA_INITSEG (SETUPSEG - INITSEG) /* 0x0020 */ - -/* Signature words to ensure LILO loaded us right */ -#define SIG1 0xAA55 -#define SIG2 0x5A5A - - .text - .code16 - .arch i386 - .org 0 - .section ".prefix", "ax", @progbits -_prefix: - -/* - This is a minimal boot sector. If anyone tries to execute it (e.g., if - a .lkrn file is dd'ed to a floppy), print an error message. -*/ - -bootsector: - jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */ -go: - 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 - _prefix, %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: - - - .org 497 -setup_sects: - .byte SETUPSECS -root_flags: - .word 0 -syssize: - .word _verbatim_size_pgh - PREFIXPGH -swap_dev: - .word 0 -ram_size: - .word 0 -vid_mode: - .word 0 -root_dev: - .word 0 -boot_flag: - .word 0xAA55 - -/* - We're now at the beginning of the second sector of the image - - where the setup code goes. - - We don't need to do too much setup for Etherboot. - - This code gets loaded at SETUPSEG:0. It wants to start - executing the Etherboot image that's loaded at SYSSEG:0 and - whose entry point is SYSSEG:0. -*/ -setup_code: - jmp trampoline -# This is the setup header, and it must start at %cs:2 (old 0x9020:2) - - .ascii "HdrS" # header signature - .word 0x0203 # header version number (>= 0x0105) - # or else old loadlin-1.5 will fail) -realmode_swtch: .word 0, 0 # default_switch, SETUPSEG -start_sys_seg: .word SYSSEG # low load segment (obsolete) - .word kernel_version - setup_code - # pointing to kernel version string - # above section of header is compatible - # with loadlin-1.5 (header v1.5). Don't - # change it. - -type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, - # Bootlin, SYSLX, bootsect...) - # See Documentation/i386/boot.txt for - # assigned ids - -# flags, unused bits must be zero (RFU) bit within loadflags -loadflags: -LOADED_HIGH = 1 # If set, the kernel is loaded high -CAN_USE_HEAP = 0x80 # If set, the loader also has set - # heap_end_ptr to tell how much - # space behind setup.S can be used for - # heap purposes. - # Only the loader knows what is free - .byte LOADED_HIGH - -setup_move_size: .word 0x8000 # size to move, when setup is not - # loaded at 0x90000. We will move setup - # to 0x90000 then just before jumping - # into the kernel. However, only the - # loader knows how much data behind - # us also needs to be loaded. - -code32_start: # here loaders can put a different - # start address for 32-bit code. - .long 0x100000 # 0x100000 = default for big kernel - -ramdisk_image: .long 0 # address of loaded ramdisk image - # Here the loader puts the 32-bit - # address where it loaded the image. - # This only will be read by the kernel. - -ramdisk_size: .long 0 # its size in bytes - -bootsect_kludge: - .long 0 # obsolete - -heap_end_ptr: .word 0 # (Header version 0x0201 or later) - # space from here (exclusive) down to - # end of setup code can be used by setup - # for local heap purposes. - -pad1: .word 0 -cmd_line_ptr: .long 0 # (Header version 0x0202 or later) - # If nonzero, a 32-bit pointer - # to the kernel command line. - # The command line should be - # located between the start of - # setup and the end of low - # memory (0xa0000), or it may - # get overwritten before it - # gets read. If this field is - # used, there is no longer - # anything magical about the - # 0x90000 segment; the setup - # can be located anywhere in - # low memory 0x10000 or higher. - -ramdisk_max: .long 0 # (Header version 0x0203 or later) - # The highest safe address for - # the contents of an initrd - -trampoline: call start_of_setup -trampoline_end: - .space 1024 -# End of setup header ##################################################### - -start_of_setup: -# Set %ds = %cs, we know that SETUPSEG = %cs at this point - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds -# Check signature at end of setup - cmpw $SIG1, (setup_sig1 - setup_code) - jne bad_sig - - cmpw $SIG2, (setup_sig2 - setup_code) - jne bad_sig - - jmp good_sig1 - -# Routine to print asciiz string at ds:si -prtstr: - lodsb - andb %al, %al - jz fin - - call prtchr - jmp prtstr - -fin: ret - -# Part of above routine, this one just prints ascii al -prtchr: pushw %ax - pushw %cx - movw $7,%bx - movw $0x01, %cx - movb $0x0e, %ah - int $0x10 - popw %cx - popw %ax - ret - -no_sig_mess: .string "No setup signature found ..." - -good_sig1: - jmp good_sig - -# We now have to find the rest of the setup code/data -bad_sig: - movw %cs, %ax # SETUPSEG - subw $DELTA_INITSEG, %ax # INITSEG - movw %ax, %ds - xorb %bh, %bh - movb (497), %bl # get setup sect from bootsect - subw $4, %bx # LILO loads 4 sectors of setup - shlw $8, %bx # convert to words (1sect=2^8 words) - movw %bx, %cx - shrw $3, %bx # convert to segment - addw $SYSSEG, %bx - movw %bx, %cs:(start_sys_seg - setup_code) -# Move rest of setup code/data to here - movw $2048, %di # four sectors loaded by LILO - subw %si, %si - pushw %cs - popw %es - movw $SYSSEG, %ax - movw %ax, %ds - rep - movsw - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds - cmpw $SIG1, (setup_sig1 - setup_code) - jne no_sig - - cmpw $SIG2, (setup_sig2 - setup_code) - jne no_sig - - jmp good_sig - -no_sig: - lea (no_sig_mess - setup_code), %si - call prtstr - -no_sig_loop: - hlt - jmp no_sig_loop - -good_sig: - cmpw $0, %cs:(realmode_swtch - setup_code) - jz rmodeswtch_normal - - lcall *%cs:(realmode_swtch - setup_code) - jmp rmodeswtch_end - -rmodeswtch_normal: - pushw %cs - call default_switch - -rmodeswtch_end: -# we get the code32 start address and modify the below 'jmpi' -# (loader may have changed it) - movl %cs:(code32_start - setup_code), %eax - movl %eax, %cs:(code32 - setup_code) - -# then we load the segment descriptors - movw %cs, %ax # aka SETUPSEG - movw %ax, %ds - -# -# Enable A20. This is at the very best an annoying procedure. -# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. -# - -A20_TEST_LOOPS = 32 # Iterations per wait -A20_ENABLE_LOOPS = 255 # Total loops to try - -a20_try_loop: - - # First, see if we are on a system with no A20 gate. -a20_none: - call a20_test - jnz a20_done - - # Next, try the BIOS (INT 0x15, AX=0x2401) -a20_bios: - movw $0x2401, %ax - pushfl # Be paranoid about flags - int $0x15 - popfl - - call a20_test - jnz a20_done - - # Try enabling A20 through the keyboard controller -a20_kbc: - call empty_8042 - - call a20_test # Just in case the BIOS worked - jnz a20_done # but had a delayed reaction. - - movb $0xD1, %al # command write - outb %al, $0x64 - call empty_8042 - - movb $0xDF, %al # A20 on - outb %al, $0x60 - call empty_8042 - - # Wait until a20 really *is* enabled; it can take a fair amount of - # time on certain systems; Toshiba Tecras are known to have this - # problem. -a20_kbc_wait: - xorw %cx, %cx -a20_kbc_wait_loop: - call a20_test - jnz a20_done - loop a20_kbc_wait_loop - - # Final attempt: use "configuration port A" -a20_fast: - inb $0x92, %al # Configuration Port A - orb $0x02, %al # "fast A20" version - andb $0xFE, %al # don't accidentally reset - outb %al, $0x92 - - # Wait for configuration port A to take effect -a20_fast_wait: - xorw %cx, %cx -a20_fast_wait_loop: - call a20_test - jnz a20_done - loop a20_fast_wait_loop - - # A20 is still not responding. Try frobbing it again. - # - decb (a20_tries - setup_code) - jnz a20_try_loop - - movw $(a20_err_msg - setup_code), %si - call prtstr - -a20_die: - hlt - jmp a20_die - -a20_tries: - .byte A20_ENABLE_LOOPS - -a20_err_msg: - .ascii "linux: fatal error: A20 gate not responding!" - .byte 13, 10, 0 - - # If we get here, all is good -a20_done: - # Leave the idt alone - - # set up gdt - xorl %eax, %eax # Compute gdt_base - movw %ds, %ax # (Convert %ds:gdt to a linear ptr) - shll $4, %eax - addl $(bImage_gdt - setup_code), %eax - movl %eax, (bImage_gdt_48+2 - setup_code) - DATA32 lgdt %ds:(bImage_gdt_48 - setup_code) # load gdt with whatever is - # appropriate - - # Switch to protected mode - movl %cr0, %eax - orb $CR0_PE, %al - movl %eax, %cr0 - - DATA32 ljmp *%ds:(code32 - setup_code) -code32: - .long 0x100000 - .word __BOOT_CS, 0 - -# Here's a bunch of information about your current kernel.. -kernel_version: .ascii "Etherboot " - .ascii VERSION - .byte 0 - -# This is the default real mode switch routine. -# to be called just before protected mode transition -default_switch: - cli # no interrupts allowed ! - movb $0x80, %al # disable NMI for bootup - # sequence - outb %al, $0x70 - lret - -# This routine tests whether or not A20 is enabled. If so, it -# exits with zf = 0. -# -# The memory address used, 0x200, is the int $0x80 vector, which -# should be safe. - -A20_TEST_ADDR = 4*0x80 - -a20_test: - pushw %cx - pushw %ax - xorw %cx, %cx - movw %cx, %fs # Low memory - decw %cx - movw %cx, %gs # High memory area - movw $A20_TEST_LOOPS, %cx - movw %fs:(A20_TEST_ADDR), %ax - pushw %ax -a20_test_wait: - incw %ax - movw %ax, %fs:(A20_TEST_ADDR) - call delay # Serialize and make delay constant - cmpw %gs:(A20_TEST_ADDR+0x10), %ax - loope a20_test_wait - - popw %fs:(A20_TEST_ADDR) - popw %ax - popw %cx - ret - - -# This routine checks that the keyboard command queue is empty -# (after emptying the output buffers) -# -# Some machines have delusions that the keyboard buffer is always full -# with no keyboard attached... -# -# If there is no keyboard controller, we will usually get 0xff -# to all the reads. With each IO taking a microsecond and -# a timeout of 100,000 iterations, this can take about half a -# second ("delay" == outb to port 0x80). That should be ok, -# and should also be plenty of time for a real keyboard controller -# to empty. -# - -empty_8042: - pushl %ecx - movl $100000, %ecx - -empty_8042_loop: - decl %ecx - jz empty_8042_end_loop - - call delay - - inb $0x64, %al # 8042 status port - testb $1, %al # output buffer? - jz no_output - - call delay - inb $0x60, %al # read it - jmp empty_8042_loop - -no_output: - testb $2, %al # is input buffer full? - jnz empty_8042_loop # yes - loop -empty_8042_end_loop: - popl %ecx - - -# Delay is needed after doing I/O -delay: - outb %al,$0x80 - ret - -# Descriptor tables -# -# NOTE: The intel manual says gdt should be sixteen bytes aligned for -# efficiency reasons. However, there are machines which are known not -# to boot with misaligned GDTs, so alter this at your peril! If you alter -# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two -# empty GDT entries (one for NULL and one reserved). -# -# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is -# true for the Voyager Quad CPU card which will not boot without -# This directive. 16 byte aligment is recommended by intel. -# - .balign 16 -bImage_gdt: - .fill GDT_ENTRY_BOOT_CS,8,0 - - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) - .word 0 # base address = 0 - .word 0x9A00 # code read/exec - .word 0x00CF # granularity = 4096, 386 - # (+5th nibble of limit) - - .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) - .word 0 # base address = 0 - .word 0x9200 # data read/write - .word 0x00CF # granularity = 4096, 386 - # (+5th nibble of limit) -bImage_gdt_end: - .balign 4 - - .word 0 # alignment byte -bImage_idt_48: - .word 0 # idt limit = 0 - .long 0 # idt base = 0L - - .word 0 # alignment byte -bImage_gdt_48: - .word bImage_gdt_end - bImage_gdt - 1 # gdt limit - .long bImage_gdt_48 - setup_code # gdt base (filled in later) - - .section ".text16", "ax", @progbits -prefix_exit: - int $0x19 /* should try to boot machine */ -prefix_exit_end: - .previous - - - .org (PREFIXSIZE - 4) -# Setup signature -- must be last -setup_sig1: .word SIG1 -setup_sig2: .word SIG2 - /* Etherboot expects to be contiguous in memory once loaded. - * The linux bImage protocol does not do this, but since we - * don't need any information that's left in the prefix, it - * doesn't matter: we just have to ensure that we make it to _start - * - * protected_start will live at 0x100000 and it will be the - * the first code called as we enter protected mode. - */ - .code32 -protected_start: - /* Load segment registers */ - movw $__BOOT_DS, %ax - movw %ax, %ss - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - /* Use the internal etherboot stack */ - movl $(_prefix_stack_end - protected_start + 0x100000), %esp - - pushl $0 /* No parameters to preserve for exit path */ - pushl $0 /* Use prefix exit path mechanism */ - - jmp _start -/* - That's about it. -*/ diff --git a/gpxe/src/arch/i386/prefix/bootpart.S b/gpxe/src/arch/i386/prefix/bootpart.S index d60fe9bc..968da1a3 100644 --- a/gpxe/src/arch/i386/prefix/bootpart.S +++ b/gpxe/src/arch/i386/prefix/bootpart.S @@ -1,3 +1,5 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + #define BOOT_SEG 0x07c0 #define EXEC_SEG 0x0100 #define STACK_SEG 0x0200 diff --git a/gpxe/src/arch/i386/prefix/comprefix.S b/gpxe/src/arch/i386/prefix/comprefix.S deleted file mode 100644 index 2cbbca50..00000000 --- a/gpxe/src/arch/i386/prefix/comprefix.S +++ /dev/null @@ -1,46 +0,0 @@ -/* We need a real mode stack that won't be stomped on by Etherboot - which starts at 0x20000. Choose something that's sufficiently high, - but not in DOC territory. Note that we couldn't do this in a real - .com program since stack variables are in the same segment as the - code and data, but this isn't really a .com program, it just looks - like one to make DOS load it into memory. It still has the 64kB - limitation of .com files though. */ -#define STACK_SEG 0x7000 -#define STACK_SIZE 0x4000 - - .text - .code16 - .arch i386 - .section ".prefix", "ax", @progbits - -/* Cheat a little with the relocations: .COM files are loaded at 0x100 */ -_prefix: - /* Set up temporary stack */ - movw $STACK_SEG, %ax - movw %ax, %ss - movw $STACK_SIZE, %sp - - pushl $0 /* No parameters to preserve for exit path */ - pushw $0 /* Dummy return address - use prefix_exit */ - - /* Calculate segment address of image start */ - pushw %cs - popw %ax - addw $(0x100/16), %ax - pushw %ax - pushw $_start - /* Calculated lcall to _start with %cs:0000 = image start */ - lret - - .section ".text16", "ax", @progbits -prefix_exit: - movw $0x4c00,%ax /* return to DOS */ - int $0x21 /* reach this on Quit */ -prefix_exit_end: - .previous - -/* The body of etherboot is attached here at build time. - * Force 16 byte alignment - */ - .align 16,0 -_body: diff --git a/gpxe/src/arch/i386/prefix/dskprefix.S b/gpxe/src/arch/i386/prefix/dskprefix.S index 0156812a..60d351f7 100644 --- a/gpxe/src/arch/i386/prefix/dskprefix.S +++ b/gpxe/src/arch/i386/prefix/dskprefix.S @@ -16,6 +16,8 @@ * getting whole tracks at a time whenever possible. */ +FILE_LICENCE ( GPL2_ONLY ) + .equ BOOTSEG, 0x07C0 /* original address of boot-sector */ .equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */ @@ -144,9 +146,9 @@ got_sectors: /* Jump to loaded copy */ ljmp $SYSSEG, $start_runtime -endseg: .word SYSSEG + _filesz_pgh +endseg: .word SYSSEG .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "SUBW" + .ascii "ADDW" .long endseg .long 16 .long 0 diff --git a/gpxe/src/arch/i386/prefix/elf_dprefix.S b/gpxe/src/arch/i386/prefix/elf_dprefix.S deleted file mode 100644 index 0eac77e0..00000000 --- a/gpxe/src/arch/i386/prefix/elf_dprefix.S +++ /dev/null @@ -1,94 +0,0 @@ -#include "elf.h" - - .arch i386 - .section ".prefix", "a", @progbits - -#define LOAD_ADDR 0x10000 - - /* ELF Header */ - .globl elf_header -elf_header: -e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 -e_type: .short ET_DYN -e_machine: .short EM_386 -e_version: .long 1 -e_entry: .long LOAD_ADDR + _start - elf_header -e_phoff: .long elf_program_header - elf_header -e_shoff: .long 0 -e_flags: .long 0 -e_ehsize: .short elf_header_end - elf_header -e_phentsize: .short ELF32_PHDR_SIZE -e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE -e_shentsize: .short 0 -e_shnum: .short 0 -e_shstrndx: .short 0 -elf_header_end: - -elf_program_header: -phdr1_p_type: .long PT_NOTE -phdr1_p_offset: .long elf_note - elf_header -phdr1_p_vaddr: .long elf_note -phdr1_p_paddr: .long elf_note -phdr1_p_filesz: .long elf_note_end - elf_note -phdr1_p_memsz: .long elf_note_end - elf_note -phdr1_p_flags: .long PF_R | PF_W | PF_X -phdr1_p_align: .long 0 - -/* The decompressor */ -phdr2_p_type: .long PT_LOAD -phdr2_p_offset: .long 0 -phdr2_p_vaddr: .long elf_header -phdr2_p_paddr: .long LOAD_ADDR -phdr2_p_filesz: .long _verbatim_size -phdr2_p_memsz: .long _image_size -phdr2_p_flags: .long PF_R | PF_W | PF_X -phdr2_p_align: .long 16 - -elf_program_header_end: - - .globl elf_note -elf_note: - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_NAME -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz "Etherboot" -4: - - - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_VERSION -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz VERSION -4: - -#if 0 - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_CHECKSUM -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .word 0 -4: -#endif - .balign 4 -elf_note_end: - - /* Dummy routines to satisfy the build */ - .section ".text16", "ax", @progbits -prefix_exit: - -prefix_exit_end: - .previous diff --git a/gpxe/src/arch/i386/prefix/elfprefix.S b/gpxe/src/arch/i386/prefix/elfprefix.S deleted file mode 100644 index d712753a..00000000 --- a/gpxe/src/arch/i386/prefix/elfprefix.S +++ /dev/null @@ -1,94 +0,0 @@ -#include "elf.h" - - .arch i386 - .section ".prefix", "a", @progbits - -#define LOAD_ADDR 0x10000 - - /* ELF Header */ - .globl elf_header -elf_header: -e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 -e_type: .short ET_EXEC -e_machine: .short EM_386 -e_version: .long 1 -e_entry: .long LOAD_ADDR + _start - elf_header -e_phoff: .long elf_program_header - elf_header -e_shoff: .long 0 -e_flags: .long 0 -e_ehsize: .short elf_header_end - elf_header -e_phentsize: .short ELF32_PHDR_SIZE -e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE -e_shentsize: .short 0 -e_shnum: .short 0 -e_shstrndx: .short 0 -elf_header_end: - -elf_program_header: -phdr1_p_type: .long PT_NOTE -phdr1_p_offset: .long elf_note - elf_header -phdr1_p_vaddr: .long elf_note -phdr1_p_paddr: .long elf_note -phdr1_p_filesz: .long elf_note_end - elf_note -phdr1_p_memsz: .long elf_note_end - elf_note -phdr1_p_flags: .long PF_R | PF_W | PF_X -phdr1_p_align: .long 0 - -/* The decompressor */ -phdr2_p_type: .long PT_LOAD -phdr2_p_offset: .long 0 -phdr2_p_vaddr: .long elf_header -phdr2_p_paddr: .long LOAD_ADDR -phdr2_p_filesz: .long _verbatim_size -phdr2_p_memsz: .long _image_size -phdr2_p_flags: .long PF_R | PF_W | PF_X -phdr2_p_align: .long 16 - -elf_program_header_end: - - .globl elf_note -elf_note: - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_NAME -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz "Etherboot" -4: - - - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_VERSION -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz VERSION -4: - -#if 0 - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_CHECKSUM -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .word 0 -4: -#endif - .balign 4 -elf_note_end: - - /* Dummy routines to satisfy the build */ - .section ".text16", "ax", @progbits -prefix_exit: - -prefix_exit_end: - .previous diff --git a/gpxe/src/arch/i386/prefix/exeprefix.S b/gpxe/src/arch/i386/prefix/exeprefix.S deleted file mode 100755 index f1b402b7..00000000 --- a/gpxe/src/arch/i386/prefix/exeprefix.S +++ /dev/null @@ -1,41 +0,0 @@ -/* - Prefix for .exe images - Doesn't work yet, even though it starts off the same as a .com - image as shown by DOS debug. -*/ - - .text - .code16 - .arch i386 - .section ".prefix", "ax", @progbits - -_prefix: - .byte 'M', 'Z' - .short _exe_size_tail /* tail */ - .short _exe_size_pages /* pages */ - .short 0 /* relocations */ - .short 2 /* header paras */ - .short _exe_bss_size /* min */ - .short 0xFFFF /* max paras */ - .short _exe_ss_offset /* SS */ - .short _stack_size /* SP */ - .short 0 /* checksum */ - .short 0 /* IP */ - .short 0 /* CS */ - .short 0x1C /* reloc offset */ - .short 0 /* overlay number */ - .short 0 /* fill */ - .short 0 /* fill */ - - .section ".text16", "ax", @progbits -prefix_exit: - movw $0x4c00,%ax /* return to DOS */ - int $0x21 /* reach this on Quit */ -prefix_exit_end: - .previous - -/* The body of etherboot is attached here at build time. - * Force 16 byte alignment - */ - .align 16,0 -_body: diff --git a/gpxe/src/arch/i386/prefix/hdprefix.S b/gpxe/src/arch/i386/prefix/hdprefix.S index 086d7f45..05767567 100644 --- a/gpxe/src/arch/i386/prefix/hdprefix.S +++ b/gpxe/src/arch/i386/prefix/hdprefix.S @@ -1,3 +1,5 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + .text .arch i386 .section ".prefix", "awx", @progbits @@ -63,10 +65,10 @@ max_sector: max_head: .byte 0 load_length: - .long _filesz_sect + .long 0 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "SUBL" + .ascii "ADDL" .long load_length .long 512 .long 0 diff --git a/gpxe/src/arch/i386/prefix/hromprefix.S b/gpxe/src/arch/i386/prefix/hromprefix.S new file mode 100644 index 00000000..03acf1e2 --- /dev/null +++ b/gpxe/src/arch/i386/prefix/hromprefix.S @@ -0,0 +1,12 @@ +/***************************************************************************** + * ROM prefix that relocates to HIGHMEM_LOADPOINT during POST if PMM allocation + * fails. Intended to be used, with caution, on BIOSes that support PCI3.00 but + * have limited PMM support, such as most AMI BIOSes. + ***************************************************************************** + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define SHRINK_WITHOUT_PMM + +#include "romprefix.S" diff --git a/gpxe/src/arch/i386/prefix/kkpxeprefix.S b/gpxe/src/arch/i386/prefix/kkpxeprefix.S index e0bea0cd..02cc6fee 100644 --- a/gpxe/src/arch/i386/prefix/kkpxeprefix.S +++ b/gpxe/src/arch/i386/prefix/kkpxeprefix.S @@ -3,6 +3,11 @@ ***************************************************************************** */ +FILE_LICENCE ( GPL2_OR_LATER ) + +/* Since we have the whole stack, we can use cached DHCP information */ +REQUEST_OBJECT ( pxeparent_dhcp ) + #define PXELOADER_KEEP_UNDI #define PXELOADER_KEEP_PXE #include "pxeprefix.S" diff --git a/gpxe/src/arch/i386/prefix/kpxeprefix.S b/gpxe/src/arch/i386/prefix/kpxeprefix.S index d708604b..923faccc 100644 --- a/gpxe/src/arch/i386/prefix/kpxeprefix.S +++ b/gpxe/src/arch/i386/prefix/kpxeprefix.S @@ -3,5 +3,7 @@ ***************************************************************************** */ +FILE_LICENCE ( GPL2_OR_LATER ) + #define PXELOADER_KEEP_UNDI #include "pxeprefix.S" diff --git a/gpxe/src/arch/i386/prefix/libprefix.S b/gpxe/src/arch/i386/prefix/libprefix.S index 42189135..9e6ba6f0 100644 --- a/gpxe/src/arch/i386/prefix/libprefix.S +++ b/gpxe/src/arch/i386/prefix/libprefix.S @@ -17,6 +17,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ) + .arch i386 /** diff --git a/gpxe/src/arch/i386/prefix/lkrnprefix.S b/gpxe/src/arch/i386/prefix/lkrnprefix.S index 094263d2..101d0388 100644 --- a/gpxe/src/arch/i386/prefix/lkrnprefix.S +++ b/gpxe/src/arch/i386/prefix/lkrnprefix.S @@ -34,6 +34,8 @@ */ +FILE_LICENCE ( GPL_ANY ) + #define SETUPSECS 4 /* Minimal nr of setup-sectors */ #define PREFIXSIZE ((SETUPSECS+1)*512) #define PREFIXPGH (PREFIXSIZE / 16 ) @@ -92,10 +94,10 @@ setup_sects: root_flags: .word 0 syssize: - .long _filesz_pgh - PREFIXPGH + .long -PREFIXPGH .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "SUBL" + .ascii "ADDL" .long syssize .long 16 .long 0 diff --git a/gpxe/src/arch/i386/prefix/lmelf_dprefix.S b/gpxe/src/arch/i386/prefix/lmelf_dprefix.S deleted file mode 100644 index 93534df5..00000000 --- a/gpxe/src/arch/i386/prefix/lmelf_dprefix.S +++ /dev/null @@ -1,161 +0,0 @@ -#include "elf.h" - .arch sledgehammer - .code32 - .equ FLAT_CODE_SEG,_pmcs-_gdt - .equ FLAT_DATA_SEG,_pmds-_gdt - .equ MSR_K6_EFER, 0xC0000080 - .equ EFER_LME, 0x00000100 - .equ X86_CR4_PAE, 0x00000020 - .equ CR0_PG, 0x80000000 - - .section ".prefix", "ax", @progbits - -#define LOAD_ADDR 0x10000 - - /* ELF Header */ - .globl elf_header -elf_header: -e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 -e_type: .short ET_DYN -e_machine: .short EM_X86_64 -e_version: .long 1 -e_entry: .long LOAD_ADDR + elf_start - elf_header -e_phoff: .long elf_program_header - elf_header -e_shoff: .long 0 -e_flags: .long 0 -e_ehsize: .short elf_header_end - elf_header -e_phentsize: .short ELF32_PHDR_SIZE -e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE -e_shentsize: .short 0 -e_shnum: .short 0 -e_shstrndx: .short 0 -elf_header_end: - -elf_program_header: -phdr1_p_type: .long PT_NOTE -phdr1_p_offset: .long elf_note - elf_header -phdr1_p_vaddr: .long elf_note -phdr1_p_paddr: .long elf_note -phdr1_p_filesz: .long elf_note_end - elf_note -phdr1_p_memsz: .long elf_note_end - elf_note -phdr1_p_flags: .long PF_R | PF_W | PF_X -phdr1_p_align: .long 0 - -/* The decompressor */ -phdr2_p_type: .long PT_LOAD -phdr2_p_offset: .long 0 -phdr2_p_vaddr: .long elf_header -phdr2_p_paddr: .long LOAD_ADDR -phdr2_p_filesz: .long _verbatim_size -phdr2_p_memsz: .long _image_size -phdr2_p_flags: .long PF_R | PF_W | PF_X -phdr2_p_align: .long 16 - -elf_program_header_end: - - .globl elf_note -elf_note: - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_NAME -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz "Etherboot" -4: - - - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_VERSION -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz VERSION -4: - -#if 0 - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_CHECKSUM -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .word 0 -4: -#endif - .balign 4 -elf_note_end: - -elf_start: - .code64 - /* Reload the gdt to something I know */ - leaq _gdt(%rip), %rax - movq %rax, 0x02 + gdtptr(%rip) - lgdt gdtptr(%rip) - - /* Enter 32bit compatibility mode */ - leaq elf_start32(%rip), %rax - movl %eax, 0x00 + elf_start32_addr(%rip) - ljmp *elf_start32_addr(%rip) - -elf_start32: - .code32 - /* Reload the data segments */ - movl $FLAT_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - - /* Disable paging */ - movl %cr0, %eax - andl $~CR0_PG, %eax - movl %eax, %cr0 - - /* Disable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - andl $~EFER_LME, %eax - wrmsr - - /* Disable PAE */ - movl %cr4, %eax - andl $~X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Save the first argument */ - pushl %ebx - jmp _start - -gdtptr: - .word _gdt_end - _gdt -1 - .long _gdt - .long 0 -_gdt: -elf_start32_addr: - .long elf_start32 - .long FLAT_CODE_SEG -_pmcs: - /* 32 bit protected mode code segment, base 0 */ - .word 0xffff,0 - .byte 0,0x9f,0xcf,0 - -_pmds: - /* 32 bit protected mode data segment, base 0 */ - .word 0xffff,0 - .byte 0,0x93,0xcf,0 -_gdt_end: - - - /* Dummy routines to satisfy the build */ - .section ".text16", "ax", @progbits -prefix_exit: - -prefix_exit_end: - .previous diff --git a/gpxe/src/arch/i386/prefix/lmelf_prefix.S b/gpxe/src/arch/i386/prefix/lmelf_prefix.S deleted file mode 100644 index 3c1e7251..00000000 --- a/gpxe/src/arch/i386/prefix/lmelf_prefix.S +++ /dev/null @@ -1,161 +0,0 @@ -#include "elf.h" - .arch sledgehammer - .code32 - .equ FLAT_CODE_SEG,_pmcs-_gdt - .equ FLAT_DATA_SEG,_pmds-_gdt - .equ MSR_K6_EFER, 0xC0000080 - .equ EFER_LME, 0x00000100 - .equ X86_CR4_PAE, 0x00000020 - .equ CR0_PG, 0x80000000 - - .section ".prefix", "ax", @progbits - -#define LOAD_ADDR 0x10000 - - /* ELF Header */ - .globl elf_header -elf_header: -e_ident: .byte 0x7f, 'E', 'L', 'F', 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 -e_type: .short ET_EXEC -e_machine: .short EM_X86_64 -e_version: .long 1 -e_entry: .long LOAD_ADDR + elf_start - elf_header -e_phoff: .long elf_program_header - elf_header -e_shoff: .long 0 -e_flags: .long 0 -e_ehsize: .short elf_header_end - elf_header -e_phentsize: .short ELF32_PHDR_SIZE -e_phnum: .short (elf_program_header_end - elf_program_header)/ELF32_PHDR_SIZE -e_shentsize: .short 0 -e_shnum: .short 0 -e_shstrndx: .short 0 -elf_header_end: - -elf_program_header: -phdr1_p_type: .long PT_NOTE -phdr1_p_offset: .long elf_note - elf_header -phdr1_p_vaddr: .long elf_note -phdr1_p_paddr: .long elf_note -phdr1_p_filesz: .long elf_note_end - elf_note -phdr1_p_memsz: .long elf_note_end - elf_note -phdr1_p_flags: .long PF_R | PF_W | PF_X -phdr1_p_align: .long 0 - -/* The decompressor */ -phdr2_p_type: .long PT_LOAD -phdr2_p_offset: .long 0 -phdr2_p_vaddr: .long elf_header -phdr2_p_paddr: .long LOAD_ADDR -phdr2_p_filesz: .long _verbatim_size -phdr2_p_memsz: .long _image_size -phdr2_p_flags: .long PF_R | PF_W | PF_X -phdr2_p_align: .long 16 - -elf_program_header_end: - - .globl elf_note -elf_note: - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_NAME -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz "Etherboot" -4: - - - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_VERSION -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .asciz VERSION -4: - -#if 0 - .balign 4 - .int 2f - 1f - .int 4f - 3f - .int EIN_PROGRAM_CHECKSUM -1: .asciz "ELFBoot" -2: - .balign 4 -3: - .word 0 -4: -#endif - .balign 4 -elf_note_end: - -elf_start: - .code64 - /* Reload the gdt to something I know */ - leaq _gdt(%rip), %rax - movq %rax, 0x02 + gdtptr(%rip) - lgdt gdtptr(%rip) - - /* Enter 32bit compatibility mode */ - leaq elf_start32(%rip), %rax - movl %eax, 0x00 + elf_start32_addr(%rip) - ljmp *elf_start32_addr(%rip) - -elf_start32: - .code32 - /* Reload the data segments */ - movl $FLAT_DATA_SEG, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %ss - - /* Disable paging */ - movl %cr0, %eax - andl $~CR0_PG, %eax - movl %eax, %cr0 - - /* Disable long mode */ - movl $MSR_K6_EFER, %ecx - rdmsr - andl $~EFER_LME, %eax - wrmsr - - /* Disable PAE */ - movl %cr4, %eax - andl $~X86_CR4_PAE, %eax - movl %eax, %cr4 - - /* Save the first argument */ - pushl %ebx - jmp _start - -gdtptr: - .word _gdt_end - _gdt -1 - .long _gdt - .long 0 -_gdt: -elf_start32_addr: - .long elf_start32 - .long FLAT_CODE_SEG -_pmcs: - /* 32 bit protected mode code segment, base 0 */ - .word 0xffff,0 - .byte 0,0x9f,0xcf,0 - -_pmds: - /* 32 bit protected mode data segment, base 0 */ - .word 0xffff,0 - .byte 0,0x93,0xcf,0 -_gdt_end: - - - /* Dummy routines to satisfy the build */ - .section ".text16", "ax", @progbits -prefix_exit: - -prefix_exit_end: - .previous diff --git a/gpxe/src/arch/i386/prefix/nbiprefix.S b/gpxe/src/arch/i386/prefix/nbiprefix.S index 4fb4acb1..607d80fb 100644 --- a/gpxe/src/arch/i386/prefix/nbiprefix.S +++ b/gpxe/src/arch/i386/prefix/nbiprefix.S @@ -30,16 +30,16 @@ segment_header: .byte 0 .byte 0x04 /* Last segment */ .long 0x00007e00 -imglen: .long _filesz - 512 -memlen: .long _filesz - 512 +imglen: .long -512 +memlen: .long -512 .size segment_header, . - segment_header .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "SUBL" + .ascii "ADDL" .long imglen .long 1 .long 0 - .ascii "SUBL" + .ascii "ADDL" .long memlen .long 1 .long 0 diff --git a/gpxe/src/arch/i386/prefix/pxeprefix.S b/gpxe/src/arch/i386/prefix/pxeprefix.S index b3b7947f..e728c482 100644 --- a/gpxe/src/arch/i386/prefix/pxeprefix.S +++ b/gpxe/src/arch/i386/prefix/pxeprefix.S @@ -1,8 +1,13 @@ +FILE_LICENCE ( GPL2_OR_LATER ) + #define PXENV_UNDI_SHUTDOWN 0x0005 #define PXENV_UNDI_GET_NIC_TYPE 0x0012 +#define PXENV_UNDI_GET_IFACE_INFO 0x0013 #define PXENV_STOP_UNDI 0x0015 #define PXENV_UNLOAD_STACK 0x0070 +#define PXE_HACK_EB54 0x0001 + .text .arch i386 .org 0 @@ -11,6 +16,8 @@ #include <undi.h> #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) ) +#define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) ) +#define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) ) /***************************************************************************** * Entry point: set operating context, print welcome message @@ -105,20 +112,13 @@ have_pxenv: /* Record entry point and UNDI segments */ pushl %es:0x0a(%bx) /* Entry point */ - popl entry_segoff pushw %es:0x24(%bx) /* UNDI code segment */ pushw %es:0x26(%bx) /* UNDI code size */ - popl undi_code_segoff pushw %es:0x20(%bx) /* UNDI data segment */ pushw %es:0x22(%bx) /* UNDI data size */ - popl undi_data_segoff /* Print "PXENV+ at <address>" */ movw $10f, %si - call print_message - call print_segoff - movb $( ',' ), %al - call print_character jmp check_have_stack .section ".prefix.data", "aw", @progbits 10: .asciz " PXENV+ at " @@ -129,19 +129,13 @@ have_ppxe: movw %es, ppxe_segment pushl %es:0x10(%bx) /* Entry point */ - popl entry_segoff pushw %es:0x30(%bx) /* UNDI code segment */ pushw %es:0x36(%bx) /* UNDI code size */ - popl undi_code_segoff pushw %es:0x28(%bx) /* UNDI data segment */ pushw %es:0x2e(%bx) /* UNDI data size */ - popl undi_data_segoff + /* Print "!PXE at <address>" */ movw $10f, %si - call print_message - call print_segoff - movb $( ',' ), %al - call print_character jmp check_have_stack .section ".prefix.data", "aw", @progbits 10: .asciz " !PXE at " @@ -201,6 +195,17 @@ memory_scan_common: ***************************************************************************** */ check_have_stack: + /* Save common values pushed onto the stack */ + popl undi_data_segoff + popl undi_code_segoff + popl entry_segoff + + /* Print have !PXE/PXENV+ message; structure pointer in %es:%bx */ + call print_message + call print_segoff + movb $( ',' ), %al + call print_character + /* Check for entry point */ movl entry_segoff, %eax testl %eax, %eax @@ -309,8 +314,6 @@ pci_physical_device: movw $10f, %si call print_message call print_pci_busdevfn - movb $0x0a, %al - call print_character jmp 99f .section ".prefix.data", "aw", @progbits 10: .asciz " UNDI device is PCI " @@ -321,12 +324,47 @@ no_physical_device: movw $10f, %si call print_message .section ".prefix.data", "aw", @progbits -10: .asciz " Unable to determine UNDI physical device\n" +10: .asciz " Unable to determine UNDI physical device" .previous 99: /***************************************************************************** + * Determine interface type + ***************************************************************************** + */ +get_iface_type: + /* Issue PXENV_UNDI_GET_IFACE_INFO */ + movw $PXENV_UNDI_GET_IFACE_INFO, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp 99f +1: /* Print interface type */ + movw $10f, %si + call print_message + leaw ( pxe_parameter_structure + 0x02 ), %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz ", type " + .previous + /* Check for "Etherboot" interface type */ + cmpl $EB_MAGIC_1, ( pxe_parameter_structure + 0x02 ) + jne 99f + cmpl $EB_MAGIC_2, ( pxe_parameter_structure + 0x06 ) + jne 99f + movw $10f, %si + call print_message + .section ".prefix.data", "aw", @progbits +10: .asciz " (workaround enabled)" + .previous + /* Flag Etherboot workarounds as required */ + orw $PXE_HACK_EB54, pxe_hacks + +99: movb $0x0a, %al + call print_character + +/***************************************************************************** * Leave NIC in a safe state ***************************************************************************** */ @@ -339,6 +377,14 @@ shutdown_nic: call print_pxe_error 1: unload_base_code: + /* Etherboot treats PXENV_UNLOAD_STACK as PXENV_STOP_UNDI, so + * we must not issue this call if the underlying stack is + * Etherboot and we were not intending to issue a PXENV_STOP_UNDI. + */ +#ifdef PXELOADER_KEEP_UNDI + testw $PXE_HACK_EB54, pxe_hacks + jnz 99f +#endif /* PXELOADER_KEEP_UNDI */ /* Issue PXENV_UNLOAD_STACK */ movw $PXENV_UNLOAD_STACK, %bx call pxe_call @@ -551,7 +597,9 @@ pxe_call: testw %ax, %ax jz 1f stc -1: /* Restore registers and return */ +1: /* Clear direction flag, for the sake of sanity */ + cld + /* Restore registers and return */ popw %es popw %di ret @@ -595,7 +643,7 @@ print_pxe_error: pxe_esp: .long 0 pxe_ss: .word 0 -pxe_parameter_structure: .fill 20 +pxe_parameter_structure: .fill 64 undi_code_segoff: undi_code_size: .word 0 @@ -605,6 +653,8 @@ undi_data_segoff: undi_data_size: .word 0 undi_data_segment: .word 0 +pxe_hacks: .word 0 + /* The following fields are part of a struct undi_device */ undi_device: @@ -668,6 +718,13 @@ run_gpxe: lret .section ".text16", "ax", @progbits 1: + /* Update the exit hook */ + movw %cs,pxe_exit_hook+2 + push %ax + mov $2f,%ax + mov %ax,pxe_exit_hook + pop %ax + /* Run main program */ pushl $main pushw %cs @@ -681,7 +738,10 @@ run_gpxe: movw %di, %ss movl %ebp, %esp - /* Check PXE stack magic */ + /* Jump to hook if applicable */ + ljmpw *pxe_exit_hook + +2: /* Check PXE stack magic */ popl %eax cmpl $STACK_MAGIC, %eax jne 1f diff --git a/gpxe/src/arch/i386/prefix/romprefix.S b/gpxe/src/arch/i386/prefix/romprefix.S index 7d532375..02e54976 100644 --- a/gpxe/src/arch/i386/prefix/romprefix.S +++ b/gpxe/src/arch/i386/prefix/romprefix.S @@ -6,6 +6,8 @@ * table so using a noticeable amount of stack space is a no-no. */ +FILE_LICENCE ( GPL2_OR_LATER ) + #include <config/general.h> #define PNP_SIGNATURE ( '$' + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) ) @@ -23,6 +25,19 @@ */ #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 ) +/* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix) + * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix). + * The latter is not as widely supported, but allows the use of large ROMs + * on some systems with crowded option ROM space. + */ + +#ifdef LOAD_ROM_FROM_PCI +#define ROM_SIZE_VALUE _prefix_filesz_sect /* Amount to load in BIOS */ +#else +#define ROM_SIZE_VALUE 0 /* Load amount (before compr. fixup) */ +#endif + + .text .code16 .arch i386 @@ -31,10 +46,12 @@ .org 0x00 romheader: .word 0xAA55 /* BIOS extension signature */ -romheader_size: .byte _filesz_sect /* Size in 512-byte blocks */ +romheader_size: .byte ROM_SIZE_VALUE /* Size in 512-byte blocks */ jmp init /* Initialisation vector */ checksum: - .byte 0 + .byte 0, 0 +real_size: + .word 0 .org 0x16 .word undiheader .org 0x18 @@ -42,12 +59,18 @@ checksum: .org 0x1a .word pnpheader .size romheader, . - romheader - + .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "SUBB" +#ifndef LOAD_ROM_FROM_PCI + .ascii "ADDB" .long romheader_size .long 512 .long 0 +#endif + .ascii "ADDB" + .long real_size + .long 512 + .long 0 .previous pciheader: @@ -59,27 +82,29 @@ pciheader: .byte 0x03 /* PCI data structure revision */ .byte 0x02, 0x00, 0x00 /* Class code */ pciheader_image_length: - .word _filesz_sect /* Image length */ + .word ROM_SIZE_VALUE /* Image length */ .word 0x0001 /* Revision level */ .byte 0x00 /* Code type */ .byte 0x80 /* Last image indicator */ pciheader_runtime_length: - .word _filesz_sect /* Maximum run-time image length */ + .word ROM_SIZE_VALUE /* Maximum run-time image length */ .word 0x0000 /* Configuration utility code header */ .word 0x0000 /* DMTF CLP entry point */ .equ pciheader_len, . - pciheader .size pciheader, . - pciheader - + +#ifndef LOAD_ROM_FROM_PCI .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */ - .ascii "SUBW" + .ascii "ADDW" .long pciheader_image_length .long 512 .long 0 - .ascii "SUBW" + .ascii "ADDW" .long pciheader_runtime_length .long 512 .long 0 .previous +#endif pnpheader: .ascii "$PnP" /* Signature */ @@ -124,6 +149,7 @@ prodstr_pci_id: .size prodstr, . - prodstr .globl undiheader + .weak undiloader undiheader: .ascii "UNDI" /* Signature */ .byte undiheader_len /* Length of structure */ @@ -172,6 +198,11 @@ init: call print_message call print_pci_busdevfn +#ifdef LOAD_ROM_FROM_PCI + /* Save PCI bus:dev.fn for later use */ + movw %ax, pci_busdevfn +#endif + /* Fill in product name string, if possible */ movw $prodstr_pci_id, %di call print_pci_busdevfn @@ -196,6 +227,9 @@ init: jne no_pci3 testb %ah, %ah jnz no_pci3 +#ifdef LOAD_ROM_FROM_PCI + incb pcibios_present +#endif movw $init_message_pci, %si xorw %di, %di call print_message @@ -236,24 +270,37 @@ no_pci3: popl %edx popl %ebx - /* Check for PnP BIOS */ - testw $0x0f, %bx /* PnP signature must be aligned - bochs */ - jnz no_bbs /* uses unalignment to indicate 'fake' PnP. */ - cmpl $PNP_SIGNATURE, %es:0(%bx) - jne no_bbs + /* Check for PnP BIOS. Although %es:di should point to the + * PnP BIOS signature on entry, some BIOSes fail to do this. + */ + movw $( 0xf000 - 1 ), %bx +pnp_scan: + incw %bx + jz no_pnp + movw %bx, %es + cmpl $PNP_SIGNATURE, %es:0 + jne pnp_scan + xorw %dx, %dx + xorw %si, %si + movzbw %es:5, %cx +1: es lodsb + addb %al, %dl + loop 1b + jnz pnp_scan /* Is PnP: print PnP message */ movw $init_message_pnp, %si xorw %di, %di call print_message /* Check for BBS */ - pushw %es:0x1b(%bx) /* Real-mode data segment */ + pushw %es:0x1b /* Real-mode data segment */ pushw %ds /* &(bbs_version) */ pushw $bbs_version pushw $PNP_GET_BBS_VERSION - lcall *%es:0xd(%bx) + lcall *%es:0xd addw $8, %sp testw %ax, %ax je got_bbs +no_pnp: /* Not PnP-compliant - therefore cannot be BBS-compliant */ no_bbs: /* Not BBS-compliant - must hook INT 19 */ movw $init_message_int19, %si xorw %di, %di @@ -294,7 +341,7 @@ pmm_scan: /* We have PMM and so a 1kB stack: preserve upper register halves */ pushal /* Calculate required allocation size in %esi */ - movzbl romheader_size, %eax + movzwl real_size, %eax shll $9, %eax addl $_textdata_memsz, %eax orw $0xffff, %ax /* Ensure allocation size is at least 64kB */ @@ -336,6 +383,7 @@ got_pmm: /* PMM allocation succeeded */ call print_character movw %si, %ax call print_hex_byte +pmm_copy: /* Copy ROM to PMM block */ xorw %ax, %ax movw %ax, %es @@ -347,11 +395,43 @@ got_pmm: /* PMM allocation succeeded */ movl %edi, decompress_to /* Shrink ROM */ movb $_prefix_memsz_sect, romheader_size +#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI) + jmp pmm_done +pmm_fail: + /* Print marker and copy ourselves to high memory */ + movl $HIGHMEM_LOADPOINT, image_source + xorw %di, %di + movb $( '!' ), %al + call print_character + jmp pmm_copy +pmm_done: +#else pmm_fail: +#endif /* Restore upper register halves */ popal +#if defined(LOAD_ROM_FROM_PCI) + call load_from_pci + jc load_err + jmp load_ok no_pmm: + /* Cannot continue without PMM - print error message */ + xorw %di, %di + movw $init_message_no_pmm, %si + call print_message +load_err: + /* Wait for five seconds to let user see message */ + movw $90, %cx +1: call wait_for_tick + loop 1b + /* Mark environment as invalid and return */ + movl $0, decompress_to + jmp out +load_ok: +#else +no_pmm: +#endif /* Update checksum */ xorw %bx, %bx xorw %si, %si @@ -396,14 +476,14 @@ no_pmm: movw $init_message_done, %si call print_message popf - jnz 2f + jnz out /* Ctrl-B was pressed: invoke gPXE. The keypress will be * picked up by the initial shell prompt, and we will drop * into a shell. */ pushw %cs call exec -2: +out: /* Restore registers */ popw %gs popw %fs @@ -450,6 +530,11 @@ init_message_bbs: init_message_pmm: .asciz " PMM" .size init_message_pmm, . - init_message_pmm +#ifdef LOAD_ROM_FROM_PCI +init_message_no_pmm: + .asciz "\nPMM required but not present!\n" + .size init_message_no_pmm, . - init_message_no_pmm +#endif init_message_int19: .asciz " INT19" .size init_message_int19, . - init_message_int19 @@ -467,6 +552,7 @@ init_message_done: * * May be either within option ROM space, or within PMM-allocated block. */ + .globl image_source image_source: .long 0 .size image_source, . - image_source @@ -474,11 +560,32 @@ image_source: /* Temporary decompression area * * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block. + * If a PCI ROM load fails, this will be set to zero. */ + .globl decompress_to decompress_to: .long HIGHMEM_LOADPOINT .size decompress_to, . - decompress_to +#ifdef LOAD_ROM_FROM_PCI + +/* Set if the PCI BIOS is present, even <3.0 */ +pcibios_present: + .byte 0 + .byte 0 /* for alignment */ + .size pcibios_present, . - pcibios_present + +/* PCI bus:device.function word + * + * Filled in by init in the .xrom case, so the remainder of the ROM + * can be located. + */ +pci_busdevfn: + .word 0 + .size pci_busdevfn, . - pci_busdevfn + +#endif + /* BBS version * * Filled in by BBS BIOS. We ignore the value. @@ -497,6 +604,289 @@ bev_entry: lret .size bev_entry, . - bev_entry + +#ifdef LOAD_ROM_FROM_PCI + +#define PCI_ROM_ADDRESS 0x30 /* Bits 31:11 address, 10:1 reserved */ +#define PCI_ROM_ADDRESS_ENABLE 0x00000001 +#define PCI_ROM_ADDRESS_MASK 0xfffff800 + +#define PCIBIOS_READ_WORD 0xb109 +#define PCIBIOS_READ_DWORD 0xb10a +#define PCIBIOS_WRITE_WORD 0xb10c +#define PCIBIOS_WRITE_DWORD 0xb10d + +/* Determine size of PCI BAR + * + * %bx : PCI bus:dev.fn to probe + * %di : Address of BAR to find size of + * %edx : Mask of address bits within BAR + * + * %ecx : Size for a memory resource, + * 1 for an I/O resource (bit 0 set). + * CF : Set on error or nonexistent device (all-ones read) + * + * All other registers saved. + */ +pci_bar_size: + /* Save registers */ + pushw %ax + pushl %esi + pushl %edx + + /* Read current BAR value */ + movw $PCIBIOS_READ_DWORD, %ax + int $0x1a + + /* Check for device existence and save it */ + testb $1, %cl /* I/O bit? */ + jz 1f + andl $1, %ecx /* If so, exit with %ecx = 1 */ + jmp 99f +1: notl %ecx + testl %ecx, %ecx /* Set ZF iff %ecx was all-ones */ + notl %ecx + jnz 1f + stc /* All ones - exit with CF set */ + jmp 99f +1: movl %ecx, %esi /* Save in %esi */ + + /* Write all ones to BAR */ + movl %edx, %ecx + movw $PCIBIOS_WRITE_DWORD, %ax + int $0x1a + + /* Read back BAR */ + movw $PCIBIOS_READ_DWORD, %ax + int $0x1a + + /* Find decode size from least set bit in mask BAR */ + bsfl %ecx, %ecx /* Find least set bit, log2(decode size) */ + jz 1f /* Mask BAR should not be zero */ + xorl %edx, %edx + incl %edx + shll %cl, %edx /* %edx = decode size */ + jmp 2f +1: xorl %edx, %edx /* Return zero size for mask BAR zero */ + + /* Restore old BAR value */ +2: movl %esi, %ecx + movw $PCIBIOS_WRITE_DWORD, %ax + int $0x1a + + movl %edx, %ecx /* Return size in %ecx */ + + /* Restore registers and return */ +99: popl %edx + popl %esi + popw %ax + ret + + .size pci_bar_size, . - pci_bar_size + +/* PCI ROM loader + * + * Called from init in the .xrom case to load the non-prefix code + * using the PCI ROM BAR. + * + * Returns with carry flag set on error. All registers saved. + */ +load_from_pci: + /* + * Use PCI BIOS access to config space. The calls take + * + * %ah : 0xb1 %al : function + * %bx : bus/dev/fn + * %di : config space address + * %ecx : value to write (for writes) + * + * %ecx : value read (for reads) + * %ah : return code + * CF : error indication + * + * All registers not used for return are preserved. + */ + + /* Save registers and set up %es for big real mode */ + pushal + pushw %es + xorw %ax, %ax + movw %ax, %es + + /* Check PCI BIOS presence */ + cmpb $0, pcibios_present + jz err_pcibios + + /* Load existing PCI ROM BAR */ + movw $PCIBIOS_READ_DWORD, %ax + movw pci_busdevfn, %bx + movw $PCI_ROM_ADDRESS, %di + int $0x1a + + /* Maybe it's already enabled? */ + testb $PCI_ROM_ADDRESS_ENABLE, %cl + jz 1f + movb $1, %dl /* Flag indicating no deinit required */ + movl %ecx, %ebp + jmp check_rom + + /* Determine PCI BAR decode size */ +1: movl $PCI_ROM_ADDRESS_MASK, %edx + call pci_bar_size /* Returns decode size in %ecx */ + jc err_size_insane /* CF => no ROM BAR, %ecx == ffffffff */ + + /* Check sanity of decode size */ + xorl %eax, %eax + movw real_size, %ax + shll $9, %eax /* %eax = ROM size */ + cmpl %ecx, %eax + ja err_size_insane /* Insane if decode size < ROM size */ + cmpl $0x100000, %ecx + jae err_size_insane /* Insane if decode size >= 1MB */ + + /* Find a place to map the BAR + * In theory we should examine e820 and all PCI BARs to find a + * free region. However, we run at POST when e820 may not be + * available, and memory reads of an unmapped location are + * de facto standardized to return all-ones. Thus, we can get + * away with searching high memory (0xf0000000 and up) on + * multiples of the ROM BAR decode size for a sufficiently + * large all-ones region. + */ + movl %ecx, %edx /* Save ROM BAR size in %edx */ + movl $0xf0000000, %ebp + xorl %eax, %eax + notl %eax /* %eax = all ones */ +bar_search: + movl %ebp, %edi + movl %edx, %ecx + shrl $2, %ecx + addr32 repe scasl /* Scan %es:edi for anything not all-ones */ + jz bar_found + addl %edx, %ebp + testl $0x80000000, %ebp + jz err_no_bar + jmp bar_search + +bar_found: + movl %edi, %ebp + /* Save current BAR value on stack to restore later */ + movw $PCIBIOS_READ_DWORD, %ax + movw $PCI_ROM_ADDRESS, %di + int $0x1a + pushl %ecx + + /* Map the ROM */ + movw $PCIBIOS_WRITE_DWORD, %ax + movl %ebp, %ecx + orb $PCI_ROM_ADDRESS_ENABLE, %cl + int $0x1a + + xorb %dl, %dl /* %dl = 0 : ROM was not already mapped */ +check_rom: + /* Check and copy ROM - enter with %dl set to skip unmapping, + * %ebp set to mapped ROM BAR address. + * We check up to prodstr_separator for equality, since anything past + * that may have been modified. Since our check includes the checksum + * byte over the whole ROM stub, that should be sufficient. + */ + xorb %dh, %dh /* %dh = 0 : ROM did not fail integrity check */ + + /* Verify ROM integrity */ + xorl %esi, %esi + movl %ebp, %edi + movl $prodstr_separator, %ecx + addr32 repe cmpsb + jz copy_rom + incb %dh /* ROM failed integrity check */ + movl %ecx, %ebp /* Save number of bytes left */ + jmp skip_load + +copy_rom: + /* Print BAR address and indicate whether we mapped it ourselves */ + movb $( ' ' ), %al + xorw %di, %di + call print_character + movl %ebp, %eax + call print_hex_dword + movb $( '-' ), %al /* '-' for self-mapped */ + subb %dl, %al + subb %dl, %al /* '+' = '-' - 2 for BIOS-mapped */ + call print_character + + /* Copy ROM at %ebp to PMM or highmem block */ + movl %ebp, %esi + movl image_source, %edi + movzwl real_size, %ecx + shll $9, %ecx + addr32 es rep movsb + movl %edi, decompress_to +skip_load: + testb %dl, %dl /* Was ROM already mapped? */ + jnz skip_unmap + + /* Unmap the ROM by restoring old ROM BAR */ + movw $PCIBIOS_WRITE_DWORD, %ax + movw $PCI_ROM_ADDRESS, %di + popl %ecx + int $0x1a + +skip_unmap: + /* Error handling */ + testb %dh, %dh + jnz err_rom_invalid + clc + jmp 99f + +err_pcibios: /* No PCI BIOS available */ + movw $load_message_no_pcibios, %si + xorl %eax, %eax /* "error code" is zero */ + jmp 1f +err_size_insane: /* BAR has size (%ecx) that is insane */ + movw $load_message_size_insane, %si + movl %ecx, %eax + jmp 1f +err_no_bar: /* No space of sufficient size (%edx) found */ + movw $load_message_no_bar, %si + movl %edx, %eax + jmp 1f +err_rom_invalid: /* Loaded ROM does not match (%ebp bytes left) */ + movw $load_message_rom_invalid, %si + movzbl romheader_size, %eax + shll $9, %eax + subl %ebp, %eax + decl %eax /* %eax is now byte index of failure */ + +1: /* Error handler - print message at %si and dword in %eax */ + xorw %di, %di + call print_message + call print_hex_dword + stc +99: popw %es + popal + ret + + .size load_from_pci, . - load_from_pci + +load_message_no_pcibios: + .asciz "\nNo PCI BIOS found! " + .size load_message_no_pcibios, . - load_message_no_pcibios + +load_message_size_insane: + .asciz "\nROM resource has invalid size " + .size load_message_size_insane, . - load_message_size_insane + +load_message_no_bar: + .asciz "\nNo memory hole of sufficient size " + .size load_message_no_bar, . - load_message_no_bar + +load_message_rom_invalid: + .asciz "\nLoaded ROM is invalid at " + .size load_message_rom_invalid, . - load_message_rom_invalid + +#endif /* LOAD_ROM_FROM_PCI */ + + /* INT19 entry point * * Called via the hooked INT 19 if we detected a non-PnP BIOS. We @@ -557,6 +947,14 @@ exec: /* Set %ds = %cs */ pushw %cs popw %ds +#ifdef LOAD_ROM_FROM_PCI + /* Don't execute if load was invalid */ + cmpl $0, decompress_to + jne 1f + lret +1: +#endif + /* Print message as soon as possible */ movw $prodstr, %si xorw %di, %di @@ -616,50 +1014,6 @@ exec_message: .asciz " starting execution\n" .size exec_message, . - exec_message -/* UNDI loader - * - * Called by an external program to load our PXE stack. - */ -undiloader: - /* Save registers */ - pushl %esi - pushl %edi - pushw %ds - pushw %es - pushw %bx - /* ROM segment address to %ds */ - pushw %cs - popw %ds - /* UNDI loader parameter structure address into %es:%di */ - movw %sp, %bx - movw %ss:18(%bx), %di - movw %ss:20(%bx), %es - /* Install to specified real-mode addresses */ - pushw %di - movw %es:12(%di), %bx - movw %es:14(%di), %ax - movl image_source, %esi - movl decompress_to, %edi - call install_prealloc - popw %di - /* Call UNDI loader C code */ - pushl $pxe_loader_call - pushw %cs - pushw $1f - pushw %ax - pushw $prot_call - lret -1: popw %bx /* discard */ - popw %bx /* discard */ - /* Restore registers and return */ - popw %bx - popw %es - popw %ds - popl %edi - popl %esi - lret - .size undiloader, . - undiloader - /* Wait for key press specified by %bl (masked by %bh) * * Used by init and INT19 code when prompting user. If the specified diff --git a/gpxe/src/arch/i386/prefix/undiloader.S b/gpxe/src/arch/i386/prefix/undiloader.S new file mode 100644 index 00000000..36c1bef3 --- /dev/null +++ b/gpxe/src/arch/i386/prefix/undiloader.S @@ -0,0 +1,49 @@ + .text + .code16 + .arch i386 + .section ".prefix", "ax", @progbits + +/* UNDI loader + * + * Called by an external program to load our PXE stack. + */ + .globl undiloader +undiloader: + /* Save registers */ + pushl %esi + pushl %edi + pushw %ds + pushw %es + pushw %bx + /* ROM segment address to %ds */ + pushw %cs + popw %ds + /* UNDI loader parameter structure address into %es:%di */ + movw %sp, %bx + movw %ss:18(%bx), %di + movw %ss:20(%bx), %es + /* Install to specified real-mode addresses */ + pushw %di + movw %es:12(%di), %bx + movw %es:14(%di), %ax + movl image_source, %esi + movl decompress_to, %edi + call install_prealloc + popw %di + /* Call UNDI loader C code */ + pushl $pxe_loader_call + pushw %cs + pushw $1f + pushw %ax + pushw $prot_call + lret +1: popw %bx /* discard */ + popw %bx /* discard */ + /* Restore registers and return */ + popw %bx + popw %es + popw %ds + popl %edi + popl %esi + lret + .size undiloader, . - undiloader diff --git a/gpxe/src/arch/i386/prefix/unnrv2b.S b/gpxe/src/arch/i386/prefix/unnrv2b.S index 70167a14..f5724c13 100644 --- a/gpxe/src/arch/i386/prefix/unnrv2b.S +++ b/gpxe/src/arch/i386/prefix/unnrv2b.S @@ -20,6 +20,8 @@ * Michael Brown 9 Mar 2005 */ +FILE_LICENCE ( GPL2_OR_LATER ) + /**************************************************************************** * This file provides the decompress() and decompress16() functions * which can be called in order to decompress an image compressed with diff --git a/gpxe/src/arch/i386/prefix/unnrv2b16.S b/gpxe/src/arch/i386/prefix/unnrv2b16.S new file mode 100644 index 00000000..b24c2846 --- /dev/null +++ b/gpxe/src/arch/i386/prefix/unnrv2b16.S @@ -0,0 +1,9 @@ +/* + * 16-bit version of the decompressor + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define CODE16 +#include "unnrv2b.S" diff --git a/gpxe/src/arch/i386/prefix/xromprefix.S b/gpxe/src/arch/i386/prefix/xromprefix.S new file mode 100644 index 00000000..d7c861f5 --- /dev/null +++ b/gpxe/src/arch/i386/prefix/xromprefix.S @@ -0,0 +1,9 @@ +/* + * ROM prefix that loads the bulk of the ROM using direct PCI accesses, + * so as not to take up much option ROM space on PCI <3.0 systems. + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +#define LOAD_ROM_FROM_PCI +#include "romprefix.S" diff --git a/gpxe/src/arch/i386/scripts/i386-kir.lds b/gpxe/src/arch/i386/scripts/i386-kir.lds index b213c605..c19480f0 100644 --- a/gpxe/src/arch/i386/scripts/i386-kir.lds +++ b/gpxe/src/arch/i386/scripts/i386-kir.lds @@ -130,6 +130,7 @@ SECTIONS { /DISCARD/ : { *(.comment) *(.note) + *(.discard) } /* diff --git a/gpxe/src/arch/i386/scripts/i386.lds b/gpxe/src/arch/i386/scripts/i386.lds index 8a0c6733..33c75f90 100644 --- a/gpxe/src/arch/i386/scripts/i386.lds +++ b/gpxe/src/arch/i386/scripts/i386.lds @@ -152,6 +152,7 @@ SECTIONS { *(.eh_frame.*) *(.rel) *(.rel.*) + *(.discard) } /* @@ -193,17 +194,9 @@ SECTIONS { * Values calculated to save code from doing it * */ + _prefix_filesz_sect = ( ( _prefix_filesz + 511 ) / 512 ); _prefix_memsz_pgh = ( ( _prefix_memsz + 15 ) / 16 ); _prefix_memsz_sect = ( ( _prefix_memsz + 511 ) / 512 ); _text16_memsz_pgh = ( ( _text16_memsz + 15 ) / 16 ); _data16_memsz_pgh = ( ( _data16_memsz + 15 ) / 16 ); - - /* - * File size in paragraphs and sectors. Note that wherever the - * _filesz variables are used, there must be a corresponding - * .zinfo.fixup section. - * - */ - _filesz_pgh = ( ( _filesz + 15 ) / 16 ); - _filesz_sect = ( ( _filesz + 511 ) / 512 ); } diff --git a/gpxe/src/arch/i386/transitions/libkir.S b/gpxe/src/arch/i386/transitions/libkir.S index 1023ddd0..1176fcce 100644 --- a/gpxe/src/arch/i386/transitions/libkir.S +++ b/gpxe/src/arch/i386/transitions/libkir.S @@ -5,6 +5,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ) + /**************************************************************************** * This file defines libkir: an interface between external and * internal environments when -DKEEP_IT_REAL is used, so that both diff --git a/gpxe/src/arch/i386/transitions/librm.S b/gpxe/src/arch/i386/transitions/librm.S index 8cf1f7f5..cb27ef35 100755..100644 --- a/gpxe/src/arch/i386/transitions/librm.S +++ b/gpxe/src/arch/i386/transitions/librm.S @@ -5,6 +5,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ) + /* Drag in local definitions */ #include "librm.h" diff --git a/gpxe/src/arch/i386/transitions/librm_mgmt.c b/gpxe/src/arch/i386/transitions/librm_mgmt.c index 50569f8e..f00be811 100755..100644 --- a/gpxe/src/arch/i386/transitions/librm_mgmt.c +++ b/gpxe/src/arch/i386/transitions/librm_mgmt.c @@ -5,6 +5,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <realmode.h> diff --git a/gpxe/src/arch/x86/Makefile b/gpxe/src/arch/x86/Makefile index a7c4bc0e..f5f67ac7 100644 --- a/gpxe/src/arch/x86/Makefile +++ b/gpxe/src/arch/x86/Makefile @@ -1,6 +1,6 @@ # Include common x86 headers # -CFLAGS += -Iarch/x86/include +INCDIRS += arch/x86/include # x86-specific directories containing source files # diff --git a/gpxe/src/arch/x86/core/pcidirect.c b/gpxe/src/arch/x86/core/pcidirect.c index db17215e..2c61d9ca 100644 --- a/gpxe/src/arch/x86/core/pcidirect.c +++ b/gpxe/src/arch/x86/core/pcidirect.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/io.h> #include <gpxe/pci.h> diff --git a/gpxe/src/arch/x86/core/x86_string.c b/gpxe/src/arch/x86/core/x86_string.c index c0224c7a..5838ebac 100644 --- a/gpxe/src/arch/x86/core/x86_string.c +++ b/gpxe/src/arch/x86/core/x86_string.c @@ -22,6 +22,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> /** diff --git a/gpxe/src/arch/x86/include/bits/pci_io.h b/gpxe/src/arch/x86/include/bits/pci_io.h index 0fbb439d..f6efcdac 100644 --- a/gpxe/src/arch/x86/include/bits/pci_io.h +++ b/gpxe/src/arch/x86/include/bits/pci_io.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/pcibios.h> #include <gpxe/pcidirect.h> diff --git a/gpxe/src/arch/x86/include/bits/string.h b/gpxe/src/arch/x86/include/bits/string.h index 42ddeddf..a68868ac 100644 --- a/gpxe/src/arch/x86/include/bits/string.h +++ b/gpxe/src/arch/x86/include/bits/string.h @@ -21,6 +21,8 @@ * consider these trivial functions to be PD. */ +FILE_LICENCE ( PUBLIC_DOMAIN ); + #define __HAVE_ARCH_MEMCPY extern void * __memcpy ( void *dest, const void *src, size_t len ); diff --git a/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h b/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h index 91424c54..833c922c 100644 --- a/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h +++ b/gpxe/src/arch/x86/include/gpxe/efi/efix86_nap.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef NAP_EFIX86 #define NAP_PREFIX_efix86 #else diff --git a/gpxe/src/arch/x86/include/gpxe/pcibios.h b/gpxe/src/arch/x86/include/gpxe/pcibios.h index b86f5abd..93a6eb8a 100644 --- a/gpxe/src/arch/x86/include/gpxe/pcibios.h +++ b/gpxe/src/arch/x86/include/gpxe/pcibios.h @@ -9,6 +9,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #ifdef PCIAPI_PCBIOS #define PCIAPI_PREFIX_pcbios #else diff --git a/gpxe/src/arch/x86/include/gpxe/pcidirect.h b/gpxe/src/arch/x86/include/gpxe/pcidirect.h index fe433c6f..8b705fb2 100644 --- a/gpxe/src/arch/x86/include/gpxe/pcidirect.h +++ b/gpxe/src/arch/x86/include/gpxe/pcidirect.h @@ -1,6 +1,8 @@ #ifndef _PCIDIRECT_H #define _PCIDIRECT_H +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <gpxe/io.h> diff --git a/gpxe/src/arch/x86/interface/efi/efix86_nap.c b/gpxe/src/arch/x86/interface/efi/efix86_nap.c index 45e99a68..89a4e3ba 100644 --- a/gpxe/src/arch/x86/interface/efi/efix86_nap.c +++ b/gpxe/src/arch/x86/interface/efi/efix86_nap.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/nap.h> #include <gpxe/efi/efi.h> diff --git a/gpxe/src/arch/x86/prefix/efidrvprefix.c b/gpxe/src/arch/x86/prefix/efidrvprefix.c index 5f631588..36d56508 100644 --- a/gpxe/src/arch/x86/prefix/efidrvprefix.c +++ b/gpxe/src/arch/x86/prefix/efidrvprefix.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <gpxe/init.h> #include <gpxe/efi/efi.h> diff --git a/gpxe/src/arch/x86/prefix/efiprefix.c b/gpxe/src/arch/x86/prefix/efiprefix.c index b05b744d..4cc9e04a 100644 --- a/gpxe/src/arch/x86/prefix/efiprefix.c +++ b/gpxe/src/arch/x86/prefix/efiprefix.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <gpxe/efi/efi.h> diff --git a/gpxe/src/arch/x86/scripts/efi.lds b/gpxe/src/arch/x86/scripts/efi.lds index aac31056..7525b81b 100644 --- a/gpxe/src/arch/x86/scripts/efi.lds +++ b/gpxe/src/arch/x86/scripts/efi.lds @@ -101,5 +101,6 @@ SECTIONS { *(.eh_frame.*) *(.rel) *(.rel.*) + *(.discard) } } diff --git a/gpxe/src/arch/x86_64/include/bits/stdint.h b/gpxe/src/arch/x86_64/include/bits/stdint.h index 23bae9c4..9eb72e9c 100644 --- a/gpxe/src/arch/x86_64/include/bits/stdint.h +++ b/gpxe/src/arch/x86_64/include/bits/stdint.h @@ -1,7 +1,7 @@ #ifndef _BITS_STDINT_H #define _BITS_STDINT_H -typedef unsigned long size_t; +typedef __SIZE_TYPE__ size_t; typedef signed long ssize_t; typedef signed long off_t; diff --git a/gpxe/src/core/config.c b/gpxe/src/config/config.c index bd0d66ec..a6e76220 100644 --- a/gpxe/src/core/config.c +++ b/gpxe/src/config/config.c @@ -5,9 +5,29 @@ * your option) any later version. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/general.h> #include <config/console.h> +/** @file + * + * Configuration options + * + * This file contains macros that pull various objects into the link + * based on definitions in configuration header files. Ideally it + * should be the only place in gPXE where one might need to use #ifdef + * for compile-time options. + * + * In the fairly common case where an object should only be considered + * for inclusion if the subsystem it depends on is present, its + * configuration macros should be placed in a file named + * <tt>config_<i>subsystem</i>.c</tt>, where @e subsystem is the + * object basename of the main source file for that subsystem. The + * build system will pull in that file if @c subsystem.c is included + * in the final gPXE executable built. + */ + /* * Build ID string calculations * @@ -72,15 +92,23 @@ REQUIRE_OBJECT ( ipv4 ); #endif /* + * Drag in all requested PXE support + * + */ +#ifdef PXE_MENU +REQUIRE_OBJECT ( pxemenu ); +#endif +#ifdef PXE_STACK +REQUIRE_OBJECT ( pxe_call ); +#endif + +/* * Drag in all requested download protocols * */ #ifdef DOWNLOAD_PROTO_TFTP REQUIRE_OBJECT ( tftp ); #endif -#ifdef DOWNLOAD_PROTO_NFS -REQUIRE_OBJECT ( nfs ); -#endif #ifdef DOWNLOAD_PROTO_HTTP REQUIRE_OBJECT ( http ); #endif @@ -107,6 +135,9 @@ REQUIRE_OBJECT ( iscsiboot ); #ifdef SANBOOT_PROTO_AOE REQUIRE_OBJECT ( aoeboot ); #endif +#ifdef SANBOOT_PROTO_IB_SRP +REQUIRE_OBJECT ( ib_srpboot ); +#endif /* * Drag in all requested resolvers @@ -115,9 +146,6 @@ REQUIRE_OBJECT ( aoeboot ); #ifdef DNS_RESOLVER REQUIRE_OBJECT ( dns ); #endif -#ifdef NMB_RESOLVER -REQUIRE_OBJECT ( nmb ); -#endif /* * Drag in all requested image formats @@ -181,6 +209,7 @@ REQUIRE_OBJECT ( config_cmd ); #ifdef IFMGMT_CMD REQUIRE_OBJECT ( ifmgmt_cmd ); #endif +/* IWMGMT_CMD is brought in by net80211.c if requested */ #ifdef ROUTE_CMD REQUIRE_OBJECT ( route_cmd ); #endif @@ -196,6 +225,15 @@ REQUIRE_OBJECT ( sanboot_cmd ); #ifdef LOGIN_CMD REQUIRE_OBJECT ( login_cmd ); #endif +#ifdef TIME_CMD +REQUIRE_OBJECT ( time_cmd ); +#endif +#ifdef DIGEST_CMD +REQUIRE_OBJECT ( digest_cmd ); +#endif +#ifdef PXE_CMD +REQUIRE_OBJECT ( pxe_cmd ); +#endif /* * Drag in miscellaneous objects diff --git a/gpxe/src/config/config_net80211.c b/gpxe/src/config/config_net80211.c new file mode 100644 index 00000000..b33c363b --- /dev/null +++ b/gpxe/src/config/config_net80211.c @@ -0,0 +1,50 @@ +/* + * 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, or (at + * your option) any later version. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <config/general.h> + +/** @file + * + * 802.11 configuration options + * + */ + +/* + * Drag in 802.11-specific commands + * + */ +#ifdef IWMGMT_CMD +REQUIRE_OBJECT ( iwmgmt_cmd ); +#endif + +/* + * Drag in 802.11 error message tables + * + */ +#ifdef ERRMSG_80211 +REQUIRE_OBJECT ( wireless_errors ); +#endif + +/* + * Drag in 802.11 cryptosystems and handshaking protocols + * + */ +#ifdef CRYPTO_80211_WEP +REQUIRE_OBJECT ( wep ); +#endif + +#ifdef CRYPTO_80211_WPA2 +#define CRYPTO_80211_WPA +REQUIRE_OBJECT ( wpa_ccmp ); +#endif + +#ifdef CRYPTO_80211_WPA +REQUIRE_OBJECT ( wpa_psk ); +REQUIRE_OBJECT ( wpa_tkip ); +#endif diff --git a/gpxe/src/config/config_romprefix.c b/gpxe/src/config/config_romprefix.c new file mode 100644 index 00000000..85f1e78a --- /dev/null +++ b/gpxe/src/config/config_romprefix.c @@ -0,0 +1,24 @@ +/* + * 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, or (at + * your option) any later version. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <config/general.h> + +/** @file + * + * ROM prefix configuration options + * + */ + +/* + * Provide UNDI loader if PXE stack is requested + * + */ +#ifdef PXE_STACK +REQUIRE_OBJECT ( undiloader ); +#endif diff --git a/gpxe/src/config/console.h b/gpxe/src/config/console.h index b4ea1dda..be3242dd 100644 --- a/gpxe/src/config/console.h +++ b/gpxe/src/config/console.h @@ -10,6 +10,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/defaults.h> //#define CONSOLE_PCBIOS /* Default BIOS console */ diff --git a/gpxe/src/config/defaults.h b/gpxe/src/config/defaults.h index 1f55ef3c..389c0b07 100644 --- a/gpxe/src/config/defaults.h +++ b/gpxe/src/config/defaults.h @@ -1,6 +1,8 @@ #ifndef CONFIG_DEFAULTS_H #define CONFIG_DEFAULTS_H +FILE_LICENCE ( GPL2_OR_LATER ); + #define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h> #include CONFIG_DEFAULTS(PLATFORM) diff --git a/gpxe/src/config/defaults/pcbios.h b/gpxe/src/config/defaults/pcbios.h index 4359e1a4..c09105cc 100644 --- a/gpxe/src/config/defaults/pcbios.h +++ b/gpxe/src/config/defaults/pcbios.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #define UACCESS_LIBRM #define IOAPI_X86 #define PCIAPI_PCBIOS @@ -23,6 +25,10 @@ #define IMAGE_BZIMAGE /* Linux bzImage image support */ #define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ +#define PXE_STACK /* PXE stack in gPXE - required for PXELINUX */ +#define PXE_MENU /* PXE menu booting */ +#define PXE_CMD /* PXE commands */ + #define SANBOOT_PROTO_ISCSI /* iSCSI protocol */ #define SANBOOT_PROTO_AOE /* AoE protocol */ diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h index a3d563c2..de51f9f8 100644 --- a/gpxe/src/config/general.h +++ b/gpxe/src/config/general.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/defaults.h> /* @@ -40,18 +42,23 @@ #define NET_PROTO_IPV4 /* IPv4 protocol */ /* + * PXE support + * + */ +//#undef PXE_STACK /* PXE stack in gPXE - you want this! */ +//#undef PXE_MENU /* PXE menu booting */ + +/* * Download protocols * */ #define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */ -#define DOWNLOAD_PROTO_NFS /* Network File System */ #define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ #define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ #define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ #undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ #undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ -#undef DOWNLOAD_PROTO_FSP /* FSP? */ /* * SAN boot protocols @@ -60,6 +67,15 @@ //#undef SANBOOT_PROTO_ISCSI /* iSCSI protocol */ //#undef SANBOOT_PROTO_AOE /* AoE protocol */ +//#undef SANBOOT_PROTO_IB_SRP /* Infiniband SCSI RDMA protocol */ + +/* + * 802.11 cryptosystems and handshaking protocols + * + */ +#define CRYPTO_80211_WEP /* WEP encryption (deprecated and insecure!) */ +#define CRYPTO_80211_WPA /* WPA Personal, authenticating with passphrase */ +#define CRYPTO_80211_WPA2 /* Add support for stronger WPA cryptography */ /* * Name resolution modules @@ -67,7 +83,6 @@ */ #define DNS_RESOLVER /* DNS resolver */ -#undef NMB_RESOLVER /* NMB resolver */ /* * Image types @@ -96,11 +111,21 @@ #define NVO_CMD /* Non-volatile option storage commands */ #define CONFIG_CMD /* Option configuration console */ #define IFMGMT_CMD /* Interface management commands */ +#define IWMGMT_CMD /* Wireless interface management commands */ #define ROUTE_CMD /* Routing table management commands */ #define IMAGE_CMD /* Image management commands */ #define DHCP_CMD /* DHCP management commands */ #define SANBOOT_CMD /* SAN boot commands */ #define LOGIN_CMD /* Login command */ +#undef TIME_CMD /* Time commands */ +#undef DIGEST_CMD /* Image crypto digest commands */ +//#undef PXE_CMD /* PXE commands */ + +/* + * Error message tables to include + * + */ +#undef ERRMSG_80211 /* All 802.11 error descriptions (~3.3kb) */ /* * Obscure configuration options diff --git a/gpxe/src/config/ioapi.h b/gpxe/src/config/ioapi.h index 7726a0f0..8ddd557b 100644 --- a/gpxe/src/config/ioapi.h +++ b/gpxe/src/config/ioapi.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/defaults.h> //#undef PCIAPI_PCBIOS /* Access via PCI BIOS */ diff --git a/gpxe/src/config/nap.h b/gpxe/src/config/nap.h index 8648d925..1b981355 100644 --- a/gpxe/src/config/nap.h +++ b/gpxe/src/config/nap.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/defaults.h> //#undef NAP_PCBIOS diff --git a/gpxe/src/config/serial.h b/gpxe/src/config/serial.h index 984a7a9c..44272d1f 100644 --- a/gpxe/src/config/serial.h +++ b/gpxe/src/config/serial.h @@ -11,7 +11,14 @@ * */ -#define COMCONSOLE 0x3f8 /* I/O port address */ +FILE_LICENCE ( GPL2_OR_LATER ); + +#define COM1 0x3f8 +#define COM2 0x2f8 +#define COM3 0x3e8 +#define COM4 0x2e8 + +#define COMCONSOLE COM1 /* I/O port address */ /* Keep settings from a previous user of the serial port (e.g. lilo or * LinuxBIOS), ignoring COMSPEED, COMDATA, COMPARITY and COMSTOP. diff --git a/gpxe/src/config/timer.h b/gpxe/src/config/timer.h index 7c3f3521..cc6a93d1 100644 --- a/gpxe/src/config/timer.h +++ b/gpxe/src/config/timer.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/defaults.h> //#undef TIMER_PCBIOS diff --git a/gpxe/src/config/umalloc.h b/gpxe/src/config/umalloc.h index de4019e5..65febf1f 100644 --- a/gpxe/src/config/umalloc.h +++ b/gpxe/src/config/umalloc.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <config/defaults.h> #endif /* CONFIG_UMALLOC_H */ diff --git a/gpxe/src/core/acpi.c b/gpxe/src/core/acpi.c index 94b7b2a1..b65f4d48 100644 --- a/gpxe/src/core/acpi.c +++ b/gpxe/src/core/acpi.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/acpi.h> /** @file diff --git a/gpxe/src/core/ansiesc.c b/gpxe/src/core/ansiesc.c index 6b820ada..31306e2a 100644 --- a/gpxe/src/core/ansiesc.c +++ b/gpxe/src/core/ansiesc.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <assert.h> #include <gpxe/ansiesc.h> diff --git a/gpxe/src/core/asprintf.c b/gpxe/src/core/asprintf.c index 94d7e7c4..03cf45cf 100644 --- a/gpxe/src/core/asprintf.c +++ b/gpxe/src/core/asprintf.c @@ -4,6 +4,8 @@ #include <stdio.h> #include <errno.h> +FILE_LICENCE ( GPL2_OR_LATER ); + /** * Write a formatted string to newly allocated memory. * diff --git a/gpxe/src/core/base64.c b/gpxe/src/core/base64.c index e54821e3..5619ef7b 100644 --- a/gpxe/src/core/base64.c +++ b/gpxe/src/core/base64.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <assert.h> diff --git a/gpxe/src/core/basename.c b/gpxe/src/core/basename.c index 7340c0d5..a481c54f 100644 --- a/gpxe/src/core/basename.c +++ b/gpxe/src/core/basename.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/core/bitmap.c b/gpxe/src/core/bitmap.c index d0266471..bbe9cbaa 100644 --- a/gpxe/src/core/bitmap.c +++ b/gpxe/src/core/bitmap.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <errno.h> #include <gpxe/bitmap.h> diff --git a/gpxe/src/core/bitops.c b/gpxe/src/core/bitops.c index 53abaaea..1bca9e47 100644 --- a/gpxe/src/core/bitops.c +++ b/gpxe/src/core/bitops.c @@ -1,5 +1,7 @@ #include <strings.h> +FILE_LICENCE ( GPL2_OR_LATER ); + int __flsl ( long x ) { unsigned long value = x; int ls = 0; diff --git a/gpxe/src/core/console.c b/gpxe/src/core/console.c index c9773f71..e22d2601 100644 --- a/gpxe/src/core/console.c +++ b/gpxe/src/core/console.c @@ -5,10 +5,7 @@ /** @file */ -static struct console_driver console_drivers[0] - __table_start ( struct console_driver, console ); -static struct console_driver console_drivers_end[0] - __table_end ( struct console_driver, console ); +FILE_LICENCE ( GPL2_OR_LATER ); /** * Write a single character to each console device. @@ -28,8 +25,7 @@ void putchar ( int character ) { if ( character == '\n' ) putchar ( '\r' ); - for ( console = console_drivers; console < console_drivers_end ; - console++ ) { + for_each_table_entry ( console, CONSOLES ) { if ( ( ! console->disabled ) && console->putchar ) console->putchar ( character ); } @@ -51,8 +47,7 @@ void putchar ( int character ) { static struct console_driver * has_input ( void ) { struct console_driver *console; - for ( console = console_drivers; console < console_drivers_end ; - console++ ) { + for_each_table_entry ( console, CONSOLES ) { if ( ( ! console->disabled ) && console->iskey ) { if ( console->iskey () ) return console; diff --git a/gpxe/src/core/cpio.c b/gpxe/src/core/cpio.c index 7d2e8828..b303fa35 100644 --- a/gpxe/src/core/cpio.c +++ b/gpxe/src/core/cpio.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** @file * * CPIO archives diff --git a/gpxe/src/core/ctype.c b/gpxe/src/core/ctype.c new file mode 100644 index 00000000..6185bb2f --- /dev/null +++ b/gpxe/src/core/ctype.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * Character types + * + */ + +#include <ctype.h> + +/** + * Check to see if character is a space + * + * @v c Character + * @ret isspace Character is a space + */ +int isspace ( int c ) { + switch ( c ) { + case ' ' : + case '\f' : + case '\n' : + case '\r' : + case '\t' : + case '\v' : + return 1; + default: + return 0; + } +} diff --git a/gpxe/src/core/cwuri.c b/gpxe/src/core/cwuri.c index 81fd900e..65e01b21 100644 --- a/gpxe/src/core/cwuri.c +++ b/gpxe/src/core/cwuri.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stddef.h> #include <gpxe/uri.h> diff --git a/gpxe/src/core/debug.c b/gpxe/src/core/debug.c index 500a7ac0..8f929309 100644 --- a/gpxe/src/core/debug.c +++ b/gpxe/src/core/debug.c @@ -36,7 +36,8 @@ static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data, printf ( " " ); continue; } - printf ( " %02x", bytes[i] ); + printf ( "%c%02x", + ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] ); } printf ( " : " ); for ( i = offset ; i < ( offset + 16 ) ; i++ ) { diff --git a/gpxe/src/core/device.c b/gpxe/src/core/device.c index 84915c2d..96ccc9ff 100644 --- a/gpxe/src/core/device.c +++ b/gpxe/src/core/device.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <gpxe/list.h> #include <gpxe/tables.h> @@ -29,11 +31,6 @@ * */ -static struct root_device root_devices[0] - __table_start ( struct root_device, root_devices ); -static struct root_device root_devices_end[0] - __table_end ( struct root_device, root_devices ); - /** Registered root devices */ static LIST_HEAD ( devices ); @@ -77,7 +74,7 @@ static void probe_devices ( void ) { struct root_device *rootdev; int rc; - for ( rootdev = root_devices; rootdev < root_devices_end; rootdev++ ) { + for_each_table_entry ( rootdev, ROOT_DEVICES ) { list_add ( &rootdev->dev.siblings, &devices ); INIT_LIST_HEAD ( &rootdev->dev.children ); if ( ( rc = rootdev_probe ( rootdev ) ) != 0 ) diff --git a/gpxe/src/core/downloader.c b/gpxe/src/core/downloader.c index 0a443db2..86c144dc 100644 --- a/gpxe/src/core/downloader.c +++ b/gpxe/src/core/downloader.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <stdarg.h> #include <errno.h> @@ -124,18 +126,37 @@ static int downloader_ensure_size ( struct downloader *downloader, * @v job Downloader job control interface */ static void downloader_job_kill ( struct job_interface *job ) { - struct downloader *downloader = + struct downloader *downloader = container_of ( job, struct downloader, job ); /* Terminate download */ downloader_finished ( downloader, -ECANCELED ); } +/** + * Report progress of download job + * + * @v job Downloader job control interface + * @v progress Progress report to fill in + */ +static void downloader_job_progress ( struct job_interface *job, + struct job_progress *progress ) { + struct downloader *downloader = + container_of ( job, struct downloader, job ); + + /* This is not entirely accurate, since downloaded data may + * arrive out of order (e.g. with multicast protocols), but + * it's a reasonable first approximation. + */ + progress->completed = downloader->pos; + progress->total = downloader->image->len; +} + /** Downloader job control interface operations */ static struct job_interface_operations downloader_job_operations = { .done = ignore_job_done, .kill = downloader_job_kill, - .progress = ignore_job_progress, + .progress = downloader_job_progress, }; /**************************************************************************** @@ -205,7 +226,7 @@ static void downloader_xfer_close ( struct xfer_interface *xfer, int rc ) { /** Downloader data transfer interface operations */ static struct xfer_interface_operations downloader_xfer_operations = { .close = downloader_xfer_close, - .vredirect = xfer_vopen, + .vredirect = xfer_vreopen, .window = unlimited_xfer_window, .alloc_iob = default_xfer_alloc_iob, .deliver_iob = downloader_xfer_deliver_iob, diff --git a/gpxe/src/core/exec.c b/gpxe/src/core/exec.c index a9861b60..6c16aa44 100644 --- a/gpxe/src/core/exec.c +++ b/gpxe/src/core/exec.c @@ -16,10 +16,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <ctype.h> #include <unistd.h> #include <getopt.h> #include <errno.h> @@ -34,11 +37,6 @@ * */ -static struct command commands[0] - __table_start ( struct command, commands ); -static struct command commands_end[0] - __table_end ( struct command, commands ); - /* Avoid dragging in getopt.o unless a command really uses it */ int optind; int nextchar; @@ -78,7 +76,7 @@ int execv ( const char *command, char * const argv[] ) { reset_getopt(); /* Hand off to command implementation */ - for ( cmd = commands ; cmd < commands_end ; cmd++ ) { + for_each_table_entry ( cmd, COMMANDS ) { if ( strcmp ( command, cmd->name ) == 0 ) return cmd->exec ( argc, ( char ** ) argv ); } @@ -173,7 +171,7 @@ static int split_args ( char *args, char * argv[] ) { while ( 1 ) { /* Skip over any whitespace / convert to NUL */ - while ( *args == ' ' ) { + while ( isspace ( *args ) ) { if ( argv ) *args = '\0'; args++; @@ -186,7 +184,7 @@ static int split_args ( char *args, char * argv[] ) { argv[argc] = args; argc++; /* Skip to start of next whitespace, if any */ - while ( *args && ( *args != ' ' ) ) { + while ( *args && ! isspace ( *args ) ) { args++; } } diff --git a/gpxe/src/core/filter.c b/gpxe/src/core/filter.c index f9ebe7cf..a8bee7dc 100644 --- a/gpxe/src/core/filter.c +++ b/gpxe/src/core/filter.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/xfer.h> #include <gpxe/filter.h> diff --git a/gpxe/src/core/gdbstub.c b/gpxe/src/core/gdbstub.c index bbed344f..c8083955 100644 --- a/gpxe/src/core/gdbstub.c +++ b/gpxe/src/core/gdbstub.c @@ -54,10 +54,6 @@ struct gdbstub { int len; /* length of payload */ }; -/* Transports */ -static struct gdb_transport gdb_transport_start[0] __table_start ( struct gdb_transport, gdb_transports ); -static struct gdb_transport gdb_transport_end[0] __table_end ( struct gdb_transport, gdb_transports ); - /* Packet parser states */ static void gdbstub_state_new ( struct gdbstub *stub, char ch ); static void gdbstub_state_data ( struct gdbstub *stub, char ch ); @@ -348,12 +344,10 @@ static void gdbstub_state_cksum2 ( struct gdbstub *stub, char ch ) { static void gdbstub_state_wait_ack ( struct gdbstub *stub, char ch ) { if ( ch == '+' ) { stub->parse = gdbstub_state_new; - } else if ( ch == '-' ) { - gdbstub_tx_packet ( stub ); /* retransmit */ - } else if ( ch == '$' ) { - /* GDB is reconnecting, drop our packet and listen to GDB */ - stub->trans->send ( "-", 1 ); - stub->parse = gdbstub_state_new; + } else { + /* This retransmit is very aggressive but necessary to keep + * in sync with GDB. */ + gdbstub_tx_packet ( stub ); } } @@ -387,7 +381,8 @@ void gdbstub_handler ( int signo, gdbreg_t *regs ) { struct gdb_transport *find_gdb_transport ( const char *name ) { struct gdb_transport *trans; - for ( trans = gdb_transport_start; trans < gdb_transport_end; trans++ ) { + + for_each_table_entry ( trans, GDB_TRANSPORTS ) { if ( strcmp ( trans->name, name ) == 0 ) { return trans; } diff --git a/gpxe/src/core/getkey.c b/gpxe/src/core/getkey.c index 787c9027..dbd074cc 100644 --- a/gpxe/src/core/getkey.c +++ b/gpxe/src/core/getkey.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <ctype.h> #include <console.h> #include <gpxe/process.h> diff --git a/gpxe/src/core/getopt.c b/gpxe/src/core/getopt.c index 6de412bb..b67da0c1 100644 --- a/gpxe/src/core/getopt.c +++ b/gpxe/src/core/getopt.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <stdio.h> diff --git a/gpxe/src/core/image.c b/gpxe/src/core/image.c index 277d09a9..24fe51ab 100644 --- a/gpxe/src/core/image.c +++ b/gpxe/src/core/image.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stddef.h> #include <string.h> #include <stdlib.h> @@ -37,12 +39,6 @@ /** List of registered images */ struct list_head images = LIST_HEAD_INIT ( images ); -/** List of image types */ -static struct image_type image_types[0] - __table_start ( struct image_type, image_types ); -static struct image_type image_types_end[0] - __table_end ( struct image_type, image_types ); - /** * Free executable/loadable image * @@ -219,7 +215,7 @@ int image_autoload ( struct image *image ) { return image_load ( image ); /* Otherwise probe for a suitable type */ - for ( type = image_types ; type < image_types_end ; type++ ) { + for_each_table_entry ( type, IMAGE_TYPES ) { DBGC ( image, "IMAGE %p trying type %s\n", image, type->name ); rc = image_load_type ( image, type ); if ( image->type == NULL ) diff --git a/gpxe/src/core/init.c b/gpxe/src/core/init.c index 50e199ce..cd0f6dcc 100644 --- a/gpxe/src/core/init.c +++ b/gpxe/src/core/init.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/device.h> #include <gpxe/init.h> @@ -25,18 +27,6 @@ * */ -/** Registered initialisation functions */ -static struct init_fn init_fns[0] - __table_start ( struct init_fn, init_fns ); -static struct init_fn init_fns_end[0] - __table_end ( struct init_fn, init_fns ); - -/** Registered startup/shutdown functions */ -static struct startup_fn startup_fns[0] - __table_start ( struct startup_fn, startup_fns ); -static struct startup_fn startup_fns_end[0] - __table_end ( struct startup_fn, startup_fns ); - /** "startup() has been called" flag */ static int started = 0; @@ -54,9 +44,8 @@ void initialise ( void ) { struct init_fn *init_fn; /* Call registered initialisation functions */ - for ( init_fn = init_fns ; init_fn < init_fns_end ; init_fn++ ) { + for_each_table_entry ( init_fn, INIT_FNS ) init_fn->initialise (); - } } /** @@ -73,8 +62,7 @@ void startup ( void ) { return; /* Call registered startup functions */ - for ( startup_fn = startup_fns ; startup_fn < startup_fns_end ; - startup_fn++ ) { + for_each_table_entry ( startup_fn, STARTUP_FNS ) { if ( startup_fn->startup ) startup_fn->startup(); } @@ -90,7 +78,7 @@ void startup ( void ) { * This function reverses the actions of startup(), and leaves gPXE in * a state ready to be removed from memory. You may call startup() * again after calling shutdown(). - + * * Call this function only once, before either exiting main() or * starting up a non-returnable image. */ @@ -101,8 +89,7 @@ void shutdown ( int flags ) { return; /* Call registered shutdown functions (in reverse order) */ - for ( startup_fn = startup_fns_end - 1 ; startup_fn >= startup_fns ; - startup_fn-- ) { + for_each_table_entry_reverse ( startup_fn, STARTUP_FNS ) { if ( startup_fn->shutdown ) startup_fn->shutdown ( flags ); } diff --git a/gpxe/src/core/interface.c b/gpxe/src/core/interface.c index 37aabfe0..43d58ed2 100644 --- a/gpxe/src/core/interface.c +++ b/gpxe/src/core/interface.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/interface.h> /** @file diff --git a/gpxe/src/core/iobuf.c b/gpxe/src/core/iobuf.c index cc4aedea..1ce7890e 100644 --- a/gpxe/src/core/iobuf.c +++ b/gpxe/src/core/iobuf.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <errno.h> #include <gpxe/malloc.h> diff --git a/gpxe/src/core/job.c b/gpxe/src/core/job.c index 6c2faf30..438064ef 100644 --- a/gpxe/src/core/job.c +++ b/gpxe/src/core/job.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <errno.h> #include <gpxe/job.h> @@ -42,6 +44,14 @@ void job_kill ( struct job_interface *job ) { job_put ( dest ); } +void job_progress ( struct job_interface *job, + struct job_progress *progress ) { + struct job_interface *dest = job_get_dest ( job ); + + dest->op->progress ( dest, progress ); + job_put ( dest ); +} + /**************************************************************************** * * Helper methods diff --git a/gpxe/src/core/linebuf.c b/gpxe/src/core/linebuf.c index d02f37c3..221f4e1a 100644 --- a/gpxe/src/core/linebuf.c +++ b/gpxe/src/core/linebuf.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/core/main.c b/gpxe/src/core/main.c index bd2428f0..d07d24c0 100644 --- a/gpxe/src/core/main.c +++ b/gpxe/src/core/main.c @@ -9,11 +9,11 @@ Literature dealing with the network protocols: DHCP - RFC2131, RFC2132 (options) TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize) RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper) - NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented) - IGMP - RFC1112 **************************************************************************/ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdio.h> #include <gpxe/init.h> #include <gpxe/features.h> @@ -27,9 +27,6 @@ Literature dealing with the network protocols: #define BOLD "\033[1m" #define CYAN "\033[36m" -static struct feature features[0] __table_start ( struct feature, features ); -static struct feature features_end[0] __table_end ( struct feature, features ); - /** * Main entry point * @@ -61,7 +58,7 @@ __asmcall int main ( void ) { NORMAL " -- Open Source Boot Firmware -- " CYAN "http://etherboot.org" NORMAL "\n" "Features:" ); - for ( feature = features ; feature < features_end ; feature++ ) + for_each_table_entry ( feature, FEATURES ) printf ( " %s", feature->name ); printf ( "\n" ); diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c index db7f1bed..8b0bc24d 100644 --- a/gpxe/src/core/malloc.c +++ b/gpxe/src/core/malloc.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stddef.h> #include <stdint.h> #include <string.h> diff --git a/gpxe/src/core/misc.c b/gpxe/src/core/misc.c index 1f51272d..c19591bb 100644 --- a/gpxe/src/core/misc.c +++ b/gpxe/src/core/misc.c @@ -2,7 +2,10 @@ MISC Support Routines **************************************************************************/ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> +#include <ctype.h> #include <byteswap.h> #include <gpxe/in.h> #include <gpxe/timer.h> @@ -30,20 +33,6 @@ int inet_aton ( const char *cp, struct in_addr *inp ) { return 0; } -int isspace ( int c ) { - switch ( c ) { - case ' ': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - return 1; - default: - return 0; - } -} - unsigned long strtoul ( const char *p, char **endp, int base ) { unsigned long ret = 0; unsigned int charval; diff --git a/gpxe/src/core/monojob.c b/gpxe/src/core/monojob.c index 657bfd7a..a24b559e 100644 --- a/gpxe/src/core/monojob.c +++ b/gpxe/src/core/monojob.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <stdio.h> #include <errno.h> diff --git a/gpxe/src/core/nvo.c b/gpxe/src/core/nvo.c index e5c07d98..3dbf51d3 100644 --- a/gpxe/src/core/nvo.c +++ b/gpxe/src/core/nvo.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> diff --git a/gpxe/src/core/open.c b/gpxe/src/core/open.c index db8d92e6..70b427ba 100644 --- a/gpxe/src/core/open.c +++ b/gpxe/src/core/open.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdarg.h> #include <string.h> #include <errno.h> @@ -30,18 +32,6 @@ * */ -/** Registered URI openers */ -static struct uri_opener uri_openers[0] - __table_start ( struct uri_opener, uri_openers ); -static struct uri_opener uri_openers_end[0] - __table_end ( struct uri_opener, uri_openers ); - -/** Registered socket openers */ -static struct socket_opener socket_openers[0] - __table_start ( struct socket_opener, socket_openers ); -static struct socket_opener socket_openers_end[0] - __table_end ( struct socket_opener, socket_openers ); - /** * Open URI * @@ -63,8 +53,10 @@ int xfer_open_uri ( struct xfer_interface *xfer, struct uri *uri ) { return -ENOMEM; /* Find opener which supports this URI scheme */ - for ( opener = uri_openers ; opener < uri_openers_end ; opener++ ) { + for_each_table_entry ( opener, URI_OPENERS ) { if ( strcmp ( resolved_uri->scheme, opener->scheme ) == 0 ) { + DBGC ( xfer, "XFER %p opening %s URI\n", + xfer, opener->scheme ); rc = opener->open ( xfer, resolved_uri ); goto done; } @@ -121,7 +113,7 @@ int xfer_open_socket ( struct xfer_interface *xfer, int semantics, socket_semantics_name ( semantics ), socket_family_name ( peer->sa_family ) ); - for ( opener = socket_openers; opener < socket_openers_end; opener++ ){ + for_each_table_entry ( opener, SOCKET_OPENERS ) { if ( ( opener->semantics == semantics ) && ( opener->family == peer->sa_family ) ) { return opener->open ( xfer, peer, local ); @@ -182,3 +174,24 @@ int xfer_open ( struct xfer_interface *xfer, int type, ... ) { va_end ( args ); return rc; } + +/** + * Reopen location + * + * @v xfer Data transfer interface + * @v type Location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + * + * This will close the existing connection and open a new connection + * using xfer_vopen(). It is intended to be used as a .vredirect + * method handler. + */ +int xfer_vreopen ( struct xfer_interface *xfer, int type, va_list args ) { + + /* Close existing connection */ + xfer_close ( xfer, 0 ); + + /* Open new location */ + return xfer_vopen ( xfer, type, args ); +} diff --git a/gpxe/src/core/posix_io.c b/gpxe/src/core/posix_io.c index e0459bdf..e6b1a0f6 100644 --- a/gpxe/src/core/posix_io.c +++ b/gpxe/src/core/posix_io.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <string.h> #include <errno.h> @@ -137,7 +139,7 @@ posix_file_xfer_deliver_iob ( struct xfer_interface *xfer, /** POSIX file data transfer interface operations */ static struct xfer_interface_operations posix_file_xfer_operations = { .close = posix_file_xfer_close, - .vredirect = xfer_vopen, + .vredirect = xfer_vreopen, .window = unlimited_xfer_window, .alloc_iob = default_xfer_alloc_iob, .deliver_iob = posix_file_xfer_deliver_iob, diff --git a/gpxe/src/core/process.c b/gpxe/src/core/process.c index 6a687140..9c13e020 100644 --- a/gpxe/src/core/process.c +++ b/gpxe/src/core/process.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <gpxe/list.h> #include <gpxe/init.h> #include <gpxe/process.h> @@ -31,21 +33,22 @@ /** Process run queue */ static LIST_HEAD ( run_queue ); -/** Registered permanent processes */ -static struct process processes[0] - __table_start ( struct process, processes ); -static struct process processes_end[0] - __table_end ( struct process, processes ); - /** * Add process to process list * * @v process Process + * + * It is safe to call process_add() multiple times; further calls will + * have no effect. */ void process_add ( struct process *process ) { - DBGC ( process, "PROCESS %p starting\n", process ); - ref_get ( process->refcnt ); - list_add_tail ( &process->list, &run_queue ); + if ( list_empty ( &process->list ) ) { + DBGC ( process, "PROCESS %p starting\n", process ); + ref_get ( process->refcnt ); + list_add_tail ( &process->list, &run_queue ); + } else { + DBGC ( process, "PROCESS %p already started\n", process ); + } } /** @@ -93,9 +96,8 @@ void step ( void ) { static void init_processes ( void ) { struct process *process; - for ( process = processes ; process < processes_end ; process++ ) { + for_each_table_entry ( process, PERMANENT_PROCESSES ) process_add ( process ); - } } /** Process initialiser */ diff --git a/gpxe/src/core/random.c b/gpxe/src/core/random.c index d34e763a..6e7374e3 100644 --- a/gpxe/src/core/random.c +++ b/gpxe/src/core/random.c @@ -4,6 +4,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <gpxe/timer.h> diff --git a/gpxe/src/core/refcnt.c b/gpxe/src/core/refcnt.c index 30bb6dea..f2286cac 100644 --- a/gpxe/src/core/refcnt.c +++ b/gpxe/src/core/refcnt.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <gpxe/refcnt.h> diff --git a/gpxe/src/core/resolv.c b/gpxe/src/core/resolv.c index f4a587f1..6f01f93e 100644 --- a/gpxe/src/core/resolv.c +++ b/gpxe/src/core/resolv.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -150,12 +152,6 @@ struct resolver numeric_resolver __resolver ( RESOLV_NUMERIC ) = { *************************************************************************** */ -/** Registered name resolvers */ -static struct resolver resolvers[0] - __table_start ( struct resolver, resolvers ); -static struct resolver resolvers_end[0] - __table_end ( struct resolver, resolvers ); - /** A name resolution multiplexer */ struct resolv_mux { /** Reference counter */ @@ -223,7 +219,7 @@ static void resolv_mux_done ( struct resolv_interface *resolv, /* Attempt next child resolver, if possible */ mux->resolver++; - if ( mux->resolver >= resolvers_end ) { + if ( mux->resolver >= table_end ( RESOLVERS ) ) { DBGC ( mux, "RESOLV %p failed to resolve name\n", mux ); goto finished; } @@ -262,7 +258,7 @@ int resolv ( struct resolv_interface *resolv, const char *name, return -ENOMEM; resolv_init ( &mux->parent, &null_resolv_ops, &mux->refcnt ); resolv_init ( &mux->child, &resolv_mux_child_ops, &mux->refcnt ); - mux->resolver = resolvers; + mux->resolver = table_start ( RESOLVERS ); memcpy ( &mux->sa, sa, sizeof ( mux->sa ) ); memcpy ( mux->name, name, name_len ); @@ -308,9 +304,36 @@ struct named_socket { int have_local; }; +/** + * Finish using named socket + * + * @v named Named socket + * @v rc Reason for finish + */ +static void named_done ( struct named_socket *named, int rc ) { + + /* Close all interfaces */ + resolv_nullify ( &named->resolv ); + xfer_nullify ( &named->xfer ); + xfer_close ( &named->xfer, rc ); +} + +/** + * Handle close() event + * + * @v xfer Data transfer interface + * @v rc Reason for close + */ +static void named_xfer_close ( struct xfer_interface *xfer, int rc ) { + struct named_socket *named = + container_of ( xfer, struct named_socket, xfer ); + + named_done ( named, rc ); +} + /** Named socket opener data transfer interface operations */ static struct xfer_interface_operations named_xfer_ops = { - .close = ignore_xfer_close, + .close = named_xfer_close, .vredirect = ignore_xfer_vredirect, .window = no_xfer_window, .alloc_iob = default_xfer_alloc_iob, @@ -330,10 +353,6 @@ static void named_resolv_done ( struct resolv_interface *resolv, struct named_socket *named = container_of ( resolv, struct named_socket, resolv ); - /* Unplug resolver and nullify data transfer interface */ - resolv_unplug ( &named->resolv ); - xfer_nullify ( &named->xfer ); - /* Redirect if name resolution was successful */ if ( rc == 0 ) { rc = xfer_redirect ( &named->xfer, LOCATION_SOCKET, @@ -342,12 +361,8 @@ static void named_resolv_done ( struct resolv_interface *resolv, &named->local : NULL ) ); } - /* Close data transfer interface if redirection failed */ - if ( rc != 0 ) - xfer_close ( &named->xfer, rc ); - - /* Unplug data transfer interface */ - xfer_unplug ( &named->xfer ); + /* Terminate resolution */ + named_done ( named, rc ); } /** Named socket opener name resolution interface operations */ diff --git a/gpxe/src/core/serial.c b/gpxe/src/core/serial.c index 5b3be39c..d35e89e9 100644 --- a/gpxe/src/core/serial.c +++ b/gpxe/src/core/serial.c @@ -11,6 +11,8 @@ * parity, 1 stop bit (8N1). This can be changed in init_serial(). */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include "stddef.h" #include <gpxe/init.h> #include <gpxe/io.h> diff --git a/gpxe/src/core/settings.c b/gpxe/src/core/settings.c index f34eb664..7d83101c 100644 --- a/gpxe/src/core/settings.c +++ b/gpxe/src/core/settings.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdlib.h> #include <stdio.h> @@ -37,85 +39,326 @@ * */ -/** Registered settings */ -static struct setting settings[0] - __table_start ( struct setting, settings ); -static struct setting settings_end[0] - __table_end ( struct setting, settings ); +/****************************************************************************** + * + * Generic settings blocks + * + ****************************************************************************** + */ -/** Registered setting types */ -static struct setting_type setting_types[0] - __table_start ( struct setting_type, setting_types ); -static struct setting_type setting_types_end[0] - __table_end ( struct setting_type, setting_types ); +/** + * A generic setting + * + */ +struct generic_setting { + /** List of generic settings */ + struct list_head list; + /** Setting */ + struct setting setting; + /** Size of setting name */ + size_t name_len; + /** Size of setting data */ + size_t data_len; +}; -/** Registered settings applicators */ -static struct settings_applicator settings_applicators[0] - __table_start ( struct settings_applicator, settings_applicators ); -static struct settings_applicator settings_applicators_end[0] - __table_end ( struct settings_applicator, settings_applicators ); +/** + * Get generic setting name + * + * @v generic Generic setting + * @ret name Generic setting name + */ +static inline void * generic_setting_name ( struct generic_setting *generic ) { + return ( ( ( void * ) generic ) + sizeof ( *generic ) ); +} -/****************************************************************************** +/** + * Get generic setting data * - * Registered settings blocks + * @v generic Generic setting + * @ret data Generic setting data + */ +static inline void * generic_setting_data ( struct generic_setting *generic ) { + return ( ( ( void * ) generic ) + sizeof ( *generic ) + + generic->name_len ); +} + +/** + * Find generic setting * - ****************************************************************************** + * @v generics Generic settings block + * @v setting Setting to find + * @ret generic Generic setting, or NULL */ +static struct generic_setting * +find_generic_setting ( struct generic_settings *generics, + struct setting *setting ) { + struct generic_setting *generic; + + list_for_each_entry ( generic, &generics->list, list ) { + if ( setting_cmp ( &generic->setting, setting ) == 0 ) + return generic; + } + return NULL; +} /** - * Store value of simple setting + * Store value of generic setting * - * @v options DHCP option block + * @v settings Settings block * @v setting Setting to store * @v data Setting data, or NULL to clear setting * @v len Length of setting data * @ret rc Return status code */ -int simple_settings_store ( struct settings *settings, struct setting *setting, - const void *data, size_t len ) { - struct simple_settings *simple = - container_of ( settings, struct simple_settings, settings ); - return dhcpopt_extensible_store ( &simple->dhcpopts, setting->tag, - data, len ); +int generic_settings_store ( struct settings *settings, + struct setting *setting, + const void *data, size_t len ) { + struct generic_settings *generics = + container_of ( settings, struct generic_settings, settings ); + struct generic_setting *old; + struct generic_setting *new = NULL; + size_t name_len; + + /* Identify existing generic setting, if any */ + old = find_generic_setting ( generics, setting ); + + /* Create new generic setting, if required */ + if ( len ) { + /* Allocate new generic setting */ + name_len = ( strlen ( setting->name ) + 1 ); + new = zalloc ( sizeof ( *new ) + name_len + len ); + if ( ! new ) + return -ENOMEM; + + /* Populate new generic setting */ + new->name_len = name_len; + new->data_len = len; + memcpy ( &new->setting, setting, sizeof ( new->setting ) ); + new->setting.name = generic_setting_name ( new ); + memcpy ( generic_setting_name ( new ), + setting->name, name_len ); + memcpy ( generic_setting_data ( new ), data, len ); + } + + /* Delete existing generic setting, if any */ + if ( old ) { + list_del ( &old->list ); + free ( old ); + } + + /* Add new setting to list, if any */ + if ( new ) + list_add ( &new->list, &generics->list ); + + return 0; } /** - * Fetch value of simple setting + * Fetch value of generic setting * - * @v options DHCP option block + * @v settings Settings block * @v setting Setting to fetch * @v data Buffer to fill with setting data * @v len Length of buffer * @ret len Length of setting data, or negative error */ -int simple_settings_fetch ( struct settings *settings, struct setting *setting, - void *data, size_t len ) { - struct simple_settings *simple = - container_of ( settings, struct simple_settings, settings ); - return dhcpopt_fetch ( &simple->dhcpopts, setting->tag, data, len ); +int generic_settings_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct generic_settings *generics = + container_of ( settings, struct generic_settings, settings ); + struct generic_setting *generic; + + /* Find generic setting */ + generic = find_generic_setting ( generics, setting ); + if ( ! generic ) + return -ENOENT; + + /* Copy out generic setting data */ + if ( len > generic->data_len ) + len = generic->data_len; + memcpy ( data, generic_setting_data ( generic ), len ); + return generic->data_len; +} + +/** + * Clear generic settings block + * + * @v settings Settings block + */ +void generic_settings_clear ( struct settings *settings ) { + struct generic_settings *generics = + container_of ( settings, struct generic_settings, settings ); + struct generic_setting *generic; + struct generic_setting *tmp; + + list_for_each_entry_safe ( generic, tmp, &generics->list, list ) { + list_del ( &generic->list ); + free ( generic ); + } + assert ( list_empty ( &generics->list ) ); } -/** Simple settings operations */ -struct settings_operations simple_settings_operations = { - .store = simple_settings_store, - .fetch = simple_settings_fetch, +/** Generic settings operations */ +struct settings_operations generic_settings_operations = { + .store = generic_settings_store, + .fetch = generic_settings_fetch, + .clear = generic_settings_clear, }; -/** Root simple settings block */ -struct simple_settings simple_settings_root = { +/****************************************************************************** + * + * Registered settings blocks + * + ****************************************************************************** + */ + +/** Root generic settings block */ +struct generic_settings generic_settings_root = { .settings = { .refcnt = NULL, .name = "", .siblings = - LIST_HEAD_INIT ( simple_settings_root.settings.siblings ), + LIST_HEAD_INIT ( generic_settings_root.settings.siblings ), .children = - LIST_HEAD_INIT ( simple_settings_root.settings.children ), - .op = &simple_settings_operations, + LIST_HEAD_INIT ( generic_settings_root.settings.children ), + .op = &generic_settings_operations, }, + .list = LIST_HEAD_INIT ( generic_settings_root.list ), }; /** Root settings block */ -#define settings_root simple_settings_root.settings +#define settings_root generic_settings_root.settings + +/** + * Find child named settings block + * + * @v parent Parent settings block + * @v name Name within this parent + * @ret settings Settings block, or NULL + */ +static struct settings * find_child_settings ( struct settings *parent, + const char *name ) { + struct settings *settings; + + /* Treat empty name as meaning "this block" */ + if ( ! *name ) + return parent; + + /* Look for child with matching name */ + list_for_each_entry ( settings, &parent->children, siblings ) { + if ( strcmp ( settings->name, name ) == 0 ) + return settings; + } + + return NULL; +} + +/** + * Find or create child named settings block + * + * @v parent Parent settings block + * @v name Name within this parent + * @ret settings Settings block, or NULL + */ +static struct settings * autovivify_child_settings ( struct settings *parent, + const char *name ) { + struct { + struct generic_settings generic; + char name[ strlen ( name ) + 1 /* NUL */ ]; + } *new_child; + struct settings *settings; + + /* Return existing settings, if existent */ + if ( ( settings = find_child_settings ( parent, name ) ) != NULL ) + return settings; + + /* Create new generic settings block */ + new_child = zalloc ( sizeof ( *new_child ) ); + if ( ! new_child ) { + DBGC ( parent, "Settings %p could not create child %s\n", + parent, name ); + return NULL; + } + memcpy ( new_child->name, name, sizeof ( new_child->name ) ); + generic_settings_init ( &new_child->generic, NULL, new_child->name ); + settings = &new_child->generic.settings; + register_settings ( settings, parent ); + return settings; +} + +/** + * Return settings block name (for debug only) + * + * @v settings Settings block + * @ret name Settings block name + */ +static const char * settings_name ( struct settings *settings ) { + static char buf[64]; + char tmp[ sizeof ( buf ) ]; + int count; + + for ( count = 0 ; settings ; settings = settings->parent ) { + memcpy ( tmp, buf, sizeof ( tmp ) ); + snprintf ( buf, sizeof ( buf ), "%s%c%s", settings->name, + ( count++ ? '.' : '\0' ), tmp ); + } + return ( buf + 1 ); +} + +/** + * Parse settings block name + * + * @v name Name + * @v get_child Function to find or create child settings block + * @ret settings Settings block, or NULL + */ +static struct settings * +parse_settings_name ( const char *name, + struct settings * ( * get_child ) ( struct settings *, + const char * ) ) { + struct settings *settings = &settings_root; + char name_copy[ strlen ( name ) + 1 ]; + char *subname; + char *remainder; + + /* Create modifiable copy of name */ + memcpy ( name_copy, name, sizeof ( name_copy ) ); + remainder = name_copy; + + /* Parse each name component in turn */ + while ( remainder ) { + struct net_device *netdev; + + subname = remainder; + remainder = strchr ( subname, '.' ); + if ( remainder ) + *(remainder++) = '\0'; + + /* Special case "netX" root settings block */ + if ( ( subname == name_copy ) && ! strcmp ( subname, "netX" ) && + ( ( netdev = last_opened_netdev() ) != NULL ) ) + settings = get_child ( settings, netdev->name ); + else + settings = get_child ( settings, subname ); + + if ( ! settings ) + break; + } + + return settings; +} + +/** + * Find named settings block + * + * @v name Name + * @ret settings Settings block, or NULL + */ +struct settings * find_settings ( const char *name ) { + + return parse_settings_name ( name, find_child_settings ); +} /** * Apply all settings @@ -127,8 +370,7 @@ static int apply_settings ( void ) { int rc; /* Call all settings applicators */ - for ( applicator = settings_applicators ; - applicator < settings_applicators_end ; applicator++ ) { + for_each_table_entry ( applicator, SETTINGS_APPLICATORS ) { if ( ( rc = applicator->apply() ) != 0 ) { DBG ( "Could not apply settings using applicator " "%p: %s\n", applicator, strerror ( rc ) ); @@ -199,7 +441,8 @@ int register_settings ( struct settings *settings, struct settings *parent ) { ref_get ( parent->refcnt ); settings->parent = parent; list_add_tail ( &settings->siblings, &parent->children ); - DBGC ( settings, "Settings %p registered\n", settings ); + DBGC ( settings, "Settings %p (\"%s\") registered\n", + settings, settings_name ( settings ) ); /* Fix up settings priority */ reprioritise_settings ( settings ); @@ -217,63 +460,19 @@ int register_settings ( struct settings *settings, struct settings *parent ) { */ void unregister_settings ( struct settings *settings ) { + DBGC ( settings, "Settings %p (\"%s\") unregistered\n", + settings, settings_name ( settings ) ); + /* Remove from list of settings */ ref_put ( settings->refcnt ); ref_put ( settings->parent->refcnt ); settings->parent = NULL; list_del ( &settings->siblings ); - DBGC ( settings, "Settings %p unregistered\n", settings ); /* Apply potentially-updated settings */ apply_settings(); } -/** - * Find child named settings block - * - * @v parent Parent settings block - * @v name Name within this parent - * @ret settings Settings block, or NULL - */ -struct settings * find_child_settings ( struct settings *parent, - const char *name ) { - struct settings *settings; - size_t len; - - /* NULL parent => add to settings root */ - if ( parent == NULL ) - parent = &settings_root; - - /* Look for a child whose name matches the initial component */ - list_for_each_entry ( settings, &parent->children, siblings ) { - len = strlen ( settings->name ); - if ( strncmp ( name, settings->name, len ) != 0 ) - continue; - if ( name[len] == 0 ) - return settings; - if ( name[len] == '.' ) - return find_child_settings ( settings, - ( name + len + 1 ) ); - } - - return NULL; -} - -/** - * Find named settings block - * - * @v name Name - * @ret settings Settings block, or NULL - */ -struct settings * find_settings ( const char *name ) { - - /* If name is empty, use the root */ - if ( ! *name ) - return &settings_root; - - return find_child_settings ( &settings_root, name ); -} - /****************************************************************************** * * Core settings routines @@ -298,6 +497,10 @@ int store_setting ( struct settings *settings, struct setting *setting, if ( ! settings ) settings = &settings_root; + /* Sanity check */ + if ( ! settings->op->store ) + return -ENOTSUP; + /* Store setting */ if ( ( rc = settings->op->store ( settings, setting, data, len ) ) != 0 ) @@ -345,6 +548,10 @@ int fetch_setting ( struct settings *settings, struct setting *setting, if ( ! settings ) settings = &settings_root; + /* Sanity check */ + if ( ! settings->op->fetch ) + return -ENOTSUP; + /* Try this block first */ if ( ( ret = settings->op->fetch ( settings, setting, data, len ) ) >= 0 ) @@ -411,7 +618,7 @@ int fetch_string_setting_copy ( struct settings *settings, struct setting *setting, char **data ) { int len; - int check_len; + int check_len = 0; len = fetch_setting_len ( settings, setting ); if ( len < 0 ) @@ -421,7 +628,8 @@ int fetch_string_setting_copy ( struct settings *settings, if ( ! *data ) return -ENOMEM; - fetch_string_setting ( settings, setting, *data, ( len + 1 ) ); + check_len = fetch_string_setting ( settings, setting, *data, + ( len + 1 ) ); assert ( check_len == len ); return len; } @@ -504,7 +712,8 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, return len; /* Mask off sign-extended bits */ - *value = ( svalue & ( -1UL >> ( sizeof ( long ) - len ) ) ); + assert ( len <= ( int ) sizeof ( long ) ); + *value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) ); return len; } @@ -559,6 +768,16 @@ int fetch_uuid_setting ( struct settings *settings, struct setting *setting, } /** + * Clear settings block + * + * @v settings Settings block + */ +void clear_settings ( struct settings *settings ) { + if ( settings->op->clear ) + settings->op->clear ( settings ); +} + +/** * Compare two settings * * @v a Setting to compare @@ -572,8 +791,12 @@ int setting_cmp ( struct setting *a, struct setting *b ) { if ( a->tag && ( a->tag == b->tag ) ) return 0; - /* Otherwise, compare the names */ - return strcmp ( a->name, b->name ); + /* Otherwise, if the settings have names, compare them */ + if ( a->name && b->name && a->name[0] ) + return strcmp ( a->name, b->name ); + + /* Otherwise, return a non-match */ + return ( ! 0 ); } /****************************************************************************** @@ -614,7 +837,7 @@ int storef_setting ( struct settings *settings, struct setting *setting, static struct setting * find_setting ( const char *name ) { struct setting *setting; - for ( setting = settings ; setting < settings_end ; setting++ ) { + for_each_table_entry ( setting, SETTINGS ) { if ( strcmp ( name, setting->name ) == 0 ) return setting; } @@ -622,6 +845,26 @@ static struct setting * find_setting ( const char *name ) { } /** + * Parse setting name as tag number + * + * @v name Name + * @ret tag Tag number, or 0 if not a valid number + */ +static unsigned int parse_setting_tag ( const char *name ) { + char *tmp = ( ( char * ) name ); + unsigned int tag = 0; + + while ( 1 ) { + tag = ( ( tag << 8 ) | strtoul ( tmp, &tmp, 0 ) ); + if ( *tmp == 0 ) + return tag; + if ( *tmp != '.' ) + return 0; + tmp++; + } +} + +/** * Find setting type * * @v name Name @@ -630,7 +873,7 @@ static struct setting * find_setting ( const char *name ) { static struct setting_type * find_setting_type ( const char *name ) { struct setting_type *type; - for ( type = setting_types ; type < setting_types_end ; type++ ) { + for_each_table_entry ( type, SETTING_TYPES ) { if ( strcmp ( name, type->name ) == 0 ) return type; } @@ -641,30 +884,38 @@ static struct setting_type * find_setting_type ( const char *name ) { * Parse setting name * * @v name Name of setting + * @v get_child Function to find or create child settings block * @v settings Settings block to fill in * @v setting Setting to fill in + * @v tmp_name Buffer for copy of setting name * @ret rc Return status code * * Interprets a name of the form * "[settings_name/]tag_name[:type_name]" and fills in the appropriate * fields. + * + * The @c tmp_name buffer must be large enough to hold a copy of the + * setting name. */ -static int parse_setting_name ( const char *name, struct settings **settings, - struct setting *setting ) { - char tmp_name[ strlen ( name ) + 1 ]; +static int +parse_setting_name ( const char *name, + struct settings * ( * get_child ) ( struct settings *, + const char * ), + struct settings **settings, struct setting *setting, + char *tmp_name ) { char *settings_name; char *setting_name; char *type_name; struct setting *named_setting; - char *tmp; /* Set defaults */ *settings = &settings_root; memset ( setting, 0, sizeof ( *setting ) ); - setting->type = &setting_type_hex; + setting->name = ""; + setting->type = &setting_type_string; /* Split name into "[settings_name/]setting_name[:type_name]" */ - memcpy ( tmp_name, name, sizeof ( tmp_name ) ); + strcpy ( tmp_name, name ); if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) { *(setting_name++) = 0; settings_name = tmp_name; @@ -677,7 +928,7 @@ static int parse_setting_name ( const char *name, struct settings **settings, /* Identify settings block, if specified */ if ( settings_name ) { - *settings = find_settings ( settings_name ); + *settings = parse_settings_name ( settings_name, get_child ); if ( *settings == NULL ) { DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n", settings_name, name ); @@ -685,25 +936,16 @@ static int parse_setting_name ( const char *name, struct settings **settings, } } - /* Identify tag number */ + /* Identify setting */ if ( ( named_setting = find_setting ( setting_name ) ) != NULL ) { + /* Matches a defined named setting; use that setting */ memcpy ( setting, named_setting, sizeof ( *setting ) ); - } else { - /* Unrecognised name: try to interpret as a tag number */ - tmp = setting_name; - while ( 1 ) { - setting->tag = ( ( setting->tag << 8 ) | - strtoul ( tmp, &tmp, 0 ) ); - if ( *tmp == 0 ) - break; - if ( *tmp != '.' ) { - DBG ( "Invalid setting \"%s\" in \"%s\"\n", - setting_name, name ); - return -ENOENT; - } - tmp++; - } + } else if ( ( setting->tag = parse_setting_tag ( setting_name ) ) !=0){ + /* Is a valid numeric tag; use the tag */ setting->tag |= (*settings)->tag_magic; + } else { + /* Use the arbitrary name */ + setting->name = setting_name; } /* Identify setting type, if specified */ @@ -729,9 +971,11 @@ static int parse_setting_name ( const char *name, struct settings **settings, int storef_named_setting ( const char *name, const char *value ) { struct settings *settings; struct setting setting; + char tmp_name[ strlen ( name ) + 1 ]; int rc; - if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 ) + if ( ( rc = parse_setting_name ( name, autovivify_child_settings, + &settings, &setting, tmp_name )) != 0) return rc; return storef_setting ( settings, &setting, value ); } @@ -747,9 +991,11 @@ int storef_named_setting ( const char *name, const char *value ) { int fetchf_named_setting ( const char *name, char *buf, size_t len ) { struct settings *settings; struct setting setting; + char tmp_name[ strlen ( name ) + 1 ]; int rc; - if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 ) + if ( ( rc = parse_setting_name ( name, find_child_settings, + &settings, &setting, tmp_name )) != 0) return rc; return fetchf_setting ( settings, &setting, buf, len ); } @@ -839,7 +1085,7 @@ static int fetchf_uristring ( struct settings *settings, fetch_string_setting ( settings, setting, raw_buf, sizeof ( raw_buf ) ); - return uri_encode ( raw_buf, buf, len ); + return uri_encode ( raw_buf, buf, len, URI_FRAGMENT ); } } @@ -1180,7 +1426,7 @@ struct setting filename_setting __setting = { /** Root path setting */ struct setting root_path_setting __setting = { .name = "root-path", - .description = "NFS/iSCSI root path", + .description = "iSCSI root path", .tag = DHCP_ROOT_PATH, .type = &setting_type_string, }; diff --git a/gpxe/src/core/string.c b/gpxe/src/core/string.c index 2e17bdcb..190007a4 100644 --- a/gpxe/src/core/string.c +++ b/gpxe/src/core/string.c @@ -10,6 +10,8 @@ * published by the Free Software Foundation. */ +FILE_LICENCE ( GPL2_ONLY ); + /* * stupid library routines.. The optimized versions should generally be found * as inline code in <asm-xx/string.h> diff --git a/gpxe/src/core/timer.c b/gpxe/src/core/timer.c index d71e3da1..096d07ec 100644 --- a/gpxe/src/core/timer.c +++ b/gpxe/src/core/timer.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <unistd.h> /** diff --git a/gpxe/src/core/uri.c b/gpxe/src/core/uri.c index 7bb46da0..6a1f2e59 100644 --- a/gpxe/src/core/uri.c +++ b/gpxe/src/core/uri.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** @file * * Uniform Resource Identifiers @@ -74,6 +76,7 @@ struct uri * parse_uri ( const char *uri_string ) { char *tmp; char *path = NULL; char *authority = NULL; + int i; size_t raw_len; /* Allocate space for URI struct and a copy of the string */ @@ -83,7 +86,7 @@ struct uri * parse_uri ( const char *uri_string ) { return NULL; raw = ( ( ( char * ) uri ) + sizeof ( *uri ) ); - /* Zero URI struct and copy in the raw string */ + /* Copy in the raw string */ memcpy ( raw, uri_string, raw_len ); /* Start by chopping off the fragment, if it exists */ @@ -169,6 +172,14 @@ struct uri * parse_uri ( const char *uri_string ) { uri->port = tmp; } + /* Decode fields that should be decoded */ + for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) { + const char *field = uri_get_field ( uri, i ); + if ( field && ( URI_ENCODED & ( 1 << i ) ) ) + uri_decode ( field, ( char * ) field, + strlen ( field ) + 1 /* NUL */ ); + } + done: DBG ( "URI \"%s\" split into", uri_string ); dump_uri ( uri ); @@ -196,71 +207,65 @@ unsigned int uri_port ( struct uri *uri, unsigned int default_port ) { * @v buf Buffer to fill with URI string * @v size Size of buffer * @v uri URI to write into buffer, or NULL + * @v fields Bitmask of fields to include in URI string, or URI_ALL * @ret len Length of URI string */ -int unparse_uri ( char *buf, size_t size, struct uri *uri ) { +int unparse_uri ( char *buf, size_t size, struct uri *uri, + unsigned int fields ) { + /* List of characters that typically go before certain fields */ + static char separators[] = { /* scheme */ 0, /* opaque */ ':', + /* user */ 0, /* password */ ':', + /* host */ '@', /* port */ ':', + /* path */ 0, /* query */ '?', + /* fragment */ '#' }; int used = 0; + int i; DBG ( "URI unparsing" ); dump_uri ( uri ); DBG ( "\n" ); + /* Ensure buffer is NUL-terminated */ + if ( size ) + buf[0] = '\0'; + /* Special-case NULL URI */ - if ( ! uri ) { - if ( size ) - buf[0] = '\0'; + if ( ! uri ) return 0; - } - - /* Special-case opaque URIs */ - if ( uri->opaque ) { - return ssnprintf ( ( buf + used ), ( size - used ), - "%s:%s", uri->scheme, uri->opaque ); - } - /* scheme:// */ - if ( uri->scheme ) { - used += ssnprintf ( ( buf + used ), ( size - used ), - "%s://", uri->scheme ); - } - - /* [user[:password]@]host[:port] */ - if ( uri->host ) { - if ( uri->user ) { - used += ssnprintf ( ( buf + used ), ( size - used ), - "%s", uri->user ); - if ( uri->password ) { - used += ssnprintf ( ( buf + used ), - ( size - used ), - ":%s", uri->password ); + /* Iterate through requested fields */ + for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) { + const char *field = uri_get_field ( uri, i ); + char sep = separators[i]; + + /* Ensure `fields' only contains bits for fields that exist */ + if ( ! field ) + fields &= ~( 1 << i ); + + /* Store this field if we were asked to */ + if ( fields & ( 1 << i ) ) { + /* Print :// if we're non-opaque and had a scheme */ + if ( ( fields & URI_SCHEME_BIT ) && + ( i > URI_OPAQUE ) ) { + used += ssnprintf ( buf + used, size - used, + "://" ); + /* Only print :// once */ + fields &= ~URI_SCHEME_BIT; } - used += ssnprintf ( ( buf + used ), ( size - used ), - "@" ); - } - used += ssnprintf ( ( buf + used ), ( size - used ), "%s", - uri->host ); - if ( uri->port ) { - used += ssnprintf ( ( buf + used ), ( size - used ), - ":%s", uri->port ); - } - } - - /* /path */ - if ( uri->path ) { - used += ssnprintf ( ( buf + used ), ( size - used ), - "%s", uri->path ); - } - /* ?query */ - if ( uri->query ) { - used += ssnprintf ( ( buf + used ), ( size - used ), - "?%s", uri->query ); - } - - /* #fragment */ - if ( uri->fragment ) { - used += ssnprintf ( ( buf + used ), ( size - used ), - "#%s", uri->fragment ); + /* Only print separator if an earlier field exists */ + if ( sep && ( fields & ( ( 1 << i ) - 1 ) ) ) + used += ssnprintf ( buf + used, size - used, + "%c", sep ); + + /* Print contents of field, possibly encoded */ + if ( URI_ENCODED & ( 1 << i ) ) + used += uri_encode ( field, buf + used, + size - used, i ); + else + used += ssnprintf ( buf + used, size - used, + "%s", field ); + } } return used; @@ -275,10 +280,10 @@ int unparse_uri ( char *buf, size_t size, struct uri *uri ) { * Creates a modifiable copy of a URI. */ struct uri * uri_dup ( struct uri *uri ) { - size_t len = ( unparse_uri ( NULL, 0, uri ) + 1 ); + size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 ); char buf[len]; - unparse_uri ( buf, len, uri ); + unparse_uri ( buf, len, uri, URI_ALL ); return parse_uri ( buf ); } @@ -391,16 +396,31 @@ struct uri * resolve_uri ( struct uri *base_uri, * Test for unreserved URI characters * * @v c Character to test + * @v field Field of URI in which character lies * @ret is_unreserved Character is an unreserved character */ -static int is_unreserved_uri_char ( int c ) { +static int is_unreserved_uri_char ( int c, int field ) { /* According to RFC3986, the unreserved character set is * * A-Z a-z 0-9 - _ . ~ + * + * but we also pass & ; = in queries, / in paths, + * and everything in opaques */ - return ( isupper ( c ) || islower ( c ) || isdigit ( c ) || - ( c == '-' ) || ( c == '_' ) || - ( c == '.' ) || ( c == '~' ) ); + int ok = ( isupper ( c ) || islower ( c ) || isdigit ( c ) || + ( c == '-' ) || ( c == '_' ) || + ( c == '.' ) || ( c == '~' ) ); + + if ( field == URI_QUERY ) + ok = ok || ( c == ';' ) || ( c == '&' ) || ( c == '=' ); + + if ( field == URI_PATH ) + ok = ok || ( c == '/' ); + + if ( field == URI_OPAQUE ) + ok = 1; + + return ok; } /** @@ -409,18 +429,20 @@ static int is_unreserved_uri_char ( int c ) { * @v raw_string String to be URI-encoded * @v buf Buffer to contain encoded string * @v len Length of buffer + * @v field Field of URI in which string lies * @ret len Length of encoded string (excluding NUL) */ -size_t uri_encode ( const char *raw_string, char *buf, size_t len ) { +size_t uri_encode ( const char *raw_string, char *buf, ssize_t len, + int field ) { ssize_t remaining = len; size_t used; unsigned char c; - if ( len ) + if ( len > 0 ) buf[0] = '\0'; while ( ( c = *(raw_string++) ) ) { - if ( is_unreserved_uri_char ( c ) ) { + if ( is_unreserved_uri_char ( c, field ) ) { used = ssnprintf ( buf, remaining, "%c", c ); } else { used = ssnprintf ( buf, remaining, "%%%02X", c ); @@ -439,17 +461,17 @@ size_t uri_encode ( const char *raw_string, char *buf, size_t len ) { * @v buf Buffer to contain decoded string * @v len Length of buffer * @ret len Length of decoded string (excluding NUL) + * + * This function may be used in-place, with @a buf the same as + * @a encoded_string. */ -size_t uri_decode ( const char *encoded_string, char *buf, size_t len ) { - ssize_t remaining = len; +size_t uri_decode ( const char *encoded_string, char *buf, ssize_t len ) { + ssize_t remaining; char hexbuf[3]; char *hexbuf_end; unsigned char c; - if ( len ) - buf[0] = '\0'; - - while ( *encoded_string ) { + for ( remaining = len; *encoded_string; remaining-- ) { if ( *encoded_string == '%' ) { encoded_string++; snprintf ( hexbuf, sizeof ( hexbuf ), "%s", @@ -459,7 +481,12 @@ size_t uri_decode ( const char *encoded_string, char *buf, size_t len ) { } else { c = *(encoded_string++); } - ssnprintf ( buf++, remaining--, "%c", c ); + if ( remaining > 1 ) + *buf++ = c; } + + if ( len ) + *buf = 0; + return ( len - remaining ); } diff --git a/gpxe/src/core/uuid.c b/gpxe/src/core/uuid.c index a3a82c68..2b67d55d 100644 --- a/gpxe/src/core/uuid.c +++ b/gpxe/src/core/uuid.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stdio.h> #include <byteswap.h> diff --git a/gpxe/src/core/vsprintf.c b/gpxe/src/core/vsprintf.c index 4457fe4f..21ab2429 100644 --- a/gpxe/src/core/vsprintf.c +++ b/gpxe/src/core/vsprintf.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stddef.h> #include <stdarg.h> #include <stdio.h> diff --git a/gpxe/src/core/xfer.c b/gpxe/src/core/xfer.c index 9ed19da2..1ec6f9d3 100644 --- a/gpxe/src/core/xfer.c +++ b/gpxe/src/core/xfer.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <stdio.h> #include <errno.h> @@ -43,11 +45,14 @@ static struct xfer_metadata dummy_metadata; */ void xfer_close ( struct xfer_interface *xfer, int rc ) { struct xfer_interface *dest = xfer_get_dest ( xfer ); + struct xfer_interface_operations *op = xfer->op; DBGC ( xfer, "XFER %p->%p close\n", xfer, dest ); xfer_unplug ( xfer ); + xfer_nullify ( xfer ); dest->op->close ( dest, rc ); + xfer->op = op; xfer_put ( dest ); } diff --git a/gpxe/src/crypto/aes_wrap.c b/gpxe/src/crypto/aes_wrap.c new file mode 100644 index 00000000..d7f94af0 --- /dev/null +++ b/gpxe/src/crypto/aes_wrap.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdlib.h> +#include <string.h> +#include <gpxe/crypto.h> +#include <gpxe/aes.h> + +/** + * Wrap a key or other data using AES Key Wrap (RFC 3394) + * + * @v kek Key Encryption Key, 16 bytes + * @v src Data to encrypt + * @v nblk Number of 8-byte blocks in @a data + * @ret dest Encrypted data (8 bytes longer than input) + * + * The algorithm is implemented such that @a src and @a dest may point + * to the same buffer. + */ +int aes_wrap ( const void *kek, const void *src, void *dest, int nblk ) +{ + u8 *A = dest; + u8 B[16]; + u8 *R; + int i, j; + void *aes_ctx = malloc ( AES_CTX_SIZE ); + + if ( ! aes_ctx ) + return -1; + + cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 ); + + /* Set up */ + memset ( A, 0xA6, sizeof ( A ) ); + memmove ( dest + 8, src, nblk * 8 ); + + /* Wrap */ + for ( j = 0; j < 6; j++ ) { + R = dest + 8; + for ( i = 1; i <= nblk; i++ ) { + memcpy ( B, A, 8 ); + memcpy ( B + 8, R, 8 ); + cipher_encrypt ( &aes_algorithm, aes_ctx, B, B, 16 ); + memcpy ( A, B, 8 ); + A[7] ^= ( nblk * j ) + i; + memcpy ( R, B + 8, 8 ); + R += 8; + } + } + + free ( aes_ctx ); + return 0; +} + +/** + * Unwrap a key or other data using AES Key Wrap (RFC 3394) + * + * @v kek Key Encryption Key, 16 bytes + * @v src Data to decrypt + * @v nblk Number of 8-byte blocks in @e plaintext key + * @ret dest Decrypted data (8 bytes shorter than input) + * @ret rc Zero on success, nonzero on IV mismatch + * + * The algorithm is implemented such that @a src and @a dest may point + * to the same buffer. + */ +int aes_unwrap ( const void *kek, const void *src, void *dest, int nblk ) +{ + u8 A[8], B[16]; + u8 *R; + int i, j; + void *aes_ctx = malloc ( AES_CTX_SIZE ); + + if ( ! aes_ctx ) + return -1; + + cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 ); + + /* Set up */ + memcpy ( A, src, 8 ); + memmove ( dest, src + 8, nblk * 8 ); + + /* Unwrap */ + for ( j = 5; j >= 0; j-- ) { + R = dest + ( nblk - 1 ) * 8; + for ( i = nblk; i >= 1; i-- ) { + memcpy ( B, A, 8 ); + memcpy ( B + 8, R, 8 ); + B[7] ^= ( nblk * j ) + i; + cipher_decrypt ( &aes_algorithm, aes_ctx, B, B, 16 ); + memcpy ( A, B, 8 ); + memcpy ( R, B + 8, 8 ); + R -= 8; + } + } + + free ( aes_ctx ); + + /* Check IV */ + for ( i = 0; i < 8; i++ ) { + if ( A[i] != 0xA6 ) + return -1; + } + + return 0; +} diff --git a/gpxe/src/crypto/arc4.c b/gpxe/src/crypto/arc4.c new file mode 100644 index 00000000..e58fba7c --- /dev/null +++ b/gpxe/src/crypto/arc4.c @@ -0,0 +1,131 @@ +/* + * The ARC4 stream cipher. + * + * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/crypto.h> +#include <gpxe/arc4.h> + +#define SWAP( ary, i, j ) \ + ({ u8 temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; }) + +/** + * Set ARC4 key + * + * @v ctxv ARC4 encryption context + * @v keyv Key to set + * @v keylen Length of key + * + * If an initialisation vector is to be used, it should be prepended + * to the key; ARC4 does not implement the @c setiv function because + * there is no standard length for an initialisation vector in the + * cipher. + */ +static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen ) +{ + struct arc4_ctx *ctx = ctxv; + const u8 *key = keyv; + u8 *S = ctx->state; + int i, j; + + for ( i = 0; i < 256; i++ ) { + S[i] = i; + } + + for ( i = j = 0; i < 256; i++ ) { + j = ( j + S[i] + key[i % keylen] ) & 0xff; + SWAP ( S, i, j ); + } + + ctx->i = ctx->j = 0; + return 0; +} + +/** + * Perform ARC4 encryption or decryption + * + * @v ctxv ARC4 encryption context + * @v srcv Data to encrypt or decrypt + * @v dstv Location to store encrypted or decrypted data + * @v len Length of data to operate on + * + * ARC4 is a stream cipher that works by generating a stream of PRNG + * data based on the key, and XOR'ing it with the data to be + * encrypted. Since XOR is symmetric, encryption and decryption in + * ARC4 are the same operation. + * + * If you pass a @c NULL source or destination pointer, @a len + * keystream bytes will be consumed without encrypting any data. + */ +static void arc4_xor ( void *ctxv, const void *srcv, void *dstv, + size_t len ) +{ + struct arc4_ctx *ctx = ctxv; + const u8 *src = srcv; + u8 *dst = dstv; + u8 *S = ctx->state; + int i = ctx->i, j = ctx->j; + + while ( len-- ) { + i = ( i + 1 ) & 0xff; + j = ( j + S[i] ) & 0xff; + SWAP ( S, i, j ); + if ( srcv && dstv ) + *dst++ = *src++ ^ S[(S[i] + S[j]) & 0xff]; + } + + ctx->i = i; + ctx->j = j; +} + +static void arc4_setiv ( void *ctx __unused, const void *iv __unused ) +{ + /* ARC4 does not use a fixed-length IV */ +} + + +/** + * Perform ARC4 encryption or decryption, skipping initial keystream bytes + * + * @v key ARC4 encryption key + * @v keylen Key length + * @v skip Number of bytes of keystream to skip + * @v src Message to encrypt or decrypt + * @v msglen Length of message + * @ret dst Encrypted or decrypted message + */ +void arc4_skip ( const void *key, size_t keylen, size_t skip, + const void *src, void *dst, size_t msglen ) +{ + struct arc4_ctx ctx; + arc4_setkey ( &ctx, key, keylen ); + arc4_xor ( &ctx, NULL, NULL, skip ); + arc4_xor ( &ctx, src, dst, msglen ); +} + +struct cipher_algorithm arc4_algorithm = { + .name = "ARC4", + .ctxsize = ARC4_CTX_SIZE, + .blocksize = 1, + .setkey = arc4_setkey, + .setiv = arc4_setiv, + .encrypt = arc4_xor, + .decrypt = arc4_xor, +}; diff --git a/gpxe/src/crypto/asn1.c b/gpxe/src/crypto/asn1.c index 25e7495b..154a8a84 100644 --- a/gpxe/src/crypto/asn1.c +++ b/gpxe/src/crypto/asn1.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <stddef.h> #include <errno.h> diff --git a/gpxe/src/crypto/axtls_aes.c b/gpxe/src/crypto/axtls_aes.c index 51e1924e..8bd37586 100644 --- a/gpxe/src/crypto/axtls_aes.c +++ b/gpxe/src/crypto/axtls_aes.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <errno.h> #include <byteswap.h> @@ -30,17 +32,6 @@ * */ -/** Basic AES blocksize */ -#define AES_BLOCKSIZE 16 - -/** AES context */ -struct aes_context { - /** AES context for AXTLS */ - AES_CTX axtls_ctx; - /** Cipher is being used for decrypting */ - int decrypting; -}; - /** * Set key * @@ -152,7 +143,7 @@ static void aes_decrypt ( void *ctx, const void *src, void *dst, } /** Basic AES algorithm */ -static struct cipher_algorithm aes_algorithm = { +struct cipher_algorithm aes_algorithm = { .name = "aes", .ctxsize = sizeof ( struct aes_context ), .blocksize = AES_BLOCKSIZE, diff --git a/gpxe/src/crypto/cbc.c b/gpxe/src/crypto/cbc.c index c7116ea9..1710203c 100644 --- a/gpxe/src/crypto/cbc.c +++ b/gpxe/src/crypto/cbc.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> #include <assert.h> #include <gpxe/crypto.h> diff --git a/gpxe/src/crypto/chap.c b/gpxe/src/crypto/chap.c index d0784d25..8aa224c4 100644 --- a/gpxe/src/crypto/chap.c +++ b/gpxe/src/crypto/chap.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stddef.h> #include <stdlib.h> #include <string.h> diff --git a/gpxe/src/crypto/crandom.c b/gpxe/src/crypto/crandom.c new file mode 100644 index 00000000..9828482e --- /dev/null +++ b/gpxe/src/crypto/crandom.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Cryptographically strong random number generator + * + * Currently the cryptographic part is not implemented, and this just + * uses random(). + */ + +#include <gpxe/crypto.h> +#include <stdlib.h> + +/** + * Get cryptographically strong random bytes + * + * @v buf Buffer in which to store random bytes + * @v len Number of random bytes to generate + * + * @b WARNING: This function is currently underimplemented, and does + * not give numbers any stronger than random()! + */ +void get_random_bytes ( void *buf, size_t len ) +{ + u8 *bufp = buf; + + /* + * Somewhat arbitrarily, choose the 0x00FF0000-masked byte + * returned by random() as having good entropy. PRNGs often + * don't provide good entropy in lower bits, and the top byte + * might show a pattern because of sign issues. + */ + + while ( len-- ) { + *bufp++ = ( random() >> 16 ) & 0xFF; + } +} diff --git a/gpxe/src/crypto/crc32.c b/gpxe/src/crypto/crc32.c new file mode 100644 index 00000000..0cc314e8 --- /dev/null +++ b/gpxe/src/crypto/crc32.c @@ -0,0 +1,54 @@ +/* + * Little-endian CRC32 implementation. + * + * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/crc32.h> + +#define CRCPOLY 0xedb88320 + +/** + * Calculate 32-bit little-endian CRC checksum + * + * @v seed Initial value + * @v data Data to checksum + * @v len Length of data + * + * Usually @a seed is initially zero or all one bits, depending on the + * protocol. To continue a CRC checksum over multiple calls, pass the + * return value from one call as the @a seed parameter to the next. + */ +u32 crc32_le ( u32 seed, const void *data, size_t len ) +{ + u32 crc = seed; + const u8 *src = data; + u32 mult; + int i; + + while ( len-- ) { + crc ^= *src++; + for ( i = 0; i < 8; i++ ) { + mult = ( crc & 1 ) ? CRCPOLY : 0; + crc = ( crc >> 1 ) ^ mult; + } + } + + return crc; +} diff --git a/gpxe/src/crypto/crypto_null.c b/gpxe/src/crypto/crypto_null.c index 8cc9217a..61efb34e 100644 --- a/gpxe/src/crypto/crypto_null.c +++ b/gpxe/src/crypto/crypto_null.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/crypto/hmac.c b/gpxe/src/crypto/hmac.c index be0298a7..d64730c0 100644 --- a/gpxe/src/crypto/hmac.c +++ b/gpxe/src/crypto/hmac.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /** * @file * diff --git a/gpxe/src/crypto/md5.c b/gpxe/src/crypto/md5.c index 76fb8a69..8c606398 100644 --- a/gpxe/src/crypto/md5.c +++ b/gpxe/src/crypto/md5.c @@ -20,36 +20,36 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> #include <string.h> #include <byteswap.h> #include <gpxe/crypto.h> #include <gpxe/md5.h> -#define __md5step __attribute__ (( regparm ( 3 ) )) - struct md5_step { - u32 __md5step ( * f ) ( u32 b, u32 c, u32 d ); + u32 ( * f ) ( u32 b, u32 c, u32 d ); u8 coefficient; u8 constant; }; -static u32 __md5step f1(u32 b, u32 c, u32 d) +static u32 f1(u32 b, u32 c, u32 d) { return ( d ^ ( b & ( c ^ d ) ) ); } -static u32 __md5step f2(u32 b, u32 c, u32 d) +static u32 f2(u32 b, u32 c, u32 d) { return ( c ^ ( d & ( b ^ c ) ) ); } -static u32 __md5step f3(u32 b, u32 c, u32 d) +static u32 f3(u32 b, u32 c, u32 d) { return ( b ^ c ^ d ); } -static u32 __md5step f4(u32 b, u32 c, u32 d) +static u32 f4(u32 b, u32 c, u32 d) { return ( c ^ ( b | ~d ) ); } diff --git a/gpxe/src/crypto/sha1extra.c b/gpxe/src/crypto/sha1extra.c new file mode 100644 index 00000000..c144a0f6 --- /dev/null +++ b/gpxe/src/crypto/sha1extra.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <gpxe/crypto.h> +#include <gpxe/sha1.h> +#include <gpxe/hmac.h> +#include <stdint.h> +#include <byteswap.h> + +/** + * SHA1 pseudorandom function for creating derived keys + * + * @v key Master key with which this call is associated + * @v key_len Length of key + * @v label NUL-terminated ASCII string describing purpose of PRF data + * @v data Further data that should be included in the PRF + * @v data_len Length of further PRF data + * @v prf_len Bytes of PRF to generate + * @ret prf Pseudorandom function bytes + * + * This is the PRF variant used by 802.11, defined in IEEE 802.11-2007 + * 8.5.5.1. EAP-FAST uses a different SHA1-based PRF, and TLS uses an + * MD5-based PRF. + */ +void prf_sha1 ( const void *key, size_t key_len, const char *label, + const void *data, size_t data_len, void *prf, size_t prf_len ) +{ + u32 blk; + u8 keym[key_len]; /* modifiable copy of key */ + u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */ + u8 *in_blknr; /* pointer to last byte of in, block number */ + u8 out[SHA1_SIZE]; /* HMAC-SHA1 result */ + u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */ + const size_t label_len = strlen ( label ); + + /* The HMAC-SHA-1 is calculated using the given key on the + message text `label', followed by a NUL, followed by one + byte indicating the block number (0 for first). */ + + memcpy ( keym, key, key_len ); + + memcpy ( in, label, strlen ( label ) + 1 ); + memcpy ( in + label_len + 1, data, data_len ); + in_blknr = in + label_len + 1 + data_len; + + for ( blk = 0 ;; blk++ ) { + *in_blknr = blk; + + hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len ); + hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) ); + hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out ); + + if ( prf_len <= SHA1_SIZE ) { + memcpy ( prf, out, prf_len ); + break; + } + + memcpy ( prf, out, SHA1_SIZE ); + prf_len -= SHA1_SIZE; + prf += SHA1_SIZE; + } +} + +/** + * PBKDF2 key derivation function inner block operation + * + * @v passphrase Passphrase from which to derive key + * @v pass_len Length of passphrase + * @v salt Salt to include in key + * @v salt_len Length of salt + * @v iterations Number of iterations of SHA1 to perform + * @v blocknr Index of this block, starting at 1 + * @ret block SHA1_SIZE bytes of PBKDF2 data + * + * The operation of this function is described in RFC 2898. + */ +static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len, + const void *salt, size_t salt_len, + int iterations, u32 blocknr, u8 *block ) +{ + u8 pass[pass_len]; /* modifiable passphrase */ + u8 in[salt_len + 4]; /* input buffer to first round */ + u8 last[SHA1_SIZE]; /* output of round N, input of N+1 */ + u8 sha1_ctx[SHA1_CTX_SIZE]; + u8 *next_in = in; /* changed to `last' after first round */ + int next_size = sizeof ( in ); + int i, j; + + blocknr = htonl ( blocknr ); + + memcpy ( pass, passphrase, pass_len ); + memcpy ( in, salt, salt_len ); + memcpy ( in + salt_len, &blocknr, 4 ); + memset ( block, 0, SHA1_SIZE ); + + for ( i = 0; i < iterations; i++ ) { + hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len ); + hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size ); + hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last ); + + for ( j = 0; j < SHA1_SIZE; j++ ) { + block[j] ^= last[j]; + } + + next_in = last; + next_size = SHA1_SIZE; + } +} + +/** + * PBKDF2 key derivation function using SHA1 + * + * @v passphrase Passphrase from which to derive key + * @v pass_len Length of passphrase + * @v salt Salt to include in key + * @v salt_len Length of salt + * @v iterations Number of iterations of SHA1 to perform + * @v key_len Length of key to generate + * @ret key Generated key bytes + * + * This is used most notably in 802.11 WPA passphrase hashing, in + * which case the salt is the SSID, 4096 iterations are used, and a + * 32-byte key is generated that serves as the Pairwise Master Key for + * EAPOL authentication. + * + * The operation of this function is further described in RFC 2898. + */ +void pbkdf2_sha1 ( const void *passphrase, size_t pass_len, + const void *salt, size_t salt_len, + int iterations, void *key, size_t key_len ) +{ + u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE; + u32 blk; + u8 buf[SHA1_SIZE]; + + for ( blk = 1; blk <= blocks; blk++ ) { + pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len, + iterations, blk, buf ); + if ( key_len <= SHA1_SIZE ) { + memcpy ( key, buf, key_len ); + break; + } + + memcpy ( key, buf, SHA1_SIZE ); + key_len -= SHA1_SIZE; + key += SHA1_SIZE; + } +} diff --git a/gpxe/src/crypto/x509.c b/gpxe/src/crypto/x509.c index 35adfa38..31ed412f 100644 --- a/gpxe/src/crypto/x509.c +++ b/gpxe/src/crypto/x509.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdlib.h> #include <string.h> #include <errno.h> diff --git a/gpxe/src/doc/pxe_extensions b/gpxe/src/doc/pxe_extensions index 92269cfc..8ff14a95 100644 --- a/gpxe/src/doc/pxe_extensions +++ b/gpxe/src/doc/pxe_extensions @@ -277,3 +277,36 @@ Provider: Set to 0x45585067 ("gPXE"). Another implementation of this APIMask: Bitmask of supported API functions (one bit for each function in the range 00e0h to 00ffh). Flags: Set to zero, reserved for future use. + + + + +FILE EXIT HOOK + +Op-Code: PXENV_FILE_EXIT_HOOK (00e7h) + +Input: Far pointer to a t_PXENV_FILE_EXIT_HOOK parameter + structure that has been initialized by the caller. + +Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be + returned in AX. The Status field in the parameter + structure must be set to one of the values represented + by the PXENV_STATUS_xxx constants. + +Description: Modify the exit path to jump to the specified code. + Only valid for pxeprefix-based builds. + +typedef struct s_PXENV_FILE_EXIT_HOOK { + PXENV_STATUS_t Status; + SEGOFF16_t Hook; +} t_PXENV_FILE_EXIT_HOOK; + + +Set before calling API service: + +Hook: The SEG16:OFF16 of the code to jump to. + + +Returned from API service: + +Status: See PXENV_STATUS_xxx constants. diff --git a/gpxe/src/doxygen.cfg b/gpxe/src/doxygen.cfg index 5c429094..0ee87ad9 100644 --- a/gpxe/src/doxygen.cfg +++ b/gpxe/src/doxygen.cfg @@ -1,4 +1,4 @@ -# Doxyfile 1.4.4 +# Doxyfile 1.5.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project @@ -14,10 +14,18 @@ # Project related configuration options #--------------------------------------------------------------------------- +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. -PROJECT_NAME = Etherboot +PROJECT_NAME = gPXE # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or @@ -45,24 +53,15 @@ CREATE_SUBDIRS = NO # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: -# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, -# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, -# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, -# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, -# Swedish, and Ukrainian. +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English -# This tag can be used to specify the encoding used in the generated output. -# The encoding is not always determined by the language that is chosen, -# but also whether or not the output is meant for Windows or non-Windows users. -# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES -# forces the Windows encoding (this is the default for the Windows binary), -# whereas setting the tag to NO uses a Unix-style encoding (the default for -# all platforms other than Windows). - -USE_WINDOWS_ENCODING = NO - # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). @@ -93,7 +92,7 @@ ABBREVIATE_BRIEF = # Doxygen will generate a detailed section even if there is only a brief # description. -ALWAYS_DETAILED_SEC = NO +ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those @@ -106,7 +105,7 @@ INLINE_INHERITED_MEMB = NO # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. -FULL_PATH_NAMES = NO +FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is @@ -135,11 +134,19 @@ SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. @@ -148,26 +155,12 @@ JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = YES - # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. @@ -197,13 +190,61 @@ ALIASES = v=@param \ OPTIMIZE_OUTPUT_FOR_C = YES -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources -# only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to @@ -212,6 +253,32 @@ OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -221,7 +288,7 @@ SUBGROUPING = YES # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES -EXTRACT_ALL = NO +EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. @@ -246,6 +313,14 @@ EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the @@ -300,7 +375,7 @@ HIDE_SCOPE_NAMES = NO # will put a list of the files that are included by a file in the documentation # of that file. -SHOW_INCLUDE_FILES = NO +SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. @@ -321,6 +396,12 @@ SORT_MEMBER_DOCS = NO SORT_BRIEF_DOCS = NO +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, @@ -378,20 +459,41 @@ SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is YES. +# in the documentation. The default is NO. SHOW_DIRECTORIES = YES +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + # The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via # popen()) the command <command> <input-file>, where <command> is the value of # the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the progam writes to standard output +# provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -426,7 +528,7 @@ WARN_IF_DOC_ERROR = YES # wrong or incomplete parameter documentation, but not about the absence of # documentation. -WARN_NO_PARAMDOC = NO +WARN_NO_PARAMDOC = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text @@ -453,28 +555,34 @@ WARN_LOGFILE = # with spaces. INPUT = @SRCDIRS@ \ - include \ - include/gpxe \ - arch/@ARCH@/include \ + @INCDIRS@ \ + config \ doc +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.c \ *.h \ - *.S \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. -RECURSIVE = NO +RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a @@ -496,6 +604,14 @@ EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). @@ -561,7 +677,7 @@ SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. -INLINE_SOURCES = NO +INLINE_SOURCES = YES # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code @@ -569,17 +685,24 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = NO -# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES -# If the REFERENCES_RELATION tag is set to YES (the default) +# If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. -REFERENCES_RELATION = NO +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen @@ -666,9 +789,43 @@ HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO @@ -693,6 +850,12 @@ HHC_LOCATION = GENERATE_CHI = NO +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. @@ -702,7 +865,39 @@ BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. -TOC_EXPAND = NO +TOC_EXPAND = YES + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#namespace">Qt Help Project / Namespace</a>. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and @@ -715,14 +910,22 @@ DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = NONE # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree @@ -730,6 +933,14 @@ GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- @@ -737,7 +948,7 @@ TREEVIEW_WIDTH = 250 # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. -GENERATE_LATEX = YES +GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be @@ -855,7 +1066,7 @@ RTF_EXTENSIONS_FILE = # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages -GENERATE_MAN = YES +GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be @@ -975,7 +1186,7 @@ MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. +# PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = YES @@ -988,8 +1199,7 @@ SEARCH_INCLUDES = YES # contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = include \ - arch/@ARCH@/include +INCLUDE_PATH = @INCDIRS@ # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1084,13 +1294,22 @@ PERL_PATH = # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. -CLASS_DIAGRAMS = YES +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. -HIDE_UNDOC_RELATIONS = YES +HIDE_UNDOC_RELATIONS = NO # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization @@ -1099,6 +1318,29 @@ HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the @@ -1143,14 +1385,22 @@ INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. CALL_GRAPH = NO +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. @@ -1180,39 +1430,31 @@ DOT_PATH = DOTFILE_DIRS = -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. -MAX_DOT_GRAPH_HEIGHT = 1024 +DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that a graph may be further truncated if the graph's -# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH -# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), -# the graph is not depth-constrained. +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly |