diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-09-05 20:35:53 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-09-05 20:35:53 +0900 |
commit | 16b1353a36171ae06d63fd309f4772dbfb1da113 (patch) | |
tree | cf6c297ee81aba0d9b47f23d78a889667e7bce48 /roms/ipxe | |
parent | a15119db2ff5c2fdfdeb913b297bf8aa3399132e (diff) | |
download | qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.gz qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.tar.bz2 qemu-16b1353a36171ae06d63fd309f4772dbfb1da113.zip |
Imported Upstream version 2.1.0upstream/2.1.0
Diffstat (limited to 'roms/ipxe')
491 files changed, 40297 insertions, 14521 deletions
diff --git a/roms/ipxe/contrib/errdb/errdb.pl b/roms/ipxe/contrib/errdb/errdb.pl index fc1919f6d..6423d8347 100755 --- a/roms/ipxe/contrib/errdb/errdb.pl +++ b/roms/ipxe/contrib/errdb/errdb.pl @@ -73,6 +73,7 @@ my $xrefs = {}; while ( <> ) { chomp; ( my $errno, my $filename, my $line, my $description ) = split ( /\t/ ); + $errno = substr ( $errno, 0, 6 ) unless $errno =~ /^7f/; $errors->{$errno} = $description; $xrefs->{$errno} ||= {}; $xrefs->{$errno}->{$filename} ||= {}; diff --git a/roms/ipxe/src/Makefile b/roms/ipxe/src/Makefile index e240f4ced..ea987b84c 100644 --- a/roms/ipxe/src/Makefile +++ b/roms/ipxe/src/Makefile @@ -34,6 +34,7 @@ OBJCOPY := $(CROSS_COMPILE)objcopy NM := $(CROSS_COMPILE)nm OBJDUMP := $(CROSS_COMPILE)objdump OPENSSL := openssl +CSPLIT := csplit PARSEROM := ./util/parserom.pl FIXROM := ./util/fixrom.pl SYMCHECK := ./util/symcheck.pl @@ -49,6 +50,7 @@ ICCFIX := ./util/iccfix EINFO := ./util/einfo GENKEYMAP := ./util/genkeymap.pl DOXYGEN := doxygen +LCAB := lcab BINUTILS_DIR := /usr BFD_DIR := $(BINUTILS_DIR) ZLIB_DIR := /usr @@ -60,7 +62,7 @@ ZLIB_DIR := /usr SRCDIRS := SRCDIRS += libgcc SRCDIRS += core -SRCDIRS += net net/tcp net/udp net/infiniband net/80211 +SRCDIRS += net net/oncrpc net/tcp net/udp net/infiniband net/80211 SRCDIRS += image SRCDIRS += drivers/bus SRCDIRS += drivers/net @@ -107,7 +109,11 @@ INCDIRS += include . # helpfully suggestive message # ALL := bin/blib.a bin/ipxe.dsk bin/ipxe.lkrn bin/ipxe.iso \ - bin/ipxe.usb bin/undionly.kpxe bin/rtl8139.rom + bin/ipxe.usb bin/ipxe.pxe bin/undionly.kpxe bin/rtl8139.rom \ + bin/8086100e.mrom bin/80861209.rom bin/10500940.rom \ + bin/10222000.rom bin/10ec8139.rom bin/1af41000.rom \ + bin/8086100f.mrom bin/808610d3.mrom bin/15ad07b0.rom + all : $(ALL) @$(ECHO) '===========================================================' @$(ECHO) @@ -148,6 +154,23 @@ everything : ############################################################################### # +# VMware build target: all ROMs used with VMware +# +vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom + @$(ECHO) '===========================================================' + @$(ECHO) + @$(ECHO) 'Available ROMs:' + @$(ECHO) ' bin/8086100f.mrom -- intel/e1000' + @$(ECHO) ' bin/808610d3.mrom -- intel/e1000e' + @$(ECHO) ' bin/10222000.rom -- vlance/pcnet32' + @$(ECHO) ' bin/15ad07b0.rom -- vmxnet3' + @$(ECHO) + @$(ECHO) 'For more information, see http://ipxe.org/howto/vmware' + @$(ECHO) + @$(ECHO) '===========================================================' + +############################################################################### +# # Build targets that do nothing but might be tried by users # configure : diff --git a/roms/ipxe/src/Makefile.housekeeping b/roms/ipxe/src/Makefile.housekeeping index d40f226f6..e240a7386 100644 --- a/roms/ipxe/src/Makefile.housekeeping +++ b/roms/ipxe/src/Makefile.housekeeping @@ -115,6 +115,18 @@ endif ############################################################################### # +# Check if $(eval ...) is available to use +# + +HAVE_EVAL := +ifndef NO_EVAL +$(eval HAVE_EVAL := yes) +endif +eval : + @$(ECHO) $(HAVE_EVAL) + +############################################################################### +# # Check for various tool workarounds # @@ -128,13 +140,11 @@ WORKAROUND_LDFLAGS := COMMA := , EMPTY := SPACE := $(EMPTY) $(EMPTY) +HASH := \# +define NEWLINE -# Check for an old version of gas (binutils 2.9.1) -# -OLDGAS := $(shell $(AS) --version | grep -q '2\.9\.1' && $(ECHO) -DGAS291) -WORKAROUND_CFLAGS += $(OLDGAS) -oldgas : - @$(ECHO) $(oldgas) + +endef # Some widespread patched versions of gcc include -fstack-protector by # default, even when -ffreestanding is specified. We therefore need @@ -202,6 +212,16 @@ endif ############################################################################### # +# Checker +# +ifeq ($(C),1) +export REAL_CC := $(CC) +CC := cgcc +CFLAGS += -Wno-decl +endif + +############################################################################### +# # Set BIN according to whatever was specified on the command line as # the build target. # @@ -473,9 +493,14 @@ CFLAGS += $(FS_FLAGS) $(DS_FLAGS) endif LDFLAGS += --gc-sections +# Force creation of static binaries (required for OpenBSD, does no +# harm on other platforms). +# +LDFLAGS += -static + # compiler.h is needed for our linking and debugging system # -CFLAGS += -include compiler.h +CFLAGS += -include include/compiler.h # CFLAGS for specific object types # @@ -508,14 +533,14 @@ endif # COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) 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_dbg%.o = $(Q)$(COMPILE_c) -DDBGLVL_MAX=$* -c $< -o $@ $(POST_O) RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ PREPROCESS_S = $(CPP) $(CFLAGS) $(CFLAGS_S) $(OBJ_CFLAGS) ASSEMBLE_S = $(AS) $(ASFLAGS) RULE_S = $(Q)$(PREPROCESS_S) $< | $(ASSEMBLE_S) -o $@ -RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -Ddebug_$(subst -,_,$(OBJECT))=$* $< | $(ASSEMBLE_S) -o $@ +RULE_S_to_dbg%.o = $(Q)$(PREPROCESS_S) -DDBGLVL_MAX=$* $< | $(ASSEMBLE_S) -o $@ RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@ DEBUG_TARGETS += dbg%.o c s @@ -535,7 +560,7 @@ ifneq ($(EMBED_OLD),$(EMBED)) $(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST)) endif -$(EMBEDDED_LIST) : +$(EMBEDDED_LIST) : $(MAKEDEPS) VERYCLEANUP += $(EMBEDDED_LIST) @@ -560,7 +585,7 @@ ifneq ($(TRUST_OLD),$(TRUST)) $(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST)) endif -$(TRUSTED_LIST) : +$(TRUSTED_LIST) : $(MAKEDEPS) VERYCLEANUP += $(TRUSTED_LIST) @@ -576,7 +601,7 @@ rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST) CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") -# (Single-element) list of client certificates +# List of embedded certificates # CERT_LIST := $(BIN)/.certificate.list ifeq ($(wildcard $(CERT_LIST)),) @@ -588,28 +613,47 @@ ifneq ($(CERT_OLD),$(CERT)) $(shell $(ECHO) "$(CERT)" > $(CERT_LIST)) endif -$(CERT_LIST) : +$(CERT_LIST) : $(MAKEDEPS) VERYCLEANUP += $(CERT_LIST) -# Embedded client certificate +# Embedded certificates concatenated and then split into one file per +# certificate (even if original files contained certificate chains) # -CERT_INC := $(BIN)/.certificate.der +CERT_FILES := $(subst $(COMMA), ,$(CERT)) +CERT_CONCAT := $(BIN)/.certificates.pem + +ifneq ($(CERT),) + +CERT_COUNT := $(shell grep "BEGIN CERTIFICATE" $(CERT_FILES) | wc -l) + +$(CERT_CONCAT) : $(CERT_FILES) $(CERT_LIST) + $(Q)cat $(CERT_FILES) > $@ + +# We must use an (otherwise unnecessary) pattern rule here to encode +# the fact that one "csplit" command generates multiple targets +CERT_PEMS := $(foreach i,$(call seq,1,$(CERT_COUNT)),\ + $(BIN)/.certificate.pem.$(i)) +$(subst .pem.,.%.,$(CERT_PEMS)) : $(BIN)/.certificates.% + $(Q)$(CSPLIT) -q -n 1 -f $(BIN)/.certificate.pem. $< \ + '/BEGIN CERTIFICATE/' '{*}' -ifdef CERT -$(CERT_INC) : $(CERT) $(CERT_LIST) +CERT_DERS := $(subst .certificate.pem.,.certificate.der.,$(CERT_PEMS)) +$(BIN)/.certificate.der.% : $(BIN)/.certificate.pem.% $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@ -clientcert_DEPS += $(CERT_INC) +CERT_ALL := $(foreach i,$(call seq,1,$(CERT_COUNT)),\ + CERT ( $(i), \"$(word $(i),$(CERT_DERS))\" )) + endif -CLEANUP += $(CERT_INC) +certstore_DEPS += $(CERT_LIST) $(CERT_FILES) $(CERT_PEMS) $(CERT_DERS) -clientcert_DEPS += $(CERT_LIST) +CFLAGS_certstore += -DCERT_ALL="$(CERT_ALL)" -CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"") +CLEANUP += $(BIN)/.certificate.* $(BIN)/.certificates.* -# (Single-element) list of client private keys +# (Single-element) list of private keys # ifdef KEY PRIVKEY := $(KEY) # Maintain backwards compatibility @@ -624,11 +668,11 @@ ifneq ($(PRIVKEY_OLD),$(PRIVKEY)) $(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST)) endif -$(PRIVKEY_LIST) : +$(PRIVKEY_LIST) : $(MAKEDEPS) VERYCLEANUP += $(PRIVKEY_LIST) -# Embedded client private key +# Embedded private key # PRIVKEY_INC := $(BIN)/.private_key.der @@ -636,22 +680,22 @@ ifdef PRIVKEY $(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST) $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@ -clientcert_DEPS += $(PRIVKEY_INC) +privkey_DEPS += $(PRIVKEY_INC) endif -CLEANUP += $(PRIVKEY_INC) +CLEANUP += $(BIN)/.private_key.* -clientcert_DEPS += $(PRIVKEY_LIST) +privkey_DEPS += $(PRIVKEY_LIST) -CFLAGS_clientcert += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"") +CFLAGS_privkey += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"") # These files use .incbin inline assembly to include a binary file. # Unfortunately ccache does not detect this dependency and caches # builds even when the binary file has changed. # -$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC) - -$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC) +$(BIN)/embedded.% : override CC := env CCACHE_DISABLE=1 $(CC) +$(BIN)/certstore.% : override CC := env CCACHE_DISABLE=1 $(CC) +$(BIN)/privkey.% : override CC := env CCACHE_DISABLE=1 $(CC) # Version number # @@ -661,87 +705,122 @@ CFLAGS_version += -DVERSION_MAJOR=$(VERSION_MAJOR) \ -DVERSION="\"$(VERSION)\"" # Make sure the version number gets updated on every git checkout ifneq ($(GITVERSION),) -$(BIN)/version.o : ../.git/index +$(BIN)/version.% : ../.git/index endif # We automatically generate rules for any file mentioned in AUTO_SRCS -# using the following set of templates. It would be cleaner to use -# $(eval ...), but this function exists only in GNU make >= 3.80. +# using the following set of templates. We use $(eval ...) if +# available, otherwise we generate separate Makefile fragments and +# include them. # deps_template : generate dependency list for a given source file # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# +define deps_template_file +$(call deps_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1)))) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # $(2) is the source type (e.g. "c") # $(3) is the source base name (e.g. "rtl8139") # -define deps_template +define deps_template_parts @$(ECHO) " [DEPS] $(1)" @$(MKDIR) -p $(BIN)/deps/$(dir $(1)) $(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \ -Wno-error -M $(1) -MG -MP | \ sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d + $(Q)$(if $(findstring drivers/,$(1)),\ + $(PERL) $(PARSEROM) $(1) >> $(BIN)/deps/$(1).d) endef # rules_template : generate rules for a given source file # # $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# +define rules_template +$(call rules_template_parts,$(1),$(subst .,,$(suffix $(1))),$(basename $(notdir $(1)))) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") # $(2) is the source type (e.g. "c") # $(3) is the source base name (e.g. "rtl8139") # -define rules_template +define rules_template_parts +$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) + $$(QM)$(ECHO) " [BUILD] $$@" + $$(RULE_$(2)) +BOBJS += $$(BIN)/$(3).o +$(foreach TGT,$(DEBUG_TARGETS),$(if $(RULE_$(2)_to_$(TGT)),$(NEWLINE)$(call rules_template_target,$(1),$(2),$(3),$(TGT)))) +$$(BIN)/deps/$(1).d : $$($(3)_DEPS) +TAGS : $$($(3)_DEPS) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# $(2) is the source type (e.g. "c") +# $(3) is the source base name (e.g. "rtl8139") +# $(4) is the destination type (e.g. "dbg%.o") +# +define rules_template_target +$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) + $$(QM)$(ECHO) " [BUILD] $$@" + $$(RULE_$(2)_to_$(4)) +$(TGT)_OBJS += $$(BIN)/$(3).$(4) +endef +# +# $(1) is the full path to the source file (e.g. "drivers/net/rtl8139.c") +# +define rules_template_file @$(ECHO) " [RULES] $(1)" @$(MKDIR) -p $(BIN)/rules/$(dir $(1)) - @$(ECHO_E) '\n$$(BIN)/$(3).o :' \ - '$(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)' \ - '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ - '\n\t$$(RULE_$(2))\n' \ - '\nBOBJS += $$(BIN)/$(3).o\n' \ - $(foreach TGT,$(DEBUG_TARGETS), \ - $(if $(RULE_$(2)_to_$(TGT)), \ - '\n$$(BIN)/$(3).$(TGT) :' \ - '$(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS)' \ - '\n\t$$(QM)$(ECHO) " [BUILD] $$@"' \ - '\n\t$$(RULE_$(2)_to_$(TGT))\n' \ - '\n$(TGT)_OBJS += $$(BIN)/$(3).$(TGT)\n' ) ) \ - '\n$(BIN)/deps/$(1).d : $$($(3)_DEPS)\n' \ - '\nTAGS : $$($(3)_DEPS)\n' > $(BIN)/rules/$(1).r - @$(if $(findstring drivers/,$(1)),\ - $(PERL) $(PARSEROM) $(1) >> $(BIN)/rules/$(1).r) + @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call rules_template,$(1)))' \ + > $(BIN)/rules/$(1).r endef -# Rule to generate the dependency list file +# Generate the dependency files # -$(BIN)/deps/%.d : % $(MAKEDEPS) - $(call deps_template,$<,$(subst .,,$(suffix $<)),$(basename $(notdir $<))) +$(BIN)/deps/%.d : % $(MAKEDEPS) $(PARSEROM) + $(call deps_template_file,$<) -# Calculate and include the list of dependency list files +# Calculate list of dependency files # AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) +autodeps : + @$(ECHO) $(AUTO_DEPS) +VERYCLEANUP += $(BIN)/deps + +# Include dependency files +# ifdef NEED_DEPS ifneq ($(AUTO_DEPS),) -include $(AUTO_DEPS) endif endif -autodeps : - @$(ECHO) $(AUTO_DEPS) -VERYCLEANUP += $(BIN)/deps -# Rule to generate the rules file +# Generate the rules files # -$(BIN)/rules/%.r : % $(MAKEDEPS) $(PARSEROM) - $(call rules_template,$<,$(subst .,,$(suffix $<)),$(basename $(notdir $<))) +$(BIN)/rules/%.r : % $(MAKEDEPS) + $(call rules_template_file,$<) -# Calculate and include the list of rules files +# Calculate list of rules files # AUTO_RULES = $(patsubst %,$(BIN)/rules/%.r,$(AUTO_SRCS)) +autorules : + @$(ECHO) $(AUTO_RULES) +VERYCLEANUP += $(BIN)/rules + +# Evaluate rules (or include rules files) +# ifdef NEED_DEPS ifneq ($(AUTO_RULES),) +ifneq ($(HAVE_EVAL),) +$(foreach SRC,$(AUTO_SRCS),$(eval $(call rules_template,$(SRC)))) +else -include $(AUTO_RULES) endif endif -autorules : - @$(ECHO) $(AUTO_RULES) -VERYCLEANUP += $(BIN)/rules +endif # The following variables are created by the rules files # @@ -879,7 +958,7 @@ ifneq ($(BLIB_OBJS_OLD),$(BLIB_OBJS)) $(shell $(ECHO) "$(BLIB_OBJS)" > $(BLIB_LIST)) endif -$(BLIB_LIST) : +$(BLIB_LIST) : $(MAKEDEPS) VERYCLEANUP += $(BLIB_LIST) @@ -949,15 +1028,20 @@ $(BIN)/%.nodeps : $(BIN)/%.tmp # Get licensing verdict for the specified target # define licensable_deps_list - $(filter-out config/local/%.h,$(call deps_list,$(1))) + $(filter-out config/local/%.h,\ + $(filter-out $(BIN)/.%.list,\ + $(call deps_list,$(1)))) endef define unlicensed_deps_list $(shell grep -L FILE_LICENCE $(call licensable_deps_list,$(1))) endef define licence_list - $(patsubst __licence_%,%,\ - $(filter __licence_%,$(shell $(NM) $(1) | cut -d" " -f3))) + $(sort $(foreach LICENCE,\ + $(filter __licence__%,$(shell $(NM) $(1) | cut -d" " -f3)),\ + $(word 2,$(subst __, ,$(LICENCE))))) endef +$(BIN)/%.licence_list : $(BIN)/%.tmp + $(Q)$(ECHO) $(call licence_list,$<) $(BIN)/%.licence : $(BIN)/%.tmp $(QM)$(ECHO) " [LICENCE] $@" $(Q)$(if $(strip $(call unlicensed_deps_list,$<)),\ @@ -1018,51 +1102,61 @@ AUTO_MEDIA = $(filter-out $(NON_AUTO_MEDIA),$(MEDIA)) automedia : @$(ECHO) $(AUTO_MEDIA) -# media_template : create Makefile rules for specified media +# media_template : create media rules # # $(1) is the media name (e.g. "rom") # define media_template +$(if $(filter $(1),$(AUTO_MEDIA)),$(call auto_media_template,$(1))) +LIST_$(1) := $$(if $$(LIST_NAME_$(1)),$$($$(LIST_NAME_$(1))),$$(DRIVERS)) +ALL_$(1) = $$(foreach ITEM,$$(LIST_$(1)),$$(BIN)/$$(ITEM).$(1)) +$$(BIN)/all$(1)s : $$(ALL_$(1)) +$$(BIN)/allall : $$(BIN)/all$(1)s +all$(1)s : $$(BIN)/all$(1)s +allall : $$(BIN)/allall +endef +# +# $(1) is the media name (e.g. "rom") +# +define auto_media_template +$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin + $$(QM)echo " [FINISH] $$@" + $$(Q)$$(CP) $$< $$@ + $$(Q)$$(if $$(PAD_$(1)),$$(PAD_$(1)) $$@) + $$(Q)$$(if $$(FINALISE_$(1)),$$(FINALISE_$(1)) $$@) +endef +# +# $(1) is the media name (e.g. "rom") +# +define media_template_file @$(ECHO) " [MEDIARULES] $(1)" @$(MKDIR) -p $(BIN)/rules/$(dir $(1)) - @$(ECHO_E) '$$(BIN)/%.$(1) : $$(BIN)/%.$(1).zbin' \ - '\n\t$$(QM)$(ECHO) " [FINISH] $$@"' \ - '\n\t$$(Q)$$(CP) $$< $$@' \ - '\n\t$$(Q)$$(PAD_$(1))' \ - '\n\t$$(Q)$$(FINALISE_$(1))' \ + @$(ECHO_E) '$(subst $(NEWLINE),\n,$(call media_template,$(1)))' \ > $(BIN)/rules/$(1).media.r endef -# Rule to generate the Makefile rules to be included +# Generate media rules files # $(BIN)/rules/%.media.r : $(MAKEDEPS) - $(call media_template,$*) + $(call media_template_file,$*) -# Calculate and include the list of Makefile rules files +# Calculate list of media rules files # -MEDIA_RULES = $(patsubst %,$(BIN)/rules/%.media.r,$(AUTO_MEDIA)) +MEDIA_RULES = $(patsubst %,$(BIN)/rules/%.media.r,$(MEDIA)) mediarules : @$(ECHO) $(MEDIA_RULES) + +# Evaluate media rules (or include media rules files) +# ifdef NEED_DEPS ifneq ($(MEDIA_RULES),) +ifneq ($(HAVE_EVAL),) +$(foreach MEDIUM,$(MEDIA),$(eval $(call media_template,$(MEDIUM)))) +else -include $(MEDIA_RULES) endif endif - -# Wrap up binary blobs (for embedded images) -# -$(BIN)/%.o : payload/%.img - $(QM)echo " [WRAP] $@" - $(Q)$(LD) -b binary -r -o $@ $< --undefined obj_payload \ - --defsym obj_$*=0 - -BOBJS += $(patsubst payload/%.img,$(BIN)/%.o,$(wildcard payload/*.img)) - -# The "allXXXs" targets for each suffix -# -allall: allroms allmroms allpxes allisos alldsks -allroms allmroms : all%s : $(foreach ROM,$(ROMS),$(BIN)/$(ROM).%) -allpxes allisos alldsks : all%s : $(foreach DRIVER,$(DRIVERS),$(BIN)/$(DRIVER).%) +endif # Alias for ipxe.% # diff --git a/roms/ipxe/src/arch/i386/Makefile b/roms/ipxe/src/arch/i386/Makefile index 8314f26da..d1b885c87 100644 --- a/roms/ipxe/src/arch/i386/Makefile +++ b/roms/ipxe/src/arch/i386/Makefile @@ -69,13 +69,20 @@ CFLAGS += -fshort-wchar # CFLAGS += -Ui386 +# Define version string for lkrnprefix.S +# +CFLAGS_lkrnprefix += -DVERSION="\"$(VERSION)\"" + # Locations of utilities # ISOLINUX_BIN_LIST := \ $(ISOLINUX_BIN) \ /usr/lib/syslinux/isolinux.bin \ + /usr/lib/syslinux/bios/isolinux.bin \ /usr/share/syslinux/isolinux.bin \ - /usr/local/share/syslinux/isolinux.bin + /usr/share/syslinux/bios/isolinux.bin \ + /usr/local/share/syslinux/isolinux.bin \ + /usr/local/share/syslinux/bios/isolinux.bin ISOLINUX_BIN = $(firstword $(wildcard $(ISOLINUX_BIN_LIST))) # i386-specific directories containing source files diff --git a/roms/ipxe/src/arch/i386/Makefile.pcbios b/roms/ipxe/src/arch/i386/Makefile.pcbios index e1b226f5a..d3fe8b9e6 100644 --- a/roms/ipxe/src/arch/i386/Makefile.pcbios +++ b/roms/ipxe/src/arch/i386/Makefile.pcbios @@ -29,17 +29,22 @@ MEDIA += exe # Padding rules # -PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff $@ +PAD_rom = $(PERL) $(PADIMG) --blksize=512 --byte=0xff PAD_mrom = $(PAD_rom) -PAD_dsk = $(PERL) $(PADIMG) --blksize=512 $@ -PAD_hd = $(PERL) $(PADIMG) --blksize=32768 $@ -PAD_exe = $(PERL) $(PADIMG) --blksize=512 $@ +PAD_dsk = $(PERL) $(PADIMG) --blksize=512 +PAD_hd = $(PERL) $(PADIMG) --blksize=32768 +PAD_exe = $(PERL) $(PADIMG) --blksize=512 # Finalisation rules # -FINALISE_rom = $(PERL) $(FIXROM) $@ +FINALISE_rom = $(PERL) $(FIXROM) FINALISE_mrom = $(FINALISE_rom) +# Use $(ROMS) rather than $(DRIVERS) for "allroms" and "allmroms" +# +LIST_NAME_rom := ROMS +LIST_NAME_mrom := ROMS + # rule to make a non-emulation ISO boot image NON_AUTO_MEDIA += iso %iso: %lkrn util/geniso diff --git a/roms/ipxe/src/arch/i386/core/cachedhcp.c b/roms/ipxe/src/arch/i386/core/cachedhcp.c new file mode 100644 index 000000000..3cac28e7d --- /dev/null +++ b/roms/ipxe/src/arch/i386/core/cachedhcp.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <ipxe/dhcppkt.h> +#include <ipxe/init.h> +#include <ipxe/netdevice.h> +#include <realmode.h> +#include <pxe_api.h> + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( cached_dhcpack_phys ); +#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys ) + +/** Colour for debug messages */ +#define colour &cached_dhcpack_phys + +/** Cached DHCPACK */ +static struct dhcp_packet *cached_dhcpack; + +/** + * Cached DHCPACK startup function + * + */ +static void cachedhcp_init ( void ) { + struct dhcp_packet *dhcppkt; + struct dhcp_packet *tmp; + struct dhcphdr *dhcphdr; + size_t len; + + /* Do nothing if no cached DHCPACK is present */ + if ( ! cached_dhcpack_phys ) { + DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" ); + return; + } + + /* No reliable way to determine length before parsing packet; + * start by assuming maximum length permitted by PXE. + */ + len = sizeof ( BOOTPLAYER_t ); + + /* Allocate and populate DHCP packet */ + dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len ); + if ( ! dhcppkt ) { + DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); + return; + } + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0, + len ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Resize packet to required length. If reallocation fails, + * just continue to use the original packet. + */ + len = dhcppkt_len ( dhcppkt ); + tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); + if ( tmp ) + dhcppkt = tmp; + + /* Reinitialise packet at new address */ + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Store as cached DHCPACK, and mark original copy as consumed */ + DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n", + cached_dhcpack_phys, len ); + cached_dhcpack = dhcppkt; + cached_dhcpack_phys = 0; +} + +/** + * Cached DHCPACK startup function + * + */ +static void cachedhcp_startup ( void ) { + + /* If cached DHCP packet was not claimed by any network device + * during startup, then free it. + */ + if ( cached_dhcpack ) { + DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + } +} + +/** Cached DHCPACK initialisation function */ +struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = cachedhcp_init, +}; + +/** Cached DHCPACK startup function */ +struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { + .startup = cachedhcp_startup, +}; + +/** + * Apply cached DHCPACK to network device, if applicable + * + * @v netdev Network device + * @ret rc Return status code + */ +static int cachedhcp_probe ( struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; + + /* Do nothing unless we have a cached DHCPACK */ + if ( ! cached_dhcpack ) + return 0; + + /* Do nothing unless cached DHCPACK's MAC address matches this + * network device. + */ + if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, + ll_protocol->ll_addr_len ) != 0 ) { + DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", + netdev->name ); + return 0; + } + DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); + + /* Register as DHCP settings for this network device */ + if ( ( rc = register_settings ( &cached_dhcpack->settings, + netdev_settings ( netdev ), + DHCP_SETTINGS_NAME ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not register settings: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Claim cached DHCPACK */ + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + + return 0; +} + +/** Cached DHCP packet network device driver */ +struct net_driver cachedhcp_driver __net_driver = { + .name = "cachedhcp", + .probe = cachedhcp_probe, +}; diff --git a/roms/ipxe/src/arch/i386/core/gdbidt.S b/roms/ipxe/src/arch/i386/core/gdbidt.S index cd8b38a9e..a1e309d7c 100644 --- a/roms/ipxe/src/arch/i386/core/gdbidt.S +++ b/roms/ipxe/src/arch/i386/core/gdbidt.S @@ -1,102 +1,11 @@ /* - * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub. + * Interrupt handlers for GDB stub */ -#include <librm.h> - #define SIZEOF_I386_REGS 32 #define SIZEOF_I386_FLAGS 4 /**************************************************************************** - * Interrupt Descriptor Table - **************************************************************************** - */ - .section ".data16", "aw", @progbits - .globl idtr -idtr: -idt_limit: - .word idt_length - 1 -idt_base: - .long 0 - -/* IDT entries have the following format: - * offset_lo, segment selector, flags, offset_hi - * - * Since it is not possible to specify relocations in arbitrary - * expressions like (int_overflow & 0xffff), we initialise the - * IDT with entries in an incorrect format. - * - * The entries are shuffled into the correct format in init_librm(). - */ -#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0 -#define IDT_ENTRY_PRESENT(name) \ - .long int_##name; \ - .word 0x8e00, VIRTUAL_CS - -.align 16 -idt: - IDT_ENTRY_PRESENT(divide_error) - IDT_ENTRY_PRESENT(debug_trap) - IDT_ENTRY_EMPTY(non_maskable_interrupt) - IDT_ENTRY_PRESENT(breakpoint) - IDT_ENTRY_PRESENT(overflow) - IDT_ENTRY_PRESENT(bound_range_exceeded) - IDT_ENTRY_PRESENT(invalid_opcode) - IDT_ENTRY_EMPTY(device_not_available) - IDT_ENTRY_PRESENT(double_fault) - IDT_ENTRY_EMPTY(coprocessor_segment_overrun) - IDT_ENTRY_PRESENT(invalid_tss) - IDT_ENTRY_PRESENT(segment_not_present) - IDT_ENTRY_PRESENT(stack_segment_fault) - IDT_ENTRY_PRESENT(general_protection) - IDT_ENTRY_PRESENT(page_fault) -idt_end: - .equ idt_length, idt_end - idt - -/* The IDT entries are fixed up (once) in init_librm() */ -idt_fixed: - .byte 0 - -/**************************************************************************** - * idt_init (real-mode near call, 16-bit real-mode near return address) - * - * Initialise the IDT, called from init_librm. - * - * Parameters: - * %eax : IDT base address - * - * Destroys %ax, %bx, and %di. - **************************************************************************** - */ - .section ".text16", "ax", @progbits - .code16 - .globl idt_init -idt_init: - movl %eax, idt_base - addl $idt, idt_base - - /* IDT entries are only fixed up once */ - movb idt_fixed, %al - orb %al, %al - jnz 2f - movb $1, idt_fixed - - /* Shuffle IDT entries into the correct format */ - movb $(idt_length / 8), %al - movw $idt, %bx - or %al, %al - jz 2f -1: - movw 2(%bx), %di - xchg %di, 6(%bx) - movw %di, 2(%bx) - addw $8, %bx - dec %al - jnz 1b -2: - ret - -/**************************************************************************** * Interrupt handlers **************************************************************************** */ @@ -111,35 +20,35 @@ idt_init: #define SIGSEGV 11 #define SIGSTKFLT 16 -int_divide_error: + .globl gdbmach_nocode_sigfpe +gdbmach_nocode_sigfpe: pushl $SIGFPE - jmp do_interrupt + jmp gdbmach_interrupt -int_debug_trap: -int_breakpoint: + .globl gdbmach_nocode_sigtrap +gdbmach_nocode_sigtrap: pushl $SIGTRAP - jmp do_interrupt + jmp gdbmach_interrupt -int_overflow: -int_bound_range_exceeded: + .globl gdbmach_nocode_sigstkflt +gdbmach_nocode_sigstkflt: pushl $SIGSTKFLT - jmp do_interrupt + jmp gdbmach_interrupt -int_invalid_opcode: + .globl gdbmach_nocode_sigill +gdbmach_nocode_sigill: pushl $SIGILL - jmp do_interrupt + jmp gdbmach_interrupt -int_double_fault: + .globl gdbmach_withcode_sigbus +gdbmach_withcode_sigbus: movl $SIGBUS, (%esp) - jmp do_interrupt + jmp gdbmach_interrupt -int_invalid_tss: -int_segment_not_present: -int_stack_segment_fault: -int_general_protection: -int_page_fault: + .globl gdbmach_withcode_sigsegv +gdbmach_withcode_sigsegv: movl $SIGSEGV, (%esp) - jmp do_interrupt + jmp gdbmach_interrupt /* When invoked, the stack contains: eflags, cs, eip, signo. */ #define IH_OFFSET_GDB_REGS ( 0 ) @@ -161,7 +70,7 @@ int_page_fault: #define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 ) #define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 ) #define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 ) -do_interrupt: +gdbmach_interrupt: /* Store CPU state in GDB register snapshot */ pushw $0 pushw %gs @@ -187,25 +96,41 @@ do_interrupt: pushl %ecx pushl %eax + /* Switch to virtual addressing */ + call _intr_to_virt + /* Call GDB stub exception handler */ pushl %esp pushl (IH_OFFSET_SIGNO + 4)(%esp) call gdbmach_handler addl $8, %esp + /* Copy register snapshot to new stack and switch to new stack */ + movl %esp, %esi + movl (IH_OFFSET_GDB_SEG_REGS + 4)(%esp), %eax + movl %eax, %es + movl (IH_OFFSET_GDB_REGS + 16)(%esp), %edi + subl $IH_OFFSET_END, %edi + movl $(IH_OFFSET_END / 4), %ecx + pushl %edi + ss rep movsl + popl %edi + movl %eax, %ss + movl %edi, %esp + /* Restore CPU state from GDB register snapshot */ popl %eax popl %ecx popl %edx popl %ebx - addl $4, %esp /* Changing ESP currently not supported */ + popl %ebp /* Skip %esp: already loaded */ popl %ebp popl %esi popl %edi popl IH_OFFSET_FLUX_OLD_EIP(%esp) popl IH_OFFSET_FLUX_OLD_EFLAGS(%esp) popl IH_OFFSET_FLUX_OLD_CS(%esp) - popl %ss + popl %ds /* Skip %ss: already loaded */ popl %ds popl %es popl %fs diff --git a/roms/ipxe/src/arch/i386/core/gdbmach.c b/roms/ipxe/src/arch/i386/core/gdbmach.c index 4232c7553..4d6897f7d 100644 --- a/roms/ipxe/src/arch/i386/core/gdbmach.c +++ b/roms/ipxe/src/arch/i386/core/gdbmach.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <assert.h> #include <ipxe/uaccess.h> #include <ipxe/gdbstub.h> +#include <librm.h> #include <gdbmach.h> /** @file @@ -150,3 +151,30 @@ __asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) { gdbstub_handler ( signo, regs ); gdbmach_enable_hwbps(); } + +static void * gdbmach_interrupt_vectors[] = { + gdbmach_nocode_sigfpe, /* Divide by zero */ + gdbmach_nocode_sigtrap, /* Debug trap */ + NULL, /* Non-maskable interrupt */ + gdbmach_nocode_sigtrap, /* Breakpoint */ + gdbmach_nocode_sigstkflt, /* Overflow */ + gdbmach_nocode_sigstkflt, /* Bound range exceeded */ + gdbmach_nocode_sigill, /* Invalid opcode */ + NULL, /* Device not available */ + gdbmach_withcode_sigbus, /* Double fault */ + NULL, /* Coprocessor segment overrun */ + gdbmach_withcode_sigsegv, /* Invalid TSS */ + gdbmach_withcode_sigsegv, /* Segment not present */ + gdbmach_withcode_sigsegv, /* Stack segment fault */ + gdbmach_withcode_sigsegv, /* General protection fault */ + gdbmach_withcode_sigsegv, /* Page fault */ +}; + +void gdbmach_init ( void ) { + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( gdbmach_interrupt_vectors ) / + sizeof ( gdbmach_interrupt_vectors[0] ) ) ; i++ ) { + set_interrupt_vector ( i, gdbmach_interrupt_vectors[i] ); + } +} diff --git a/roms/ipxe/src/arch/i386/core/pci_autoboot.c b/roms/ipxe/src/arch/i386/core/pci_autoboot.c new file mode 100644 index 000000000..5e6197e2e --- /dev/null +++ b/roms/ipxe/src/arch/i386/core/pci_autoboot.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 Red Hat Inc. + * Alex Williamson <alex.williamson@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/device.h> +#include <ipxe/init.h> +#include <realmode.h> +#include <usr/autoboot.h> + +uint16_t __bss16 ( autoboot_busdevfn ); +#define autoboot_busdevfn __use_data16 ( autoboot_busdevfn ) + +/** + * Initialise PCI autoboot device + */ +static void pci_autoboot_init ( void ) { + + if ( autoboot_busdevfn ) { + autoboot_device.bus_type = BUS_TYPE_PCI; + autoboot_device.location = autoboot_busdevfn; + } +} + +/** PCI autoboot device initialisation function */ +struct init_fn pci_autoboot_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = pci_autoboot_init, +}; diff --git a/roms/ipxe/src/arch/i386/core/relocate.c b/roms/ipxe/src/arch/i386/core/relocate.c index b9b029443..5fbf2d2c2 100644 --- a/roms/ipxe/src/arch/i386/core/relocate.c +++ b/roms/ipxe/src/arch/i386/core/relocate.c @@ -33,8 +33,10 @@ extern char _etextdata[]; /** * Relocate iPXE * - * @v ix86 x86 register dump from prefix - * @ret ix86 x86 registers to return to prefix + * @v ebp Maximum address to use for relocation + * @ret esi Current physical address + * @ret edi New physical address + * @ret ecx Length to copy * * This finds a suitable location for iPXE near the top of 32-bit * address space, and returns the physical address of the new location @@ -59,7 +61,7 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) { /* Determine maximum usable address */ max = MAX_ADDR; - if ( ix86->regs.ebp && ( ix86->regs.ebp < max ) ) { + if ( ix86->regs.ebp < max ) { max = ix86->regs.ebp; DBG ( "Limiting relocation to [0,%lx)\n", max ); } diff --git a/roms/ipxe/src/arch/i386/core/video_subr.c b/roms/ipxe/src/arch/i386/core/video_subr.c index 306c6d56c..3f701bd96 100644 --- a/roms/ipxe/src/arch/i386/core/video_subr.c +++ b/roms/ipxe/src/arch/i386/core/video_subr.c @@ -104,7 +104,7 @@ static void vga_putc(int byte) struct console_driver vga_console __console_driver = { .putchar = vga_putc, - .disabled = 1, + .disabled = CONSOLE_DISABLED, .usage = CONSOLE_DIRECT_VGA, }; diff --git a/roms/ipxe/src/arch/i386/core/virtaddr.S b/roms/ipxe/src/arch/i386/core/virtaddr.S index aae1e1edd..5e5d77352 100644 --- a/roms/ipxe/src/arch/i386/core/virtaddr.S +++ b/roms/ipxe/src/arch/i386/core/virtaddr.S @@ -36,6 +36,7 @@ _virt_to_phys: addl %ebp, 12(%esp) /* Switch to physical code segment */ + cli pushl $PHYSICAL_CS leal 1f(%ebp), %eax pushl %eax @@ -44,10 +45,10 @@ _virt_to_phys: /* Reload other segment registers and adjust %esp */ movl $PHYSICAL_DS, %eax movl %eax, %ds - movl %eax, %es - movl %eax, %fs + movl %eax, %es + movl %eax, %fs movl %eax, %gs - movl %eax, %ss + movl %eax, %ss addl %ebp, %esp /* Restore registers and flags, and return */ @@ -64,9 +65,6 @@ _virt_to_phys: * selectors. All other registers are preserved. Flags are * preserved. * - * Note that this depends on the GDT already being correctly set up - * (e.g. by a call to run_here()). - * * Parameters: none * Returns: none **************************************************************************** @@ -79,18 +77,19 @@ _phys_to_virt: pushl %ebp /* Switch to virtual code segment */ + cli ljmp $VIRTUAL_CS, $1f -1: +1: /* Reload data segment registers */ movl $VIRTUAL_DS, %eax movl %eax, %ds - movl %eax, %es - movl %eax, %fs + movl %eax, %es + movl %eax, %fs movl %eax, %gs /* Reload stack segment and adjust %esp */ movl virt_offset, %ebp - movl %eax, %ss + movl %eax, %ss subl %ebp, %esp /* Change the return address to a virtual address */ @@ -101,3 +100,46 @@ _phys_to_virt: popl %eax popfl ret + +/**************************************************************************** + * _intr_to_virt (virtual code segment, virtual or physical stack segment) + * + * Switch from virtual code segment with either a virtual or physical + * stack segment to using virtual addressing. %esp is adjusted if + * necessary to a virtual value. Segment registers are set to virtual + * selectors. All other registers are preserved. Flags are + * preserved. + * + * Parameters: none + * Returns: none + **************************************************************************** + */ + .globl _intr_to_virt +_intr_to_virt: + /* Preserve registers and flags */ + pushfl + pushl %eax + pushl %ebp + + /* Check whether stack segment is physical or virtual */ + movl %ss, %eax + cmpw $VIRTUAL_DS, %ax + movl $VIRTUAL_DS, %eax + + /* Reload data segment registers */ + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + + /* Reload stack segment and adjust %esp if necessary */ + je 1f + movl virt_offset, %ebp + movl %eax, %ss + subl %ebp, %esp +1: + /* Restore registers and flags, and return */ + popl %ebp + popl %eax + popfl + ret diff --git a/roms/ipxe/src/arch/i386/drivers/net/undiload.c b/roms/ipxe/src/arch/i386/drivers/net/undiload.c index 0edfa35dc..77134dcb8 100644 --- a/roms/ipxe/src/arch/i386/drivers/net/undiload.c +++ b/roms/ipxe/src/arch/i386/drivers/net/undiload.c @@ -38,6 +38,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Disambiguate the various error causes */ +#define EINFO_EUNDILOAD \ + __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ + "UNDI loader error" ) +#define EUNDILOAD( status ) EPLATFORM ( EINFO_EUNDILOAD, status ) + /** Parameter block for calling UNDI loader */ static struct s_UNDI_LOADER __bss16 ( undi_loader ); #define undi_loader __use_data16 ( undi_loader ) @@ -97,21 +103,21 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { /* Call loader */ undi_loader_entry = undirom->loader_entry; - __asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t" + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "pushw %%ds\n\t" "pushw %%ax\n\t" "lcall *undi_loader_entry\n\t" - "addw $4, %%sp\n\t" ) + "popl %%ebp\n\t" /* discard */ + "popl %%ebp\n\t" /* gcc bug */ ) : "=a" ( exit ) : "a" ( __from_data16 ( &undi_loader ) ) - : "ebx", "ecx", "edx", "esi", "edi", "ebp" ); + : "ebx", "ecx", "edx", "esi", "edi" ); if ( exit != PXENV_EXIT_SUCCESS ) { /* Clear entry point */ memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) ); - rc = -undi_loader.Status; - if ( rc == 0 ) /* Paranoia */ - rc = -EIO; + rc = -EUNDILOAD ( undi_loader.Status ); DBGC ( undi, "UNDI %p loader failed: %s\n", undi, strerror ( rc ) ); return rc; diff --git a/roms/ipxe/src/arch/i386/drivers/net/undinet.c b/roms/ipxe/src/arch/i386/drivers/net/undinet.c index 6205c809b..82dd8d2f9 100644 --- a/roms/ipxe/src/arch/i386/drivers/net/undinet.c +++ b/roms/ipxe/src/arch/i386/drivers/net/undinet.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/netdevice.h> #include <ipxe/if_ether.h> #include <ipxe/ethernet.h> +#include <ipxe/profile.h> #include <undi.h> #include <undinet.h> #include <pxeparent.h> @@ -71,6 +72,9 @@ struct undi_nic { /** Delay between retries of PXENV_UNDI_INITIALIZE */ #define UNDI_INITIALIZE_RETRY_DELAY_MS 200 +/** Maximum number of calls to PXENV_UNDI_ISR per poll */ +#define UNDI_POLL_QUOTA 4 + /** Alignment of received frame payload */ #define UNDI_RX_ALIGN 16 @@ -79,6 +83,26 @@ static void undinet_close ( struct net_device *netdev ); /** Address of UNDI entry point */ static SEGOFF16_t undinet_entry; +/** Transmit profiler */ +static struct profiler undinet_tx_profiler __profiler = + { .name = "undinet.tx" }; + +/** Transmit call profiler */ +static struct profiler undinet_tx_call_profiler __profiler = + { .name = "undinet.tx_call" }; + +/** IRQ profiler */ +static struct profiler undinet_irq_profiler __profiler = + { .name = "undinet.irq" }; + +/** ISR call profiler */ +static struct profiler undinet_isr_call_profiler __profiler = + { .name = "undinet.isr_call" }; + +/** Receive profiler */ +static struct profiler undinet_rx_profiler __profiler = + { .name = "undinet.rx" }; + /***************************************************************************** * * UNDI interrupt service routine @@ -194,6 +218,9 @@ static int undinet_transmit ( struct net_device *netdev, size_t len; int rc; + /* Start profiling */ + profile_start ( &undinet_tx_profiler ); + /* Technically, we ought to make sure that the previous * transmission has completed before we re-use the buffer. * However, many PXE stacks (including at least some Intel PXE @@ -256,14 +283,16 @@ static int undinet_transmit ( struct net_device *netdev, undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet ); /* Issue PXE API call */ + profile_start ( &undinet_tx_call_profiler ); if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT, &undi_transmit, sizeof ( undi_transmit ) ) ) != 0 ) goto done; + profile_stop ( &undinet_tx_call_profiler ); /* Free I/O buffer */ netdev_tx_complete ( netdev, iobuf ); - + profile_stop ( &undinet_tx_profiler ); done: return rc; } @@ -302,6 +331,7 @@ static void undinet_poll ( struct net_device *netdev ) { struct undi_nic *undinic = netdev->priv; struct s_PXENV_UNDI_ISR undi_isr; struct io_buffer *iobuf = NULL; + unsigned int quota = UNDI_POLL_QUOTA; size_t len; size_t reserve_len; size_t frag_len; @@ -316,10 +346,12 @@ static void undinet_poll ( struct net_device *netdev ) { */ if ( ! undinet_isr_triggered() ) { /* Allow interrupt to occur */ - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "nop\n\t" - "nop\n\t" - "cli\n\t" ) : : ); + profile_start ( &undinet_irq_profiler ); + __asm__ __volatile__ ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ); + profile_stop ( &undinet_irq_profiler ); /* If interrupts are known to be supported, * then do nothing on this poll; wait for the @@ -338,17 +370,22 @@ static void undinet_poll ( struct net_device *netdev ) { } /* Run through the ISR loop */ - while ( 1 ) { + while ( quota-- ) { + profile_start ( &undinet_isr_call_profiler ); if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR, &undi_isr, - sizeof ( undi_isr ) ) ) != 0 ) + sizeof ( undi_isr ) ) ) != 0 ) { + netdev_rx_err ( netdev, NULL, rc ); break; + } + profile_stop ( &undinet_isr_call_profiler ); switch ( undi_isr.FuncFlag ) { case PXENV_UNDI_ISR_OUT_TRANSMIT: /* We don't care about transmit completions */ break; case PXENV_UNDI_ISR_OUT_RECEIVE: /* Packet fragment received */ + profile_start ( &undinet_rx_profiler ); len = undi_isr.FrameLength; frag_len = undi_isr.BufferLength; reserve_len = ( -undi_isr.FrameHeaderLength & @@ -393,6 +430,7 @@ static void undinet_poll ( struct net_device *netdev ) { if ( undinic->hacks & UNDI_HACK_EB54 ) --last_trigger_count; } + profile_stop ( &undinet_rx_profiler ); break; case PXENV_UNDI_ISR_OUT_DONE: /* Processing complete */ @@ -531,6 +569,53 @@ static struct net_device_operations undinet_operations = { .irq = undinet_irq, }; +/** A device with broken support for generating interrupts */ +struct undinet_irq_broken { + /** PCI vendor ID */ + uint16_t pci_vendor; + /** PCI device ID */ + uint16_t pci_device; +}; + +/** + * List of devices with broken support for generating interrupts + * + * Some PXE stacks are known to claim that IRQs are supported, but + * then never generate interrupts. No satisfactory solution has been + * found to this problem; the workaround is to add the PCI vendor and + * device IDs to this list. This is something of a hack, since it + * will generate false positives for identical devices with a working + * PXE stack (e.g. those that have been reflashed with iPXE), but it's + * an improvement on the current situation. + */ +static const struct undinet_irq_broken undinet_irq_broken_list[] = { + /* HP XX70x laptops */ + { .pci_vendor = 0x8086, .pci_device = 0x1502 }, + { .pci_vendor = 0x8086, .pci_device = 0x1503 }, +}; + +/** + * Check for devices with broken support for generating interrupts + * + * @v undi UNDI device + * @ret irq_is_broken Interrupt support is broken; no interrupts are generated + */ +static int undinet_irq_is_broken ( struct undi_device *undi ) { + const struct undinet_irq_broken *broken; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) / + sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) { + broken = &undinet_irq_broken_list[i]; + if ( ( undi->dev.desc.bus_type == BUS_TYPE_PCI ) && + ( undi->dev.desc.vendor == broken->pci_vendor ) && + ( undi->dev.desc.device == broken->pci_device ) ) { + return 1; + } + } + return 0; +} + /** * Probe UNDI device * @@ -647,6 +732,11 @@ int undinet_probe ( struct undi_device *undi ) { undinic ); undinic->hacks |= UNDI_HACK_EB54; } + if ( undinet_irq_is_broken ( undi ) ) { + DBGC ( undinic, "UNDINIC %p forcing polling mode due to " + "broken interrupts\n", undinic ); + undinic->irq_supported = 0; + } /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c index 25c8dad2d..b2b7bf2d8 100644 --- a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c +++ b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c @@ -62,11 +62,13 @@ static unsigned int bios_attr = ATTR_DEFAULT; /** * Handle ANSI CUP (cursor position) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params[0] Row (1 is top) * @v params[1] Column (1 is left) */ -static void bios_handle_cup ( unsigned int count __unused, int params[] ) { +static void bios_handle_cup ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, int params[] ) { int cx = ( params[1] - 1 ); int cy = ( params[0] - 1 ); @@ -85,10 +87,12 @@ static void bios_handle_cup ( unsigned int count __unused, int params[] ) { /** * Handle ANSI ED (erase in page) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params[0] Region to erase */ -static void bios_handle_ed ( unsigned int count __unused, +static void bios_handle_ed ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, int params[] __unused ) { /* We assume that we always clear the whole screen */ assert ( params[0] == ANSIESC_ED_ALL ); @@ -97,16 +101,20 @@ static void bios_handle_ed ( unsigned int count __unused, "int $0x10\n\t" "cli\n\t" ) : : "a" ( 0x0600 ), "b" ( bios_attr << 8 ), - "c" ( 0 ), "d" ( 0xffff ) ); + "c" ( 0 ), + "d" ( ( ( console_height - 1 ) << 8 ) | + ( console_width - 1 ) ) ); } /** * Handle ANSI SGR (set graphics rendition) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params List of graphic rendition aspects */ -static void bios_handle_sgr ( unsigned int count, int params[] ) { +static void bios_handle_sgr ( struct ansiesc_context *ctx __unused, + unsigned int count, int params[] ) { static const uint8_t bios_attr_fcols[10] = { ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN, ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA, @@ -167,7 +175,8 @@ static void bios_putchar ( int character ) { return; /* Print character with attribute */ - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "sti\n\t" /* Skip non-printable characters */ "cmpb $0x20, %%al\n\t" "jb 1f\n\t" @@ -188,11 +197,11 @@ static void bios_putchar ( int character ) { "xorw %%bx, %%bx\n\t" "movb $0x0e, %%ah\n\t" "int $0x10\n\t" - "cli\n\t" ) + "cli\n\t" + "popl %%ebp\n\t" /* gcc bug */ ) : "=a" ( discard_a ), "=b" ( discard_b ), "=c" ( discard_c ) - : "a" ( character ), "b" ( bios_attr ) - : "ebp" ); + : "a" ( character ), "b" ( bios_attr ) ); } /** diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c b/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c index c1788b3a3..8f3069e18 100644 --- a/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c +++ b/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c @@ -190,6 +190,8 @@ static void hide_etherboot ( void ) { * possible. */ static void unhide_etherboot ( int flags __unused ) { + struct memory_map memmap; + int rc; /* If we have more than one hooked interrupt at this point, it * means that some other vector is still hooked, in which case @@ -203,15 +205,23 @@ static void unhide_etherboot ( int flags __unused ) { return; } - /* Try to unhook INT 15. If it fails, then just leave it - * hooked; it takes care of protecting itself. :) - */ - unhook_bios_interrupt ( 0x15, ( unsigned int ) int15, - &int15_vector ); + /* Try to unhook INT 15 */ + if ( ( rc = unhook_bios_interrupt ( 0x15, ( unsigned int ) int15, + &int15_vector ) ) != 0 ) { + DBG ( "Cannot unhook INT15: %s\n", strerror ( rc ) ); + /* Leave it hooked; there's nothing else we can do, + * and it should be intrinsically safe (though + * wasteful of RAM). + */ + } /* Unhook fake E820 map, if used */ if ( FAKE_E820 ) unfake_e820(); + + /* Dump memory map after unhiding */ + DBG ( "Unhidden iPXE from system memory map\n" ); + get_memmap ( &memmap ); } /** Hide Etherboot startup function */ diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c b/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c index cf6592264..0937a7ce2 100644 --- a/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c +++ b/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c @@ -63,6 +63,10 @@ struct e820_entry { static struct e820_entry __bss16 ( e820buf ); #define e820buf __use_data16 ( e820buf ) +/** We are running during POST; inhibit INT 15,e820 and INT 15,e801 */ +uint8_t __bss16 ( memmap_post ); +#define memmap_post __use_data16 ( memmap_post ) + /** * Get size of extended memory via INT 15,e801 * @@ -74,6 +78,12 @@ static unsigned int extmemsize_e801 ( void ) { unsigned int flags; unsigned int extmem; + /* Inhibit INT 15,e801 during POST */ + if ( memmap_post ) { + DBG ( "INT 15,e801 not available during POST\n" ); + return 0; + } + __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" "int $0x15\n\t" "pushfw\n\t" @@ -164,6 +174,12 @@ static int meme820 ( struct memory_map *memmap ) { unsigned int flags; unsigned int discard_D; + /* Inhibit INT 15,e820 during POST */ + if ( memmap_post ) { + DBG ( "INT 15,e820 not available during POST\n" ); + return -ENOTTY; + } + /* Clear the E820 buffer. Do this once before starting, * rather than on each call; some BIOSes rely on the contents * being preserved between calls. diff --git a/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c b/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c index f86f180ce..523724ab0 100644 --- a/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c +++ b/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c @@ -31,18 +31,21 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** "startpxe" command descriptor */ -static struct command_descriptor startpxe_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>]" ); +/** "startpxe" options */ +struct startpxe_options {}; + +/** "startpxe" option list */ +static struct option_descriptor startpxe_opts[] = {}; /** * "startpxe" payload * * @v netdev Network device + * @v opts Command options * @ret rc Return status code */ -static int startpxe_payload ( struct net_device *netdev ) { +static int startpxe_payload ( struct net_device *netdev, + struct startpxe_options *opts __unused ) { if ( netdev_is_open ( netdev ) ) pxe_activate ( netdev ); @@ -50,6 +53,12 @@ static int startpxe_payload ( struct net_device *netdev ) { return 0; } +/** "startpxe" command descriptor */ +static struct ifcommon_command_descriptor startpxe_cmd = + IFCOMMON_COMMAND_DESC ( struct startpxe_options, startpxe_opts, + 0, MAX_ARGUMENTS, "[<interface>]", + startpxe_payload, 0 ); + /** * The "startpxe" command * @@ -58,7 +67,7 @@ static int startpxe_payload ( struct net_device *netdev ) { * @ret rc Return status code */ static int startpxe_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &startpxe_cmd, startpxe_payload, 0 ); + return ifcommon_exec ( argc, argv, &startpxe_cmd ); } /** "stoppxe" options */ @@ -69,7 +78,7 @@ static struct option_descriptor stoppxe_opts[] = {}; /** "stoppxe" command descriptor */ static struct command_descriptor stoppxe_cmd = - COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0, "" ); + COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0, NULL ); /** * The "stoppxe" command diff --git a/roms/ipxe/src/arch/i386/image/bootsector.c b/roms/ipxe/src/arch/i386/image/bootsector.c index ab3cf94c2..9a089e6bb 100644 --- a/roms/ipxe/src/arch/i386/image/bootsector.c +++ b/roms/ipxe/src/arch/i386/image/bootsector.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <realmode.h> #include <biosint.h> #include <bootsector.h> +#include <ipxe/console.h> /** Vector for storing original INT 18 handler * @@ -60,6 +61,9 @@ int call_bootsector ( unsigned int segment, unsigned int offset, unsigned int drive ) { int discard_b, discard_D, discard_d; + /* Reset console, since boot sector will probably use it */ + console_reset(); + DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset ); /* Hook INTs 18 and 19 to capture failure paths */ @@ -80,6 +84,8 @@ int call_bootsector ( unsigned int segment, unsigned int offset, "movw %%ss, %%ax\n\t" "movw %%ax, %%cs:saved_ss\n\t" "movw %%sp, %%cs:saved_sp\n\t" + /* Save frame pointer (gcc bug) */ + "movl %%ebp, %%cs:saved_ebp\n\t" /* Prepare jump to boot sector */ "pushw %%bx\n\t" "pushw %%di\n\t" @@ -99,11 +105,14 @@ int call_bootsector ( unsigned int segment, unsigned int offset, "sti\n\t" "lret\n\t" /* Preserved variables */ + "\nsaved_ebp: .long 0\n\t" "\nsaved_ss: .word 0\n\t" "\nsaved_sp: .word 0\n\t" "\nsaved_retaddr: .word 0\n\t" /* Boot failure return point */ "\nbootsector_exec_fail:\n\t" + /* Restore frame pointer (gcc bug) */ + "movl %%cs:saved_ebp, %%ebp\n\t" /* Restore stack pointer */ "movw %%cs:saved_ss, %%ax\n\t" "movw %%ax, %%ss\n\t" @@ -114,7 +123,7 @@ int call_bootsector ( unsigned int segment, unsigned int offset, "=d" ( discard_d ) : "b" ( segment ), "D" ( offset ), "d" ( drive ) - : "eax", "ecx", "esi", "ebp" ); + : "eax", "ecx", "esi" ); DBG ( "Booted disk returned via INT 18 or 19\n" ); diff --git a/roms/ipxe/src/arch/i386/image/bzimage.c b/roms/ipxe/src/arch/i386/image/bzimage.c index 12be17793..4865c394c 100644 --- a/roms/ipxe/src/arch/i386/image/bzimage.c +++ b/roms/ipxe/src/arch/i386/image/bzimage.c @@ -347,12 +347,23 @@ static void bzimage_parse_cpio_cmdline ( struct image *image, } /** + * Align initrd length + * + * @v len Length + * @ret len Length rounded up to INITRD_ALIGN + */ +static inline size_t bzimage_align ( size_t len ) { + + return ( ( len + INITRD_ALIGN - 1 ) & ~( INITRD_ALIGN - 1 ) ); +} + +/** * Load initrd * * @v image bzImage image * @v initrd initrd image * @v address Address at which to load, or UNULL - * @ret len Length of loaded image, rounded up to INITRD_ALIGN + * @ret len Length of loaded image, excluding zero-padding */ static size_t bzimage_load_initrd ( struct image *image, struct image *initrd, @@ -360,7 +371,7 @@ static size_t bzimage_load_initrd ( struct image *image, char *filename = initrd->cmdline; char *cmdline; struct cpio_header cpio; - size_t offset = 0; + size_t offset; size_t name_len; size_t pad_len; @@ -368,7 +379,7 @@ static size_t bzimage_load_initrd ( struct image *image, if ( initrd == image ) return 0; - /* Create cpio header before non-prebuilt images */ + /* Create cpio header for non-prebuilt images */ if ( filename && filename[0] ) { cmdline = strchr ( filename, ' ' ); name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) ) @@ -383,24 +394,21 @@ static size_t bzimage_load_initrd ( struct image *image, bzimage_parse_cpio_cmdline ( image, &cpio, ( cmdline + 1 /* ' ' */ )); } - if ( address ) { - copy_to_user ( address, offset, &cpio, - sizeof ( cpio ) ); - } - offset += sizeof ( cpio ); - if ( address ) { - memset_user ( address, offset, 0, name_len ); - copy_to_user ( address, offset, filename, - ( name_len - 1 /* NUL (or space) */ ) ); - } - offset += name_len; - offset = ( ( offset + 0x03 ) & ~0x03 ); + offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 ); + } else { + offset = 0; + name_len = 0; } - /* Copy in initrd image body */ - if ( address ) - memmove_user ( address, offset, initrd->data, 0, initrd->len ); + /* Copy in initrd image body (and cpio header if applicable) */ if ( address ) { + memmove_user ( address, offset, initrd->data, 0, initrd->len ); + if ( offset ) { + memset_user ( address, 0, 0, offset ); + copy_to_user ( address, 0, &cpio, sizeof ( cpio ) ); + copy_to_user ( address, sizeof ( cpio ), filename, + ( name_len - 1 /* NUL (or space) */ ) ); + } DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)" "%s%s\n", image, initrd, user_to_phys ( address, 0 ), user_to_phys ( address, offset ), @@ -411,11 +419,10 @@ static size_t bzimage_load_initrd ( struct image *image, } offset += initrd->len; - /* Round up to multiple of INITRD_ALIGN and zero-pad */ + /* Zero-pad to next INITRD_ALIGN boundary */ pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) ); if ( address ) memset_user ( address, offset, 0, pad_len ); - offset += pad_len; return offset; } @@ -443,6 +450,7 @@ static int bzimage_check_initrds ( struct image *image, /* Calculate length */ len += bzimage_load_initrd ( image, initrd, UNULL ); + len = bzimage_align ( len ); DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n", image, initrd, user_to_phys ( initrd->data, 0 ), @@ -490,6 +498,7 @@ static void bzimage_load_initrds ( struct image *image, struct image *other; userptr_t top; userptr_t dest; + size_t offset; size_t len; /* Reshuffle initrds into desired order */ @@ -508,9 +517,7 @@ static void bzimage_load_initrds ( struct image *image, return; /* Find highest usable address */ - top = userptr_add ( highest->data, - ( ( highest->len + INITRD_ALIGN - 1 ) & - ~( INITRD_ALIGN - 1 ) ) ); + top = userptr_add ( highest->data, bzimage_align ( highest->len ) ); if ( user_to_phys ( top, 0 ) > bzimg->mem_limit ) top = phys_to_user ( bzimg->mem_limit ); DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n", @@ -522,23 +529,27 @@ static void bzimage_load_initrds ( struct image *image, /* Calculate cumulative length of following * initrds (including padding). */ - len = 0; + offset = 0; for_each_image ( other ) { if ( other == initrd ) - len = 0; - len += bzimage_load_initrd ( image, other, UNULL ); + offset = 0; + offset += bzimage_load_initrd ( image, other, UNULL ); + offset = bzimage_align ( offset ); } /* Load initrd at this address */ - dest = userptr_add ( top, -len ); - bzimage_load_initrd ( image, initrd, dest ); + dest = userptr_add ( top, -offset ); + len = bzimage_load_initrd ( image, initrd, dest ); /* Record initrd location */ - if ( ! bzimg->ramdisk_image ) { + if ( ! bzimg->ramdisk_image ) bzimg->ramdisk_image = user_to_phys ( dest, 0 ); - bzimg->ramdisk_size = len; - } + bzimg->ramdisk_size = ( user_to_phys ( dest, len ) - + bzimg->ramdisk_image ); } + DBGC ( image, "bzImage %p initrds at [%#08lx,%#08lx)\n", + image, bzimg->ramdisk_image, + ( bzimg->ramdisk_image + bzimg->ramdisk_size ) ); } /** diff --git a/roms/ipxe/src/arch/i386/image/com32.c b/roms/ipxe/src/arch/i386/image/com32.c index 5cc9a4476..c12ffb684 100644 --- a/roms/ipxe/src/arch/i386/image/com32.c +++ b/roms/ipxe/src/arch/i386/image/com32.c @@ -41,13 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/init.h> #include <ipxe/io.h> -struct idt_register com32_external_idtr = { - .limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1, - .base = COM32_IDT -}; - -struct idt_register com32_internal_idtr; - /** * Execute COMBOOT image * @@ -95,8 +88,6 @@ static int com32_exec_loop ( struct image *image ) { unregister_image ( image ); __asm__ __volatile__ ( - "sidt com32_internal_idtr\n\t" - "lidt com32_external_idtr\n\t" /* Set up IDT */ "movl %%esp, (com32_internal_esp)\n\t" /* Save internal virtual address space ESP */ "movl (com32_external_esp), %%esp\n\t" /* Switch to COM32 ESP (top of available memory) */ "call _virt_to_phys\n\t" /* Switch to flat physical address space */ @@ -110,8 +101,7 @@ static int com32_exec_loop ( struct image *image ) { "pushl $6\n\t" /* Number of additional arguments */ "call *%6\n\t" /* Execute image */ "cli\n\t" /* Disable interrupts */ - "call _phys_to_virt\n\t" /* Switch back to internal virtual address space */ - "lidt com32_internal_idtr\n\t" /* Switch back to internal IDT (for debugging) */ + "call _phys_to_virt\n\t" /* Switch back to internal virtual address space */ "movl (com32_internal_esp), %%esp\n\t" /* Switch back to internal stack */ : : @@ -201,55 +191,25 @@ static int com32_identify ( struct image *image ) { /** - * Load COM32 image into memory and set up the IDT + * Load COM32 image into memory * @v image COM32 image * @ret rc Return status code */ static int com32_load_image ( struct image *image ) { - physaddr_t com32_irq_wrapper_phys; - struct idt_descriptor *idt; - struct ijb_entry *ijb; size_t filesz, memsz; userptr_t buffer; - int rc, i; - - /* The interrupt descriptor table, interrupt jump buffer, and - * image data are all contiguous in memory. Prepare them all at once. - */ - filesz = image->len + - COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) + - COM32_NUM_IDT_ENTRIES * sizeof ( struct ijb_entry ); + int rc; + + filesz = image->len; memsz = filesz; - buffer = phys_to_user ( COM32_IDT ); + buffer = phys_to_user ( COM32_START_PHYS ); if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) { DBGC ( image, "COM32 %p: could not prepare segment: %s\n", image, strerror ( rc ) ); return rc; } - /* Write the IDT and IJB */ - idt = phys_to_virt ( COM32_IDT ); - ijb = phys_to_virt ( COM32_IJB ); - com32_irq_wrapper_phys = virt_to_phys ( com32_irq_wrapper ); - - for ( i = 0; i < COM32_NUM_IDT_ENTRIES; i++ ) { - uint32_t ijb_address = virt_to_phys ( &ijb[i] ); - - idt[i].offset_low = ijb_address & 0xFFFF; - idt[i].selector = PHYSICAL_CS; - idt[i].flags = IDT_INTERRUPT_GATE_FLAGS; - idt[i].offset_high = ijb_address >> 16; - - ijb[i].pusha_instruction = IJB_PUSHA; - ijb[i].mov_instruction = IJB_MOV_AL_IMM8; - ijb[i].mov_value = i; - ijb[i].jump_instruction = IJB_JMP_REL32; - ijb[i].jump_destination = com32_irq_wrapper_phys - - virt_to_phys ( &ijb[i + 1] ); - } - /* Copy image to segment */ - buffer = phys_to_user ( COM32_START_PHYS ); memcpy_user ( buffer, 0, image->data, 0, filesz ); return 0; diff --git a/roms/ipxe/src/arch/i386/image/elfboot.c b/roms/ipxe/src/arch/i386/image/elfboot.c index a867a9566..0f6957f02 100644 --- a/roms/ipxe/src/arch/i386/image/elfboot.c +++ b/roms/ipxe/src/arch/i386/image/elfboot.c @@ -60,10 +60,11 @@ static int elfboot_exec ( struct image *image ) { /* Jump to OS with flat physical addressing */ DBGC ( image, "ELF %p starting execution at %lx\n", image, entry ); - __asm__ __volatile__ ( PHYS_CODE ( "call *%%edi\n\t" ) + __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "call *%%edi\n\t" + "popl %%ebp\n\t" /* gcc bug */ ) : : "D" ( entry ) - : "eax", "ebx", "ecx", "edx", "esi", "ebp", - "memory" ); + : "eax", "ebx", "ecx", "edx", "esi", "memory" ); DBGC ( image, "ELF %p returned\n", image ); diff --git a/roms/ipxe/src/arch/i386/image/multiboot.c b/roms/ipxe/src/arch/i386/image/multiboot.c index 3d6d2bf34..86b0bc12d 100644 --- a/roms/ipxe/src/arch/i386/image/multiboot.c +++ b/roms/ipxe/src/arch/i386/image/multiboot.c @@ -152,8 +152,7 @@ static physaddr_t multiboot_add_cmdline ( struct image *image ) { size_t len; /* Copy image URI to base memory buffer as start of command line */ - len = ( unparse_uri ( buf, remaining, image->uri, - URI_ALL ) + 1 /* NUL */ ); + len = ( format_uri ( image->uri, buf, remaining ) + 1 /* NUL */ ); if ( len > remaining ) len = remaining; mb_cmdline_offset += len; diff --git a/roms/ipxe/src/arch/i386/image/nbi.c b/roms/ipxe/src/arch/i386/image/nbi.c index d3e523e92..99046144d 100644 --- a/roms/ipxe/src/arch/i386/image/nbi.c +++ b/roms/ipxe/src/arch/i386/image/nbi.c @@ -248,7 +248,8 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) { imgheader->execaddr.segoff.offset ); __asm__ __volatile__ ( - REAL_CODE ( "pushw %%ds\n\t" /* far pointer to bootp data */ + REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "pushw %%ds\n\t" /* far pointer to bootp data */ "pushw %%bx\n\t" "pushl %%esi\n\t" /* location */ "pushw %%cs\n\t" /* lcall execaddr */ @@ -258,13 +259,14 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) { "pushl %%edi\n\t" "lret\n\t" "\n2:\n\t" - "addw $8,%%sp\n\t" /* clean up stack */ ) + "addw $8,%%sp\n\t" /* clean up stack */ + "popl %%ebp\n\t" /* gcc bug */ ) : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ), "=b" ( discard_b ) : "D" ( imgheader->execaddr.segoff ), "S" ( imgheader->location ), "b" ( __from_data16 ( basemem_packet ) ) - : "ecx", "edx", "ebp" ); + : "ecx", "edx" ); return rc; } @@ -288,11 +290,13 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { /* Jump to OS with flat physical addressing */ __asm__ __volatile__ ( - PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */ + PHYS_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "pushl %%ebx\n\t" /* bootp data */ "pushl %%esi\n\t" /* imgheader */ "pushl %%eax\n\t" /* loaderinfo */ "call *%%edi\n\t" - "addl $12, %%esp\n\t" /* clean up stack */ ) + "addl $12, %%esp\n\t" /* clean up stack */ + "popl %%ebp\n\t" /* gcc bug */ ) : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ), "=b" ( discard_b ) : "D" ( imgheader->execaddr.linear ), @@ -300,7 +304,7 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { imgheader->location.offset ), "b" ( virt_to_phys ( basemem_packet ) ), "a" ( virt_to_phys ( &loaderinfo ) ) - : "ecx", "edx", "ebp", "memory" ); + : "ecx", "edx", "memory" ); return rc; } diff --git a/roms/ipxe/src/arch/i386/image/pxe_image.c b/roms/ipxe/src/arch/i386/image/pxe_image.c index 4a7d874be..dc28f6082 100644 --- a/roms/ipxe/src/arch/i386/image/pxe_image.c +++ b/roms/ipxe/src/arch/i386/image/pxe_image.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/segment.h> #include <ipxe/netdevice.h> #include <ipxe/features.h> +#include <ipxe/console.h> FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 ); @@ -74,6 +75,9 @@ static int pxe_exec ( struct image *image ) { /* Set PXE command line */ pxe_cmdline = image->cmdline; + /* Reset console since PXE NBP will probably use it */ + console_reset(); + /* Start PXE NBP */ rc = pxe_start_nbp(); diff --git a/roms/ipxe/src/arch/i386/include/bios.h b/roms/ipxe/src/arch/i386/include/bios.h index fadb9f1b7..3e6a845e3 100644 --- a/roms/ipxe/src/arch/i386/include/bios.h +++ b/roms/ipxe/src/arch/i386/include/bios.h @@ -6,6 +6,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define BDA_SEG 0x0040 #define BDA_EQUIPMENT_WORD 0x0010 #define BDA_FBMS 0x0013 +#define BDA_REBOOT 0x0072 +#define BDA_REBOOT_WARM 0x1234 #define BDA_NUM_DRIVES 0x0075 #endif /* BIOS_H */ diff --git a/roms/ipxe/src/arch/i386/include/bits/byteswap.h b/roms/ipxe/src/arch/i386/include/bits/byteswap.h index f3d30a254..0d9cb967c 100644 --- a/roms/ipxe/src/arch/i386/include/bits/byteswap.h +++ b/roms/ipxe/src/arch/i386/include/bits/byteswap.h @@ -53,8 +53,8 @@ __bswap_variable_64 ( uint64_t x ) { static inline __attribute__ (( always_inline )) void __bswap_64s ( uint64_t *x ) { struct { - uint32_t low; - uint32_t high; + uint32_t __attribute__ (( may_alias )) low; + uint32_t __attribute__ (( may_alias )) high; } __attribute__ (( may_alias )) *dwords = ( ( void * ) x ); uint32_t discard; diff --git a/roms/ipxe/src/arch/i386/include/bits/compiler.h b/roms/ipxe/src/arch/i386/include/bits/compiler.h index 000db0c14..d48b4b385 100644 --- a/roms/ipxe/src/arch/i386/include/bits/compiler.h +++ b/roms/ipxe/src/arch/i386/include/bits/compiler.h @@ -19,8 +19,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); * The implicit calls to memcpy() and memset() which gcc can generate * do not seem to have this inconsistency; -mregparm and -mrtd affect * them in the same way as any other function. + * + * Update (25/4/14): it appears that more recent gcc versions do allow + * -mrtd to affect calls to the implicit arithmetic functions. There + * is nothing obvious in the gcc changelogs to indicate precisely when + * this happened. From experimentation with available gcc versions, + * the change occurred sometime between v4.6.3 and v4.7.2. We assume + * that only versions up to v4.6.x require the special treatment. */ +#if ( __GNUC__ < 4 ) || ( ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ <= 6 ) ) #define __libgcc __attribute__ (( cdecl )) +#else +#define __libgcc +#endif #endif /* ASSEMBLY */ diff --git a/roms/ipxe/src/arch/i386/include/bits/profile.h b/roms/ipxe/src/arch/i386/include/bits/profile.h new file mode 100644 index 000000000..f3ee54ae9 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/bits/profile.h @@ -0,0 +1,28 @@ +#ifndef _BITS_PROFILE_H +#define _BITS_PROFILE_H + +/** @file + * + * Profiling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> + +/** + * Get profiling timestamp + * + * @ret timestamp Timestamp + */ +static inline __attribute__ (( always_inline )) uint64_t +profile_timestamp ( void ) { + uint64_t tsc; + + /* Read timestamp counter */ + __asm__ __volatile__ ( "rdtsc" : "=A" ( tsc ) ); + return tsc; +} + +#endif /* _BITS_PROFILE_H */ diff --git a/roms/ipxe/src/arch/i386/include/bits/reboot.h b/roms/ipxe/src/arch/i386/include/bits/reboot.h new file mode 100644 index 000000000..5b09e95f7 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/bits/reboot.h @@ -0,0 +1,14 @@ +#ifndef _BITS_REBOOT_H +#define _BITS_REBOOT_H + +/** @file + * + * i386-specific reboot API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/bios_reboot.h> + +#endif /* _BITS_REBOOT_H */ diff --git a/roms/ipxe/src/arch/i386/include/bits/strings.h b/roms/ipxe/src/arch/i386/include/bits/strings.h new file mode 100644 index 000000000..092bcb593 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/bits/strings.h @@ -0,0 +1,50 @@ +#ifndef _BITS_STRINGS_H +#define _BITS_STRINGS_H + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsl ( long value ) { + long msb_minus_one; + + /* If the input value is zero, the BSR instruction returns + * ZF=1 and leaves an undefined value in the output register. + * Perform this check in C rather than asm so that it can be + * omitted in cases where the compiler is able to prove that + * the input is non-zero. + */ + if ( value ) { + __asm__ ( "bsrl %1, %0" + : "=r" ( msb_minus_one ) + : "rm" ( value ) ); + return ( msb_minus_one + 1 ); + } else { + return 0; + } +} + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsll ( long long value ){ + unsigned long high = ( value >> 32 ); + unsigned long low = ( value >> 0 ); + + if ( high ) { + return ( 32 + __flsl ( high ) ); + } else if ( low ) { + return ( __flsl ( low ) ); + } else { + return 0; + } +} + +#endif /* _BITS_STRINGS_H */ diff --git a/roms/ipxe/src/arch/i386/include/comboot.h b/roms/ipxe/src/arch/i386/include/comboot.h index b34341398..2d2f04fe1 100644 --- a/roms/ipxe/src/arch/i386/include/comboot.h +++ b/roms/ipxe/src/arch/i386/include/comboot.h @@ -13,50 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <setjmp.h> #include <ipxe/in.h> -/** Descriptor in a 32-bit IDT */ -struct idt_descriptor { - uint16_t offset_low; - uint16_t selector; - uint16_t flags; - uint16_t offset_high; -} __attribute__ (( packed )); - -/** Operand for the LIDT instruction */ -struct idt_register { - uint16_t limit; - uint32_t base; -} __attribute__ (( packed )); - -/** Entry in the interrupt jump buffer */ -struct ijb_entry { - uint8_t pusha_instruction; - uint8_t mov_instruction; - uint8_t mov_value; - uint8_t jump_instruction; - uint32_t jump_destination; -} __attribute__ (( packed )); - -/** The x86 opcode for "pushal" */ -#define IJB_PUSHA 0x60 - -/** The x86 opcode for "movb $imm8,%al" */ -#define IJB_MOV_AL_IMM8 0xB0 - -/** The x86 opcode for "jmp rel32" */ -#define IJB_JMP_REL32 0xE9 - -/** Flags that specify a 32-bit interrupt gate with DPL=0 */ -#define IDT_INTERRUPT_GATE_FLAGS 0x8E00 - -/** Address of COM32 interrupt descriptor table */ -#define COM32_IDT 0x100000 - -/** Number of entries in a fully populated IDT */ -#define COM32_NUM_IDT_ENTRIES 256 - -/** Address of COM32 interrupt jump buffer */ -#define COM32_IJB 0x100800 - /** Segment used for COMBOOT PSP and image */ #define COMBOOT_PSP_SEG 0x07C0 @@ -153,7 +109,6 @@ extern void unhook_comboot_interrupts ( ); extern void com32_intcall_wrapper ( ); extern void com32_farcall_wrapper ( ); extern void com32_cfarcall_wrapper ( ); -extern void com32_irq_wrapper ( ); /* Resolve a hostname to an (IPv4) address */ extern int comboot_resolv ( const char *name, struct in_addr *address ); diff --git a/roms/ipxe/src/arch/i386/include/gdbmach.h b/roms/ipxe/src/arch/i386/include/gdbmach.h index 794dab193..416ae341a 100644 --- a/roms/ipxe/src/arch/i386/include/gdbmach.h +++ b/roms/ipxe/src/arch/i386/include/gdbmach.h @@ -46,6 +46,14 @@ enum { GDBMACH_AWATCH, }; +/* Interrupt vectors */ +extern void gdbmach_nocode_sigfpe ( void ); +extern void gdbmach_nocode_sigtrap ( void ); +extern void gdbmach_nocode_sigstkflt ( void ); +extern void gdbmach_nocode_sigill ( void ); +extern void gdbmach_withcode_sigbus ( void ); +extern void gdbmach_withcode_sigsegv ( void ); + static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) { regs [ GDBMACH_EIP ] = pc; } @@ -61,4 +69,6 @@ static inline void gdbmach_breakpoint ( void ) { extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ); +extern void gdbmach_init ( void ); + #endif /* GDBMACH_H */ diff --git a/roms/ipxe/src/arch/i386/include/initrd.h b/roms/ipxe/src/arch/i386/include/initrd.h index c25d0924b..a5659f43c 100644 --- a/roms/ipxe/src/arch/i386/include/initrd.h +++ b/roms/ipxe/src/arch/i386/include/initrd.h @@ -13,9 +13,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Minimum alignment for initrds * - * Chosen to maximise memcpy() speeds + * Some versions of Linux complain about initrds that are not + * page-aligned. */ -#define INITRD_ALIGN 4 +#define INITRD_ALIGN 4096 /** Minimum free space required to reshuffle initrds * diff --git a/roms/ipxe/src/arch/i386/include/int13.h b/roms/ipxe/src/arch/i386/include/int13.h index 5d36b6378..e337ca1d1 100644 --- a/roms/ipxe/src/arch/i386/include/int13.h +++ b/roms/ipxe/src/arch/i386/include/int13.h @@ -291,122 +291,6 @@ struct master_boot_record { /** MBR magic signature */ #define INT13_MBR_MAGIC 0xaa55 -/** ISO9660 block size */ -#define ISO9660_BLKSIZE 2048 - -/** An ISO9660 Primary Volume Descriptor (fixed portion) */ -struct iso9660_primary_descriptor_fixed { - /** Descriptor type */ - uint8_t type; - /** Identifier ("CD001") */ - uint8_t id[5]; -} __attribute__ (( packed )); - -/** An ISO9660 Primary Volume Descriptor */ -struct iso9660_primary_descriptor { - /** Fixed portion */ - struct iso9660_primary_descriptor_fixed fixed; -} __attribute__ (( packed )); - -/** ISO9660 Primary Volume Descriptor type */ -#define ISO9660_TYPE_PRIMARY 0x01 - -/** ISO9660 identifier */ -#define ISO9660_ID "CD001" - -/** ISO9660 Primary Volume Descriptor block address */ -#define ISO9660_PRIMARY_LBA 16 - -/** An El Torito Boot Record Volume Descriptor (fixed portion) */ -struct eltorito_descriptor_fixed { - /** Descriptor type */ - uint8_t type; - /** Identifier ("CD001") */ - uint8_t id[5]; - /** Version, must be 1 */ - uint8_t version; - /** Boot system indicator; must be "EL TORITO SPECIFICATION" */ - uint8_t system_id[32]; -} __attribute__ (( packed )); - -/** An El Torito Boot Record Volume Descriptor */ -struct eltorito_descriptor { - /** Fixed portion */ - struct eltorito_descriptor_fixed fixed; - /** Unused */ - uint8_t unused[32]; - /** Boot catalog sector */ - uint32_t sector; -} __attribute__ (( packed )); - -/** ISO9660 Boot Volume Descriptor type */ -#define ISO9660_TYPE_BOOT 0x00 - -/** El Torito Boot Record Volume Descriptor block address */ -#define ELTORITO_LBA 17 - -/** An El Torito Boot Catalog Validation Entry */ -struct eltorito_validation_entry { - /** Header ID; must be 1 */ - uint8_t header_id; - /** Platform ID - * - * 0 = 80x86 - * 1 = PowerPC - * 2 = Mac - */ - uint8_t platform_id; - /** Reserved */ - uint16_t reserved; - /** ID string */ - uint8_t id_string[24]; - /** Checksum word */ - uint16_t checksum; - /** Signature; must be 0xaa55 */ - uint16_t signature; -} __attribute__ (( packed )); - -/** El Torito platform IDs */ -enum eltorito_platform_id { - ELTORITO_PLATFORM_X86 = 0x00, - ELTORITO_PLATFORM_POWERPC = 0x01, - ELTORITO_PLATFORM_MAC = 0x02, -}; - -/** A bootable entry in the El Torito Boot Catalog */ -struct eltorito_boot_entry { - /** Boot indicator - * - * Must be @c ELTORITO_BOOTABLE for a bootable ISO image - */ - uint8_t indicator; - /** Media type - * - */ - uint8_t media_type; - /** Load segment */ - uint16_t load_segment; - /** System type */ - uint8_t filesystem; - /** Unused */ - uint8_t reserved_a; - /** Sector count */ - uint16_t length; - /** Starting sector */ - uint32_t start; - /** Unused */ - uint8_t reserved_b[20]; -} __attribute__ (( packed )); - -/** Boot indicator for a bootable ISO image */ -#define ELTORITO_BOOTABLE 0x88 - -/** El Torito media types */ -enum eltorito_media_type { - /** No emulation */ - ELTORITO_NO_EMULATION = 0, -}; - /** A floppy disk geometry */ struct int13_fdd_geometry { /** Number of tracks */ diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h new file mode 100644 index 000000000..a0845328d --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_reboot.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_BIOS_REBOOT_H +#define _IPXE_BIOS_REBOOT_H + +/** @file + * + * Standard PC-BIOS reboot mechanism + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#ifdef REBOOT_PCBIOS +#define REBOOT_PREFIX_pcbios +#else +#define REBOOT_PREFIX_pcbios __pcbios_ +#endif + +#endif /* _IPXE_BIOS_REBOOT_H */ diff --git a/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h b/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h new file mode 100644 index 000000000..3a9eb2495 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/ipxe/errno/pcbios.h @@ -0,0 +1,115 @@ +#ifndef _IPXE_ERRNO_PCBIOS_H +#define _IPXE_ERRNO_PCBIOS_H + +/** + * @file + * + * PC-BIOS platform error codes + * + * We use the PXE-specified error codes as the platform error codes + * for the PC-BIOS platform. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <pxe_error.h> + +/** + * Convert platform error code to platform component of iPXE error code + * + * @v platform Platform error code + * @ret errno Platform component of iPXE error code + */ +#define PLATFORM_TO_ERRNO( platform ) ( (platform) & 0xff ) + +/** + * Convert iPXE error code to platform error code + * + * @v errno iPXE error code + * @ret platform Platform error code + */ +#define ERRNO_TO_PLATFORM( errno ) ( (errno) & 0xff ) + +/* Platform-specific error codes */ +#define PLATFORM_ENOERR PXENV_STATUS_SUCCESS +#define PLATFORM_E2BIG PXENV_STATUS_BAD_FUNC +#define PLATFORM_EACCES PXENV_STATUS_TFTP_ACCESS_VIOLATION +#define PLATFORM_EADDRINUSE PXENV_STATUS_UDP_OPEN +#define PLATFORM_EADDRNOTAVAIL PXENV_STATUS_UDP_OPEN +#define PLATFORM_EAFNOSUPPORT PXENV_STATUS_UNSUPPORTED +#define PLATFORM_EAGAIN PXENV_STATUS_FAILURE +#define PLATFORM_EALREADY PXENV_STATUS_UDP_OPEN +#define PLATFORM_EBADF PXENV_STATUS_TFTP_CLOSED +#define PLATFORM_EBADMSG PXENV_STATUS_FAILURE +#define PLATFORM_EBUSY PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_ECANCELED PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE +#define PLATFORM_ECHILD PXENV_STATUS_TFTP_FILE_NOT_FOUND +#define PLATFORM_ECONNABORTED PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION +#define PLATFORM_ECONNREFUSED PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION +#define PLATFORM_ECONNRESET PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION +#define PLATFORM_EDEADLK PXENV_STATUS_FAILURE +#define PLATFORM_EDESTADDRREQ PXENV_STATUS_BAD_FUNC +#define PLATFORM_EDOM PXENV_STATUS_FAILURE +#define PLATFORM_EDQUOT PXENV_STATUS_FAILURE +#define PLATFORM_EEXIST PXENV_STATUS_FAILURE +#define PLATFORM_EFAULT PXENV_STATUS_MCOPY_PROBLEM +#define PLATFORM_EFBIG PXENV_STATUS_MCOPY_PROBLEM +#define PLATFORM_EHOSTUNREACH PXENV_STATUS_ARP_TIMEOUT +#define PLATFORM_EIDRM PXENV_STATUS_FAILURE +#define PLATFORM_EILSEQ PXENV_STATUS_FAILURE +#define PLATFORM_EINPROGRESS PXENV_STATUS_FAILURE +#define PLATFORM_EINTR PXENV_STATUS_FAILURE +#define PLATFORM_EINVAL PXENV_STATUS_BAD_FUNC +#define PLATFORM_EIO PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION +#define PLATFORM_EISCONN PXENV_STATUS_UDP_OPEN +#define PLATFORM_EISDIR PXENV_STATUS_FAILURE +#define PLATFORM_ELOOP PXENV_STATUS_FAILURE +#define PLATFORM_EMFILE PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_EMLINK PXENV_STATUS_FAILURE +#define PLATFORM_EMSGSIZE PXENV_STATUS_BAD_FUNC +#define PLATFORM_EMULTIHOP PXENV_STATUS_FAILURE +#define PLATFORM_ENAMETOOLONG PXENV_STATUS_FAILURE +#define PLATFORM_ENETDOWN PXENV_STATUS_ARP_TIMEOUT +#define PLATFORM_ENETRESET PXENV_STATUS_FAILURE +#define PLATFORM_ENETUNREACH PXENV_STATUS_ARP_TIMEOUT +#define PLATFORM_ENFILE PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_ENOBUFS PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_ENODATA PXENV_STATUS_FAILURE +#define PLATFORM_ENODEV PXENV_STATUS_TFTP_FILE_NOT_FOUND +#define PLATFORM_ENOENT PXENV_STATUS_TFTP_FILE_NOT_FOUND +#define PLATFORM_ENOEXEC PXENV_STATUS_FAILURE +#define PLATFORM_ENOLCK PXENV_STATUS_FAILURE +#define PLATFORM_ENOLINK PXENV_STATUS_FAILURE +#define PLATFORM_ENOMEM PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_ENOMSG PXENV_STATUS_FAILURE +#define PLATFORM_ENOPROTOOPT PXENV_STATUS_UNSUPPORTED +#define PLATFORM_ENOSPC PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_ENOSR PXENV_STATUS_OUT_OF_RESOURCES +#define PLATFORM_ENOSTR PXENV_STATUS_FAILURE +#define PLATFORM_ENOSYS PXENV_STATUS_UNSUPPORTED +#define PLATFORM_ENOTCONN PXENV_STATUS_FAILURE +#define PLATFORM_ENOTDIR PXENV_STATUS_FAILURE +#define PLATFORM_ENOTEMPTY PXENV_STATUS_FAILURE +#define PLATFORM_ENOTSOCK PXENV_STATUS_FAILURE +#define PLATFORM_ENOTSUP PXENV_STATUS_UNSUPPORTED +#define PLATFORM_ENOTTY PXENV_STATUS_FAILURE +#define PLATFORM_ENXIO PXENV_STATUS_TFTP_FILE_NOT_FOUND +#define PLATFORM_EOPNOTSUPP PXENV_STATUS_UNSUPPORTED +#define PLATFORM_EOVERFLOW PXENV_STATUS_FAILURE +#define PLATFORM_EPERM PXENV_STATUS_TFTP_ACCESS_VIOLATION +#define PLATFORM_EPIPE PXENV_STATUS_FAILURE +#define PLATFORM_EPROTO PXENV_STATUS_FAILURE +#define PLATFORM_EPROTONOSUPPORT PXENV_STATUS_UNSUPPORTED +#define PLATFORM_EPROTOTYPE PXENV_STATUS_FAILURE +#define PLATFORM_ERANGE PXENV_STATUS_FAILURE +#define PLATFORM_EROFS PXENV_STATUS_FAILURE +#define PLATFORM_ESPIPE PXENV_STATUS_FAILURE +#define PLATFORM_ESRCH PXENV_STATUS_TFTP_FILE_NOT_FOUND +#define PLATFORM_ESTALE PXENV_STATUS_FAILURE +#define PLATFORM_ETIME PXENV_STATUS_FAILURE +#define PLATFORM_ETIMEDOUT PXENV_STATUS_TFTP_READ_TIMEOUT +#define PLATFORM_ETXTBSY PXENV_STATUS_FAILURE +#define PLATFORM_EWOULDBLOCK PXENV_STATUS_TFTP_OPEN +#define PLATFORM_EXDEV PXENV_STATUS_FAILURE + +#endif /* _IPXE_ERRNO_PCBIOS_H */ diff --git a/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h b/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h new file mode 100644 index 000000000..48cd6a7b7 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/ipxe/vesafb.h @@ -0,0 +1,210 @@ +#ifndef _IPXE_VESAFB_H +#define _IPXE_VESAFB_H + +/** @file + * + * VESA frame buffer console + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <realmode.h> + +/** INT 10,4f00: return controller information */ +#define VBE_CONTROLLER_INFO 0x4f00 + +/** VBE controller information */ +struct vbe_controller_info { + /** VBE signature */ + uint32_t vbe_signature; + /** VBE minor version */ + uint8_t vbe_minor_version; + /** VBE major version */ + uint8_t vbe_major_version; + /** Pointer to OEM string */ + struct segoff oem_string_ptr; + /** Capabilities of graphics controller */ + uint32_t capabilities; + /** Pointer to video mode list */ + struct segoff video_mode_ptr; + /** Number of 64kB memory blocks */ + uint16_t total_memory; + /** VBE implementation software revision */ + uint16_t oem_software_rev; + /** Pointer to vendor name string */ + struct segoff oem_vendor_name_ptr; + /** Pointer to product name string */ + struct segoff oem_product_name_ptr; + /** Pointer to product revision string */ + struct segoff oem_product_rev_ptr; + /** Reserved for VBE implementation scratch area */ + uint8_t reserved[222]; + /* VBE2.0 defines an additional 256-byte data area for + * including the OEM strings inline within the VBE information + * block; we omit this to reduce the amount of base memory + * required for VBE calls. + */ +} __attribute__ (( packed )); + +/** VBE controller information signature */ +#define VBE_CONTROLLER_SIGNATURE \ + ( ( 'V' << 0 ) | ( 'E' << 8 ) | ( 'S' << 16 ) | ( 'A' << 24 ) ) + +/** VBE mode list end marker */ +#define VBE_MODE_END 0xffff + +/** INT 10,4f01: return VBE mode information */ +#define VBE_MODE_INFO 0x4f01 + +/** VBE mode information */ +struct vbe_mode_info { + /** Mode attributes */ + uint16_t mode_attributes; + /** Window A attributes */ + uint8_t win_a_attributes; + /** Window B attributes */ + uint8_t win_b_attributes; + /** Window granularity */ + uint16_t win_granularity; + /** Window size */ + uint16_t win_size; + /** Window A start segment */ + uint16_t win_a_segment; + /** Window B start segment */ + uint16_t win_b_segment; + /** Pointer to window function */ + struct segoff win_func_ptr; + /** Bytes per scan line */ + uint16_t bytes_per_scan_line; + /** Horizontal resolution in pixels or characters */ + uint16_t x_resolution; + /** Vertical resolution in pixels or characters */ + uint16_t y_resolution; + /** Character cell width in pixels */ + uint8_t x_char_size; + /** Character cell height in pixels */ + uint8_t y_char_size; + /** Number of memory planes */ + uint8_t number_of_planes; + /** Bits per pixel */ + uint8_t bits_per_pixel; + /** Number of banks */ + uint8_t number_of_banks; + /** Memory model type */ + uint8_t memory_model; + /** Bank size in kB */ + uint8_t bank_size; + /** Number of images */ + uint8_t number_of_image_pages; + /** Reserved for page function */ + uint8_t reserved_1; + /** Size of direct colour red mask in bits */ + uint8_t red_mask_size; + /** Bit position of LSB of red mask */ + uint8_t red_field_position; + /** Size of direct colour green mask in bits */ + uint8_t green_mask_size; + /** Bit position of LSB of green mask */ + uint8_t green_field_position; + /** Size of direct colour blue mask in bits */ + uint8_t blue_mask_size; + /** Bit position of LSB of blue mask */ + uint8_t blue_field_position; + /** Size of direct colour reserved mask in bits */ + uint8_t rsvd_mask_size; + /** Bit position of LSB of reserved mask */ + uint8_t rsvd_field_position; + /** Direct colour mode attributes */ + uint8_t direct_colour_mode_info; + /** Physical address for flat memory frame buffer */ + uint32_t phys_base_ptr; + /** Pointer to start of off-screen memory */ + uint32_t off_screen_mem_offset; + /** Amount of off-screen memory in 1kB units */ + uint16_t off_screen_mem_size; + /** Reserved */ + uint8_t reserved_2[206]; +} __attribute__ (( packed )); + +/** VBE mode attributes */ +enum vbe_mode_attributes { + /** Mode supported in hardware */ + VBE_MODE_ATTR_SUPPORTED = 0x0001, + /** TTY output functions supported by BIOS */ + VBE_MODE_ATTR_TTY = 0x0004, + /** Colour mode */ + VBE_MODE_ATTR_COLOUR = 0x0008, + /** Graphics mode */ + VBE_MODE_ATTR_GRAPHICS = 0x0010, + /** Not a VGA compatible mode */ + VBE_MODE_ATTR_NOT_VGA = 0x0020, + /** VGA compatible windowed memory mode is not available */ + VBE_MODE_ATTR_NOT_WINDOWED = 0x0040, + /** Linear frame buffer mode is available */ + VBE_MODE_ATTR_LINEAR = 0x0080, + /** Double scan mode is available */ + VBE_MODE_ATTR_DOUBLE = 0x0100, + /** Interlaced mode is available */ + VBE_MODE_ATTR_INTERLACED = 0x0200, + /** Hardware triple buffering support */ + VBE_MODE_ATTR_TRIPLE_BUF = 0x0400, + /** Hardware stereoscopic display support */ + VBE_MODE_ATTR_STEREO = 0x0800, + /** Dual display start address support */ + VBE_MODE_ATTR_DUAL = 0x1000, +}; + +/** VBE mode memory models */ +enum vbe_mode_memory_model { + /** Text mode */ + VBE_MODE_MODEL_TEXT = 0x00, + /** CGA graphics mode */ + VBE_MODE_MODEL_CGA = 0x01, + /** Hercules graphics mode */ + VBE_MODE_MODEL_HERCULES = 0x02, + /** Planar mode */ + VBE_MODE_MODEL_PLANAR = 0x03, + /** Packed pixel mode */ + VBE_MODE_MODEL_PACKED_PIXEL = 0x04, + /** Non-chain 4, 256 colour mode */ + VBE_MODE_MODEL_NON_CHAIN_4 = 0x05, + /** Direct colour mode */ + VBE_MODE_MODEL_DIRECT_COLOUR = 0x06, + /** YUV mode */ + VBE_MODE_MODEL_YUV = 0x07, +}; + +/** INT 10,4f02: set VBE mode */ +#define VBE_SET_MODE 0x4f02 + +/** VBE linear frame buffer mode bit */ +#define VBE_MODE_LINEAR 0x4000 + +/** INT 10,1130: get font information */ +#define VBE_GET_FONT 0x1130 + +/** Font sets */ +enum vbe_font_set { + /** 8x14 character font */ + VBE_FONT_8x14 = 0x0200, + /** 8x8 double dot font */ + VBE_FONT_8x8_DOUBLE = 0x0300, + /** 8x8 double dot font (high 128 characters) */ + VBE_FONT_8x8_DOUBLE_HIGH = 0x0400, + /** 9x14 alpha alternate font */ + VBE_FONT_9x14_ALPHA_ALT = 0x0500, + /** 8x16 font */ + VBE_FONT_8x16 = 0x0600, + /** 9x16 alternate font */ + VBE_FONT_9x16_ALT = 0x0700, +}; + +/** INT 10,00: set VGA mode */ +#define VBE_SET_VGA_MODE 0x0000 + +/** INT 10,0f: get VGA mode */ +#define VBE_GET_VGA_MODE 0x0f00 + +#endif /* _IPXE_VESAFB_H */ diff --git a/roms/ipxe/src/arch/i386/include/librm.h b/roms/ipxe/src/arch/i386/include/librm.h index 801f586b8..c8ba72b53 100644 --- a/roms/ipxe/src/arch/i386/include/librm.h +++ b/roms/ipxe/src/arch/i386/include/librm.h @@ -88,6 +88,13 @@ UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off, trivial_memmove_user ( dest, dest_off, src, src_off, len ); } +static inline __always_inline int +UACCESS_INLINE ( librm, memcmp_user ) ( userptr_t first, off_t first_off, + userptr_t second, off_t second_off, + size_t len ) { + return trivial_memcmp_user ( first, first_off, second, second_off, len); +} + static inline __always_inline void UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset, int c, size_t len ) { @@ -158,8 +165,8 @@ extern char *text16; /* Variables in librm.S, present in the normal data segment */ extern uint16_t rm_sp; extern uint16_t rm_ss; -extern uint16_t __data16 ( rm_cs ); -#define rm_cs __use_data16 ( rm_cs ) +extern uint16_t __text16 ( rm_cs ); +#define rm_cs __use_text16 ( rm_cs ) extern uint16_t __text16 ( rm_ds ); #define rm_ds __use_text16 ( rm_ds ) @@ -202,6 +209,71 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size ); asm_code_str \ "call _phys_to_virt\n\t" +/** Number of interrupts */ +#define NUM_INT 256 + +/** An interrupt descriptor table register */ +struct idtr { + /** Limit */ + uint16_t limit; + /** Base */ + uint32_t base; +} __attribute__ (( packed )); + +/** An interrupt descriptor table entry */ +struct interrupt_descriptor { + /** Low 16 bits of address */ + uint16_t low; + /** Code segment */ + uint16_t segment; + /** Unused */ + uint8_t unused; + /** Type and attributes */ + uint8_t attr; + /** High 16 bits of address */ + uint16_t high; +} __attribute__ (( packed )); + +/** Interrupt descriptor is present */ +#define IDTE_PRESENT 0x80 + +/** Interrupt descriptor 32-bit interrupt gate type */ +#define IDTE_TYPE_IRQ32 0x0e + +/** An interrupt vector + * + * Each interrupt vector comprises an eight-byte fragment of code: + * + * 60 pushal + * b0 xx movb $INT, %al + * e9 xx xx xx xx jmp interrupt_wrapper + */ +struct interrupt_vector { + /** "pushal" instruction */ + uint8_t pushal; + /** "movb" instruction */ + uint8_t movb; + /** Interrupt number */ + uint8_t intr; + /** "jmp" instruction */ + uint8_t jmp; + /** Interrupt wrapper address offset */ + uint32_t offset; + /** Next instruction after jump */ + uint8_t next[0]; +} __attribute__ (( packed )); + +/** "pushal" instruction */ +#define PUSHAL_INSN 0x60 + +/** "movb" instruction */ +#define MOVB_INSN 0xb0 + +/** "jmp" instruction */ +#define JMP_INSN 0xe9 + +extern void set_interrupt_vector ( unsigned int intr, void *vector ); + #endif /* ASSEMBLY */ #endif /* LIBRM_H */ diff --git a/roms/ipxe/src/arch/i386/include/pxe.h b/roms/ipxe/src/arch/i386/include/pxe.h index 0206f683a..b95b0cce5 100644 --- a/roms/ipxe/src/arch/i386/include/pxe.h +++ b/roms/ipxe/src/arch/i386/include/pxe.h @@ -4,6 +4,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include "pxe_types.h" +#include "pxe_error.h" #include "pxe_api.h" #include <ipxe/device.h> #include <ipxe/tables.h> diff --git a/roms/ipxe/src/arch/i386/include/pxe_error.h b/roms/ipxe/src/arch/i386/include/pxe_error.h new file mode 100644 index 000000000..a1398cbd4 --- /dev/null +++ b/roms/ipxe/src/arch/i386/include/pxe_error.h @@ -0,0 +1,123 @@ +#ifndef PXE_ERROR_H +#define PXE_ERROR_H + +/** @file + * + * Preboot eXecution Environment (PXE) error definitions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @defgroup pxeerrors PXE error codes + * + * @{ + */ + +/* Generic errors */ +#define PXENV_STATUS_SUCCESS 0x0000 +#define PXENV_STATUS_FAILURE 0x0001 +#define PXENV_STATUS_BAD_FUNC 0x0002 +#define PXENV_STATUS_UNSUPPORTED 0x0003 +#define PXENV_STATUS_KEEP_UNDI 0x0004 +#define PXENV_STATUS_KEEP_ALL 0x0005 +#define PXENV_STATUS_OUT_OF_RESOURCES 0x0006 + +/* ARP errors (0x0010 to 0x001f) */ +#define PXENV_STATUS_ARP_TIMEOUT 0x0011 + +/* Base-Code state errors */ +#define PXENV_STATUS_UDP_CLOSED 0x0018 +#define PXENV_STATUS_UDP_OPEN 0x0019 +#define PXENV_STATUS_TFTP_CLOSED 0x001a +#define PXENV_STATUS_TFTP_OPEN 0x001b + +/* BIOS/system errors (0x0020 to 0x002f) */ +#define PXENV_STATUS_MCOPY_PROBLEM 0x0020 +#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x0021 +#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x0022 +#define PXENV_STATUS_BIS_INIT_FAILURE 0x0023 +#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x0024 +#define PXENV_STATUS_BIS_GBOA_FAILURE 0x0025 +#define PXENV_STATUS_BIS_FREE_FAILURE 0x0026 +#define PXENV_STATUS_BIS_GSI_FAILURE 0x0027 +#define PXENV_STATUS_BIS_BAD_CKSUM 0x0028 + +/* TFTP/MTFTP errors (0x0030 to 0x003f) */ +#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x0030 +#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x0032 +#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x0033 +#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x0035 +#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x0036 +#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x0038 +#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x0039 +#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x003a +#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x003b +#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x003c +#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x003d +#define PXENV_STATUS_TFTP_NO_FILESIZE 0x003e +#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x003f + +/* Reserved errors 0x0040 to 0x004f) */ + +/* DHCP/BOOTP errors (0x0050 to 0x005f) */ +#define PXENV_STATUS_DHCP_TIMEOUT 0x0051 +#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x0052 +#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x0053 +#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x0054 + +/* Driver errors (0x0060 to 0x006f) */ +#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x0060 +#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x0061 +#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x0062 +#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x0063 +#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x0064 +#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x0065 +#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x0066 +#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x0067 +#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x0068 +#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x0069 +#define PXENV_STATUS_UNDI_INVALID_STATE 0x006a +#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x006b +#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x006c + +/* ROM and NBP bootstrap errors (0x0070 to 0x007f) */ +#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x0074 +#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x0076 +#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x0077 +#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x0078 +#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x0079 + +/* Environment NBP errors (0x0080 to 0x008f) */ + +/* Reserved errors (0x0090 to 0x009f) */ + +/* Miscellaneous errors (0x00a0 to 0x00af) */ +#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0x00a0 +#define PXENV_STATUS_BINL_NO_PXE_SERVER 0x00a1 +#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0x00a2 +#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0x00a3 + +/* BUSD errors (0x00b0 to 0x00bf) */ +#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0x00b0 + +/* Loader errors (0x00c0 to 0x00cf) */ +#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0x00c0 +#define PXENV_STATUS_LOADER_NO_BC_ROMID 0x00c1 +#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0x00c2 +#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0x00c3 +#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0x00c4 +#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0x00c5 +#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0x00c6 +#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0x00c8 +#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0x00c9 +#define PXENV_STATUS_LOADER_UNDI_START 0x00ca +#define PXENV_STATUS_LOADER_BC_START 0x00cb + +/** @} */ + +/** Derive PXENV_STATUS code from iPXE error number */ +#define PXENV_STATUS( rc ) ( (-(rc)) & 0x00ff ) + +#endif /* PXE_ERROR_H */ diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/apm.c b/roms/ipxe/src/arch/i386/interface/pcbios/apm.c new file mode 100644 index 000000000..3b13e1cd0 --- /dev/null +++ b/roms/ipxe/src/arch/i386/interface/pcbios/apm.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * Advanced Power Management + * + */ + +#include <errno.h> +#include <realmode.h> +#include <ipxe/reboot.h> + +/** + * Power off the computer using APM + * + * @ret rc Return status code + */ +static int apm_poweroff ( void ) { + uint16_t apm_version; + uint16_t apm_signature; + uint16_t apm_flags; + uint16_t carry; + + /* APM check */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t" + "adc %%edx,0\n\t" ) + : "=a" ( apm_version ), "=b" ( apm_signature ), + "=c" ( apm_flags ), "=d" ( carry ) + : "a" ( 0x5300 ), "b" ( 0x0000 ), + "d" ( 0x0000 ) ); + if ( carry ) { + DBG ( "APM not present\n" ); + return -ENOTSUP; + } + if ( apm_signature != 0x504d ) { /* signature 'PM' */ + DBG ( "APM not present\n" ); + return -ENOTSUP; + } + if ( apm_version < 0x0101 ) { /* Need version 1.1+ */ + DBG ( "APM 1.1+ not supported\n" ); + return -ENOTSUP; + } + if ( ( apm_flags & 0x8 ) == 0x8 ) { + DBG ( "APM power management disabled\n" ); + return -EPERM; + } + DBG2 ( "APM check completed\n" ); + + /* APM initialisation */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t" + "adc %%edx,0\n\t" ) + : "=d" ( carry ) + : "a" ( 0x5301 ), "b" ( 0x0000 ), + "d" ( 0x0000 ) ); + if ( carry ) { + DBG ( "APM initialisation failed\n" ); + return -EIO; + } + DBG2 ( "APM initialisation completed\n" ); + + /* Set APM driver version */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t" + "adc %%edx,0\n\t" ) + : "=d" ( carry ) + : "a" ( 0x530e ), "b" ( 0x0000 ), + "c" ( 0x0101 ), "d" ( 0x0000 ) ); + if ( carry ) { + DBG ( "APM setting driver version failed\n" ); + return -EIO; + } + DBG2 ( "APM driver version set\n" ); + + /* Setting power state to off */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x15\n\t" + "adc %%edx,0\n\t" ) + : "=d" ( carry ) + : "a" ( 0x5307 ), "b" ( 0x0001 ), + "c" ( 0x0003 ), "d" ( 0x0000) ); + if ( carry ) { + DBG ( "APM setting power state failed\n" ); + return -ENOTTY; + } + + /* Should never happen */ + return -ECANCELED; +} + +PROVIDE_REBOOT ( pcbios, poweroff, apm_poweroff ); diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c index 7f4614666..1e7de756b 100644 --- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c +++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_nap.c @@ -8,9 +8,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ static void bios_cpu_nap ( void ) { - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "hlt\n\t" - "cli\n\t" ) : : ); + __asm__ __volatile__ ( "sti\n\t" + "hlt\n\t" + "cli\n\t" ); } PROVIDE_NAP ( pcbios, cpu_nap, bios_cpu_nap ); diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c new file mode 100644 index 000000000..68546b2e5 --- /dev/null +++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_reboot.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Standard PC-BIOS reboot mechanism + * + */ + +#include <ipxe/reboot.h> +#include <realmode.h> +#include <bios.h> + +/** + * Reboot system + * + * @v warm Perform a warm reboot + */ +static void bios_reboot ( int warm ) { + uint16_t flag; + + /* Configure BIOS for cold/warm reboot */ + flag = ( warm ? BDA_REBOOT_WARM : 0 ); + put_real ( flag, BDA_SEG, BDA_REBOOT ); + + /* Jump to system reset vector */ + __asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) : : ); +} + +PROVIDE_REBOOT ( pcbios, reboot, bios_reboot ); diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c index 2ecc24ea5..dd7897e29 100644 --- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c +++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c @@ -41,47 +41,21 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret rc Return status code */ static int bios_find_smbios ( struct smbios *smbios ) { - union { - struct smbios_entry entry; - uint8_t bytes[256]; /* 256 is maximum length possible */ - } u; - static unsigned int offset = 0; - size_t len; - unsigned int i; - uint8_t sum; + struct smbios_entry entry; + int rc; - /* Try to find SMBIOS */ - for ( ; offset < 0x10000 ; offset += 0x10 ) { + /* Scan through BIOS segment to find SMBIOS entry point */ + if ( ( rc = find_smbios_entry ( real_to_user ( BIOS_SEG, 0 ), 0x10000, + &entry ) ) != 0 ) + return rc; - /* Read start of header and verify signature */ - copy_from_real ( &u.entry, BIOS_SEG, offset, - sizeof ( u.entry )); - if ( u.entry.signature != SMBIOS_SIGNATURE ) - continue; + /* Fill in entry point descriptor structure */ + smbios->address = phys_to_user ( entry.smbios_address ); + smbios->len = entry.smbios_len; + smbios->count = entry.smbios_count; + smbios->version = SMBIOS_VERSION ( entry.major, entry.minor ); - /* Read whole header and verify checksum */ - len = u.entry.len; - copy_from_real ( &u.bytes, BIOS_SEG, offset, len ); - for ( i = 0 , sum = 0 ; i < len ; i++ ) { - sum += u.bytes[i]; - } - if ( sum != 0 ) { - DBG ( "SMBIOS at %04x:%04x has bad checksum %02x\n", - BIOS_SEG, offset, sum ); - continue; - } - - /* Fill result structure */ - DBG ( "Found SMBIOS v%d.%d entry point at %04x:%04x\n", - u.entry.major, u.entry.minor, BIOS_SEG, offset ); - smbios->address = phys_to_user ( u.entry.smbios_address ); - smbios->len = u.entry.smbios_len; - smbios->count = u.entry.smbios_count; - return 0; - } - - DBG ( "No SMBIOS found\n" ); - return -ENODEV; + return 0; } PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios ); diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c index 3cb8756f7..65bbf9e01 100644 --- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c +++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c @@ -44,10 +44,10 @@ static unsigned long bios_currticks ( void ) { uint8_t midnight; /* Re-enable interrupts so that the timer interrupt can occur */ - __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" - "nop\n\t" - "nop\n\t" - "cli\n\t" ) : : ); + __asm__ __volatile__ ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ); get_real ( ticks, BDA_SEG, 0x006c ); get_real ( midnight, BDA_SEG, 0x0070 ); diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/int13.c b/roms/ipxe/src/arch/i386/interface/pcbios/int13.c index 263f861e4..1c7a8128f 100644 --- a/roms/ipxe/src/arch/i386/interface/pcbios/int13.c +++ b/roms/ipxe/src/arch/i386/interface/pcbios/int13.c @@ -38,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/sanboot.h> #include <ipxe/device.h> #include <ipxe/pci.h> +#include <ipxe/iso9660.h> +#include <ipxe/eltorito.h> #include <realmode.h> #include <bios.h> #include <biosint.h> diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c b/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c new file mode 100644 index 000000000..2adc7b040 --- /dev/null +++ b/roms/ipxe/src/arch/i386/interface/pcbios/vesafb.c @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * VESA frame buffer console + * + */ + +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#include <realmode.h> +#include <ipxe/console.h> +#include <ipxe/io.h> +#include <ipxe/ansicol.h> +#include <ipxe/fbcon.h> +#include <ipxe/vesafb.h> +#include <config/console.h> + +/* Avoid dragging in BIOS console if not otherwise used */ +extern struct console_driver bios_console; +struct console_driver bios_console __attribute__ (( weak )); + +/* Disambiguate the various error causes */ +#define EIO_FAILED __einfo_error ( EINFO_EIO_FAILED ) +#define EINFO_EIO_FAILED \ + __einfo_uniqify ( EINFO_EIO, 0x01, \ + "Function call failed" ) +#define EIO_HARDWARE __einfo_error ( EINFO_EIO_HARDWARE ) +#define EINFO_EIO_HARDWARE \ + __einfo_uniqify ( EINFO_EIO, 0x02, \ + "Not supported in current configuration" ) +#define EIO_MODE __einfo_error ( EINFO_EIO_MODE ) +#define EINFO_EIO_MODE \ + __einfo_uniqify ( EINFO_EIO, 0x03, \ + "Invalid in current video mode" ) +#define EIO_VBE( code ) \ + EUNIQ ( EINFO_EIO, (code), EIO_FAILED, EIO_HARDWARE, EIO_MODE ) + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_VESAFB ) && CONSOLE_EXPLICIT ( CONSOLE_VESAFB ) ) +#undef CONSOLE_VESAFB +#define CONSOLE_VESAFB ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) +#endif + +/** Font corresponding to selected character width and height */ +#define VESAFB_FONT VBE_FONT_8x16 + +/* Forward declaration */ +struct console_driver vesafb_console __console_driver; + +/** A VESA frame buffer */ +struct vesafb { + /** Frame buffer console */ + struct fbcon fbcon; + /** Physical start address */ + physaddr_t start; + /** Pixel geometry */ + struct fbcon_geometry pixel; + /** Margin */ + struct fbcon_margin margin; + /** Colour mapping */ + struct fbcon_colour_map map; + /** Font definition */ + struct fbcon_font font; + /** Saved VGA mode */ + uint8_t saved_mode; +}; + +/** The VESA frame buffer */ +static struct vesafb vesafb; + +/** Base memory buffer used for VBE calls */ +union vbe_buffer { + /** VBE controller information block */ + struct vbe_controller_info controller; + /** VBE mode information block */ + struct vbe_mode_info mode; +}; +static union vbe_buffer __bss16 ( vbe_buf ); +#define vbe_buf __use_data16 ( vbe_buf ) + +/** + * Convert VBE status code to iPXE status code + * + * @v status VBE status code + * @ret rc Return status code + */ +static int vesafb_rc ( unsigned int status ) { + unsigned int code; + + if ( ( status & 0xff ) != 0x4f ) + return -ENOTSUP; + code = ( ( status >> 8 ) & 0xff ); + return ( code ? -EIO_VBE ( code ) : 0 ); +} + +/** + * Get font definition + * + */ +static void vesafb_font ( void ) { + struct segoff font; + + /* Get font information + * + * Working around gcc bugs is icky here. The value we want is + * returned in %ebp, but there's no way to specify %ebp in an + * output constraint. We can't put %ebp in the clobber list, + * because this tends to cause random build failures on some + * gcc versions. We can't manually push/pop %ebp and return + * the value via a generic register output constraint, because + * gcc might choose to use %ebp to satisfy that constraint + * (and we have no way to prevent it from so doing). + * + * Work around this hideous mess by using %ecx and %edx as the + * output registers, since they get clobbered anyway. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushw %%bp\n\t" /* gcc bug */ + "int $0x10\n\t" + "movw %%es, %%cx\n\t" + "movw %%bp, %%dx\n\t" + "popw %%bp\n\t" /* gcc bug */ ) + : "=c" ( font.segment ), + "=d" ( font.offset ) + : "a" ( VBE_GET_FONT ), + "b" ( VESAFB_FONT ) ); + DBGC ( &vbe_buf, "VESAFB has font %04x at %04x:%04x\n", + VESAFB_FONT, font.segment, font.offset ); + vesafb.font.start = real_to_user ( font.segment, font.offset ); +} + +/** + * Get VBE mode list + * + * @ret mode_numbers Mode number list (terminated with VBE_MODE_END) + * @ret rc Return status code + * + * The caller is responsible for eventually freeing the mode list. + */ +static int vesafb_mode_list ( uint16_t **mode_numbers ) { + struct vbe_controller_info *controller = &vbe_buf.controller; + userptr_t video_mode_ptr; + uint16_t mode_number; + uint16_t status; + size_t len; + int rc; + + /* Avoid returning uninitialised data on error */ + *mode_numbers = NULL; + + /* Get controller information block */ + controller->vbe_signature = 0; + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( status ) + : "a" ( VBE_CONTROLLER_INFO ), + "D" ( __from_data16 ( controller ) ) + : "memory", "ebx", "edx" ); + if ( ( rc = vesafb_rc ( status ) ) != 0 ) { + DBGC ( &vbe_buf, "VESAFB could not get controller information: " + "[%04x] %s\n", status, strerror ( rc ) ); + return rc; + } + if ( controller->vbe_signature != VBE_CONTROLLER_SIGNATURE ) { + DBGC ( &vbe_buf, "VESAFB invalid controller signature " + "\"%c%c%c%c\"\n", ( controller->vbe_signature >> 0 ), + ( controller->vbe_signature >> 8 ), + ( controller->vbe_signature >> 16 ), + ( controller->vbe_signature >> 24 ) ); + DBGC_HDA ( &vbe_buf, 0, controller, sizeof ( *controller ) ); + return -EINVAL; + } + DBGC ( &vbe_buf, "VESAFB found VBE version %d.%d with mode list at " + "%04x:%04x\n", controller->vbe_major_version, + controller->vbe_minor_version, + controller->video_mode_ptr.segment, + controller->video_mode_ptr.offset ); + + /* Calculate length of mode list */ + video_mode_ptr = real_to_user ( controller->video_mode_ptr.segment, + controller->video_mode_ptr.offset ); + len = 0; + do { + copy_from_user ( &mode_number, video_mode_ptr, len, + sizeof ( mode_number ) ); + len += sizeof ( mode_number ); + } while ( mode_number != VBE_MODE_END ); + + /* Allocate and fill mode list */ + *mode_numbers = malloc ( len ); + if ( ! *mode_numbers ) + return -ENOMEM; + copy_from_user ( *mode_numbers, video_mode_ptr, 0, len ); + + return 0; +} + +/** + * Get video mode information + * + * @v mode_number Mode number + * @ret rc Return status code + */ +static int vesafb_mode_info ( unsigned int mode_number ) { + struct vbe_mode_info *mode = &vbe_buf.mode; + uint16_t status; + int rc; + + /* Get mode information */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( status ) + : "a" ( VBE_MODE_INFO ), + "c" ( mode_number ), + "D" ( __from_data16 ( mode ) ) + : "memory" ); + if ( ( rc = vesafb_rc ( status ) ) != 0 ) { + DBGC ( &vbe_buf, "VESAFB could not get mode %04x information: " + "[%04x] %s\n", mode_number, status, strerror ( rc ) ); + return rc; + } + DBGC ( &vbe_buf, "VESAFB mode %04x %dx%d %dbpp(%d:%d:%d:%d) model " + "%02x [x%d]%s%s%s%s%s\n", mode_number, mode->x_resolution, + mode->y_resolution, mode->bits_per_pixel, mode->rsvd_mask_size, + mode->red_mask_size, mode->green_mask_size, mode->blue_mask_size, + mode->memory_model, ( mode->number_of_image_pages + 1 ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_SUPPORTED ) ? + "" : " [unsupported]" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_TTY ) ? + " [tty]" : "" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_GRAPHICS ) ? + "" : " [text]" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_LINEAR ) ? + "" : " [nonlinear]" ), + ( ( mode->mode_attributes & VBE_MODE_ATTR_TRIPLE_BUF ) ? + " [buf]" : "" ) ); + + return 0; +} + +/** + * Set video mode + * + * @v mode_number Mode number + * @ret rc Return status code + */ +static int vesafb_set_mode ( unsigned int mode_number ) { + struct vbe_mode_info *mode = &vbe_buf.mode; + uint16_t status; + int rc; + + /* Get mode information */ + if ( ( rc = vesafb_mode_info ( mode_number ) ) != 0 ) + return rc; + + /* Record mode parameters */ + vesafb.start = mode->phys_base_ptr; + vesafb.pixel.width = mode->x_resolution; + vesafb.pixel.height = mode->y_resolution; + vesafb.pixel.len = ( ( mode->bits_per_pixel + 7 ) / 8 ); + vesafb.pixel.stride = mode->bytes_per_scan_line; + DBGC ( &vbe_buf, "VESAFB mode %04x has frame buffer at %08x\n", + mode_number, mode->phys_base_ptr ); + + /* Initialise font colours */ + vesafb.map.red_scale = ( 8 - mode->red_mask_size ); + vesafb.map.green_scale = ( 8 - mode->green_mask_size ); + vesafb.map.blue_scale = ( 8 - mode->blue_mask_size ); + vesafb.map.red_lsb = mode->red_field_position; + vesafb.map.green_lsb = mode->green_field_position; + vesafb.map.blue_lsb = mode->blue_field_position; + + /* Select this mode */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( status ) + : "a" ( VBE_SET_MODE ), + "b" ( mode_number ) ); + if ( ( rc = vesafb_rc ( status ) ) != 0 ) { + DBGC ( &vbe_buf, "VESAFB could not set mode %04x: [%04x] %s\n", + mode_number, status, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Select video mode + * + * @v mode_numbers Mode number list (terminated with VBE_MODE_END) + * @v min_width Minimum required width (in pixels) + * @v min_height Minimum required height (in pixels) + * @v min_bpp Minimum required colour depth (in bits per pixel) + * @ret mode_number Mode number, or negative error + */ +static int vesafb_select_mode ( const uint16_t *mode_numbers, + unsigned int min_width, unsigned int min_height, + unsigned int min_bpp ) { + struct vbe_mode_info *mode = &vbe_buf.mode; + int best_mode_number = -ENOENT; + unsigned int best_score = INT_MAX; + unsigned int score; + uint16_t mode_number; + int rc; + + /* Find the first suitable mode */ + while ( ( mode_number = *(mode_numbers++) ) != VBE_MODE_END ) { + + /* Force linear mode variant */ + mode_number |= VBE_MODE_LINEAR; + + /* Get mode information */ + if ( ( rc = vesafb_mode_info ( mode_number ) ) != 0 ) + continue; + + /* Skip unusable modes */ + if ( ( mode->mode_attributes & ( VBE_MODE_ATTR_SUPPORTED | + VBE_MODE_ATTR_GRAPHICS | + VBE_MODE_ATTR_LINEAR ) ) != + ( VBE_MODE_ATTR_SUPPORTED | VBE_MODE_ATTR_GRAPHICS | + VBE_MODE_ATTR_LINEAR ) ) { + continue; + } + if ( mode->memory_model != VBE_MODE_MODEL_DIRECT_COLOUR ) + continue; + + /* Skip modes not meeting the requirements */ + if ( ( mode->x_resolution < min_width ) || + ( mode->y_resolution < min_height ) || + ( mode->bits_per_pixel < min_bpp ) ) { + continue; + } + + /* Select this mode if it has the best (i.e. lowest) + * score. We choose the scoring system to favour + * modes close to the specified width and height; + * within modes of the same width and height we prefer + * a higher colour depth. + */ + score = ( ( mode->x_resolution * mode->y_resolution ) - + mode->bits_per_pixel ); + if ( score < best_score ) { + best_mode_number = mode_number; + best_score = score; + } + } + + if ( best_mode_number >= 0 ) { + DBGC ( &vbe_buf, "VESAFB selected mode %04x\n", + best_mode_number ); + } else { + DBGC ( &vbe_buf, "VESAFB found no suitable mode\n" ); + } + + return best_mode_number; +} + +/** + * Restore video mode + * + */ +static void vesafb_restore ( void ) { + uint32_t discard_a; + + /* Restore saved VGA mode */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( discard_a ) + : "a" ( VBE_SET_VGA_MODE | vesafb.saved_mode ) ); + DBGC ( &vbe_buf, "VESAFB restored VGA mode %#02x\n", + vesafb.saved_mode ); +} + +/** + * Initialise VESA frame buffer + * + * @v config Console configuration, or NULL to reset + * @ret rc Return status code + */ +static int vesafb_init ( struct console_configuration *config ) { + uint32_t discard_b; + uint16_t *mode_numbers; + unsigned int xgap; + unsigned int ygap; + unsigned int left; + unsigned int right; + unsigned int top; + unsigned int bottom; + int mode_number; + int rc; + + /* Record current VGA mode */ + __asm__ __volatile__ ( REAL_CODE ( "int $0x10" ) + : "=a" ( vesafb.saved_mode ), "=b" ( discard_b ) + : "a" ( VBE_GET_VGA_MODE ) ); + DBGC ( &vbe_buf, "VESAFB saved VGA mode %#02x\n", vesafb.saved_mode ); + + /* Get VESA mode list */ + if ( ( rc = vesafb_mode_list ( &mode_numbers ) ) != 0 ) + goto err_mode_list; + + /* Select mode */ + if ( ( mode_number = vesafb_select_mode ( mode_numbers, config->width, + config->height, + config->depth ) ) < 0 ) { + rc = mode_number; + goto err_select_mode; + } + + /* Set mode */ + if ( ( rc = vesafb_set_mode ( mode_number ) ) != 0 ) + goto err_set_mode; + + /* Calculate margin. If the actual screen size is larger than + * the requested screen size, then update the margins so that + * the margin remains relative to the requested screen size. + * (As an exception, if a zero margin was specified then treat + * this as meaning "expand to edge of actual screen".) + */ + xgap = ( vesafb.pixel.width - config->width ); + ygap = ( vesafb.pixel.height - config->height ); + left = ( xgap / 2 ); + right = ( xgap - left ); + top = ( ygap / 2 ); + bottom = ( ygap - top ); + vesafb.margin.left = ( config->left + ( config->left ? left : 0 ) ); + vesafb.margin.right = ( config->right + ( config->right ? right : 0 ) ); + vesafb.margin.top = ( config->top + ( config->top ? top : 0 ) ); + vesafb.margin.bottom = + ( config->bottom + ( config->bottom ? bottom : 0 ) ); + + /* Get font data */ + vesafb_font(); + + /* Initialise frame buffer console */ + if ( ( rc = fbcon_init ( &vesafb.fbcon, phys_to_user ( vesafb.start ), + &vesafb.pixel, &vesafb.margin, &vesafb.map, + &vesafb.font, config->pixbuf ) ) != 0 ) + goto err_fbcon_init; + + free ( mode_numbers ); + return 0; + + fbcon_fini ( &vesafb.fbcon ); + err_fbcon_init: + err_set_mode: + vesafb_restore(); + err_select_mode: + free ( mode_numbers ); + err_mode_list: + return rc; +} + +/** + * Finalise VESA frame buffer + * + */ +static void vesafb_fini ( void ) { + + /* Finalise frame buffer console */ + fbcon_fini ( &vesafb.fbcon ); + + /* Restore saved VGA mode */ + vesafb_restore(); +} + +/** + * Print a character to current cursor position + * + * @v character Character + */ +static void vesafb_putchar ( int character ) { + + fbcon_putchar ( &vesafb.fbcon, character ); +} + +/** + * Configure console + * + * @v config Console configuration, or NULL to reset + * @ret rc Return status code + */ +static int vesafb_configure ( struct console_configuration *config ) { + int rc; + + /* Reset console, if applicable */ + if ( ! vesafb_console.disabled ) { + vesafb_fini(); + bios_console.disabled &= ~CONSOLE_DISABLED_OUTPUT; + ansicol_reset_magic(); + } + vesafb_console.disabled = CONSOLE_DISABLED; + + /* Do nothing more unless we have a usable configuration */ + if ( ( config == NULL ) || + ( config->width == 0 ) || ( config->height == 0 ) ) { + return 0; + } + + /* Initialise VESA frame buffer */ + if ( ( rc = vesafb_init ( config ) ) != 0 ) + return rc; + + /* Mark console as enabled */ + vesafb_console.disabled = 0; + bios_console.disabled |= CONSOLE_DISABLED_OUTPUT; + + /* Set magic colour to transparent if we have a background picture */ + if ( config->pixbuf ) + ansicol_set_magic_transparent(); + + return 0; +} + +/** VESA frame buffer console driver */ +struct console_driver vesafb_console __console_driver = { + .usage = CONSOLE_VESAFB, + .putchar = vesafb_putchar, + .configure = vesafb_configure, + .disabled = CONSOLE_DISABLED, +}; diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c index b8e73a061..657d47b6c 100644 --- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c +++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/uaccess.h> #include <ipxe/init.h> +#include <ipxe/profile.h> #include <setjmp.h> #include <registers.h> #include <biosint.h> @@ -32,6 +33,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); * PXE API entry point */ +/* Disambiguate the various error causes */ +#define EINFO_EPXENBP \ + __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ + "External PXE NBP error" ) +#define EPXENBP( status ) EPLATFORM ( EINFO_EPXENBP, status ) + /** Vector for chaining INT 1A */ extern struct segoff __text16 ( pxe_int_1a_vector ); #define pxe_int_1a_vector __use_text16 ( pxe_int_1a_vector ) @@ -42,6 +49,26 @@ extern void pxe_int_1a ( void ); /** INT 1A hooked flag */ static int int_1a_hooked = 0; +/** PXENV_UNDI_TRANSMIT API call profiler */ +static struct profiler pxe_api_tx_profiler __profiler = + { .name = "pxeapi.tx" }; + +/** PXENV_UNDI_ISR API call profiler */ +static struct profiler pxe_api_isr_profiler __profiler = + { .name = "pxeapi.isr" }; + +/** PXE unknown API call profiler + * + * This profiler can be used to measure the overhead of a dummy PXE + * API call. + */ +static struct profiler pxe_api_unknown_profiler __profiler = + { .name = "pxeapi.unknown" }; + +/** Miscellaneous PXE API call profiler */ +static struct profiler pxe_api_misc_profiler __profiler = + { .name = "pxeapi.misc" }; + /** * Handle an unknown PXE API call * @@ -75,6 +102,27 @@ static struct pxe_api_call * find_pxe_api_call ( uint16_t opcode ) { } /** + * Determine applicable profiler (for debugging) + * + * @v opcode PXE opcode + * @ret profiler Profiler + */ +static struct profiler * pxe_api_profiler ( unsigned int opcode ) { + + /* Determine applicable profiler */ + switch ( opcode ) { + case PXENV_UNDI_TRANSMIT: + return &pxe_api_tx_profiler; + case PXENV_UNDI_ISR: + return &pxe_api_isr_profiler; + case PXENV_UNKNOWN: + return &pxe_api_unknown_profiler; + default: + return &pxe_api_misc_profiler; + } +} + +/** * Dispatch PXE API call * * @v bx PXE opcode @@ -84,10 +132,14 @@ static struct pxe_api_call * find_pxe_api_call ( uint16_t opcode ) { __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) { uint16_t opcode = ix86->regs.bx; userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di ); + struct profiler *profiler = pxe_api_profiler ( opcode ); struct pxe_api_call *call; union u_PXENV_ANY params; PXENV_EXIT_t ret; + /* Start profiling */ + profile_start ( profiler ); + /* Locate API call */ call = find_pxe_api_call ( opcode ); if ( ! call ) { @@ -107,6 +159,9 @@ __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) { /* Copy modified parameter block back to caller and return */ copy_to_user ( uparams, 0, ¶ms, call->params_len ); ix86->regs.ax = ret; + + /* Stop profiling, if applicable */ + profile_stop ( profiler ); } /** @@ -257,7 +312,7 @@ rmjmp_buf pxe_restart_nbp; int pxe_start_nbp ( void ) { int jmp; int discard_b, discard_c, discard_d, discard_D; - uint16_t rc; + uint16_t status; /* Allow restarting NBP via PXENV_RESTART_TFTP */ jmp = rmsetjmp ( pxe_restart_nbp ); @@ -265,22 +320,26 @@ int pxe_start_nbp ( void ) { DBG ( "Restarting NBP (%x)\n", jmp ); /* Far call to PXE NBP */ - __asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t" + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "movw %%cx, %%es\n\t" "pushw %%es\n\t" "pushw %%di\n\t" "sti\n\t" "lcall $0, $0x7c00\n\t" - "addw $4, %%sp\n\t" ) - : "=a" ( rc ), "=b" ( discard_b ), + "popl %%ebp\n\t" /* discard */ + "popl %%ebp\n\t" /* gcc bug */ ) + : "=a" ( status ), "=b" ( discard_b ), "=c" ( discard_c ), "=d" ( discard_d ), "=D" ( discard_D ) : "a" ( 0 ), "b" ( __from_text16 ( &pxenv ) ), "c" ( rm_cs ), "d" ( virt_to_phys ( &pxenv ) ), "D" ( __from_text16 ( &ppxe ) ) - : "esi", "ebp", "memory" ); + : "esi", "memory" ); + if ( status ) + return -EPXENBP ( status ); - return rc; + return 0; } REQUIRE_OBJECT ( pxe_preboot ); diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c index aab376e82..f4801bad0 100644 --- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c +++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c @@ -72,6 +72,17 @@ static void pxe_tftp_close ( struct pxe_tftp_connection *pxe_tftp, int rc ) { } /** + * Check flow control window + * + * @v pxe_tftp PXE TFTP connection + * @ret len Length of window + */ +static size_t pxe_tftp_xfer_window ( struct pxe_tftp_connection *pxe_tftp ) { + + return pxe_tftp->blksize; +} + +/** * Receive new data * * @v pxe_tftp PXE TFTP connection @@ -128,6 +139,8 @@ static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp, static struct interface_operation pxe_tftp_xfer_ops[] = { INTF_OP ( xfer_deliver, struct pxe_tftp_connection *, pxe_tftp_xfer_deliver ), + INTF_OP ( xfer_window, struct pxe_tftp_connection *, + pxe_tftp_xfer_window ), INTF_OP ( intf_close, struct pxe_tftp_connection *, pxe_tftp_close ), }; @@ -167,19 +180,19 @@ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port, /* Reset PXE TFTP connection structure */ memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) ); intf_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_desc, NULL ); + if ( blksize < TFTP_DEFAULT_BLKSIZE ) + blksize = TFTP_DEFAULT_BLKSIZE; + pxe_tftp.blksize = blksize; pxe_tftp.rc = -EINPROGRESS; /* Construct URI string */ address.s_addr = ipaddress; if ( ! port ) port = htons ( TFTP_PORT ); - if ( blksize < TFTP_DEFAULT_BLKSIZE ) - blksize = TFTP_DEFAULT_BLKSIZE; - snprintf ( uri_string, sizeof ( uri_string ), - "tftp%s://%s:%d%s%s?blksize=%zd", - sizeonly ? "size" : "", - inet_ntoa ( address ), ntohs ( port ), - ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize ); + snprintf ( uri_string, sizeof ( uri_string ), "tftp%s://%s:%d%s%s", + sizeonly ? "size" : "", inet_ntoa ( address ), + ntohs ( port ), ( ( filename[0] == '/' ) ? "" : "/" ), + filename ); DBG ( " %s", uri_string ); /* Open PXE TFTP connection */ diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c index 5d2122694..29e586ed2 100644 --- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c +++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/ip.h> #include <ipxe/arp.h> #include <ipxe/rarp.h> +#include <ipxe/profile.h> #include "pxe.h" /** @@ -53,6 +54,9 @@ static int undi_tx_count = 0; struct net_device *pxe_netdev = NULL; +/** Transmit profiler */ +static struct profiler undi_tx_profiler __profiler = { .name = "undi.tx" }; + /** * Set network device as current PXE network device * @@ -309,6 +313,9 @@ pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) { unsigned int i; int rc; + /* Start profiling */ + profile_start ( &undi_tx_profiler ); + /* Sanity check */ if ( ! pxe_netdev ) { DBGC ( &pxe_netdev, "PXENV_UNDI_TRANSMIT called with no " @@ -323,8 +330,10 @@ pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) { * processing at this point, to work around callers that never * call PXENV_UNDI_OPEN before attempting to use the UNDI API. */ - netdev_rx_freeze ( pxe_netdev ); - netdev_irq ( pxe_netdev, 1 ); + if ( ! netdev_rx_frozen ( pxe_netdev ) ) { + netdev_rx_freeze ( pxe_netdev ); + netdev_irq ( pxe_netdev, 1 ); + } /* Identify network-layer protocol */ switch ( undi_transmit->Protocol ) { @@ -422,6 +431,7 @@ pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) { return PXENV_EXIT_FAILURE; } + profile_stop ( &undi_tx_profiler ); undi_transmit->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; } diff --git a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c index 8b2a2c880..744c7b6dd 100644 --- a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c +++ b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/dhcp.h> +#include <ipxe/profile.h> #include <pxeparent.h> #include <pxe_api.h> #include <pxe_types.h> @@ -31,6 +32,65 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Disambiguate the various error causes */ +#define EINFO_EPXECALL \ + __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ + "External PXE API error" ) +#define EPXECALL( status ) EPLATFORM ( EINFO_EPXECALL, status ) + +/** A parent PXE API call profiler */ +struct pxeparent_profiler { + /** Total time spent performing REAL_CALL() */ + struct profiler total; + /** Time spent transitioning to real mode */ + struct profiler p2r; + /** Time spent in external code */ + struct profiler ext; + /** Time spent transitioning back to protected mode */ + struct profiler r2p; +}; + +/** PXENV_UNDI_TRANSMIT profiler */ +static struct pxeparent_profiler pxeparent_tx_profiler __profiler = { + { .name = "pxeparent.tx" }, + { .name = "pxeparent.tx_p2r" }, + { .name = "pxeparent.tx_ext" }, + { .name = "pxeparent.tx_r2p" }, +}; + +/** PXENV_UNDI_ISR profiler + * + * Note that this profiler will not see calls to + * PXENV_UNDI_ISR_IN_START, which are handled by the UNDI ISR and do + * not go via pxeparent_call(). + */ +static struct pxeparent_profiler pxeparent_isr_profiler __profiler = { + { .name = "pxeparent.isr" }, + { .name = "pxeparent.isr_p2r" }, + { .name = "pxeparent.isr_ext" }, + { .name = "pxeparent.isr_r2p" }, +}; + +/** PXE unknown API call profiler + * + * This profiler can be used to measure the overhead of a dummy PXE + * API call. + */ +static struct pxeparent_profiler pxeparent_unknown_profiler __profiler = { + { .name = "pxeparent.unknown" }, + { .name = "pxeparent.unknown_p2r" }, + { .name = "pxeparent.unknown_ext" }, + { .name = "pxeparent.unknown_r2p" }, +}; + +/** Miscellaneous PXE API call profiler */ +static struct pxeparent_profiler pxeparent_misc_profiler __profiler = { + { .name = "pxeparent.misc" }, + { .name = "pxeparent.misc_p2r" }, + { .name = "pxeparent.misc_ext" }, + { .name = "pxeparent.misc_r2p" }, +}; + /** * Name PXE API call * @@ -98,10 +158,31 @@ pxeparent_function_name ( unsigned int function ) { } /** + * Determine applicable profiler pair (for debugging) + * + * @v function API call number + * @ret profiler Profiler + */ +static struct pxeparent_profiler * pxeparent_profiler ( unsigned int function ){ + + /* Determine applicable profiler */ + switch ( function ) { + case PXENV_UNDI_TRANSMIT: + return &pxeparent_tx_profiler; + case PXENV_UNDI_ISR: + return &pxeparent_isr_profiler; + case PXENV_UNKNOWN: + return &pxeparent_unknown_profiler; + default: + return &pxeparent_misc_profiler; + } +} + +/** * PXE parent parameter block * - * Used as the paramter block for all parent PXE API calls. Resides in base - * memory. + * Used as the parameter 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 ) @@ -125,8 +206,11 @@ SEGOFF16_t __bss16 ( pxeparent_entry_point ); */ int pxeparent_call ( SEGOFF16_t entry, unsigned int function, void *params, size_t params_len ) { + struct pxeparent_profiler *profiler = pxeparent_profiler ( function ); PXENV_EXIT_t exit; - int discard_b, discard_D; + unsigned long started; + unsigned long stopped; + int discard_D; int rc; /* Copy parameter block and entry point */ @@ -137,30 +221,37 @@ int pxeparent_call ( SEGOFF16_t entry, unsigned int function, /* 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" + profile_start ( &profiler->total ); + __asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */ + "rdtsc\n\t" + "pushl %%eax\n\t" + "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 ) + "movw %%ax, %%bx\n\t" + "rdtsc\n\t" + "addw $6, %%sp\n\t" + "popl %%edx\n\t" + "popl %%ebp\n\t" /* gcc bug */ ) + : "=a" ( stopped ), "=d" ( started ), + "=b" ( exit ), "=D" ( discard_D ) : "b" ( function ), "D" ( __from_data16 ( &pxeparent_params ) ) - : "ecx", "edx", "esi", "ebp" ); + : "ecx", "esi" ); + profile_stop ( &profiler->total ); + profile_start_at ( &profiler->p2r, profiler->total.started ); + profile_stop_at ( &profiler->p2r, started ); + profile_start_at ( &profiler->ext, started ); + profile_stop_at ( &profiler->ext, stopped ); + profile_start_at ( &profiler->r2p, stopped ); + profile_stop_at ( &profiler->r2p, profiler->total.stopped ); /* 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; - } + rc = ( ( exit == PXENV_EXIT_SUCCESS ) ? + 0 : -EPXECALL ( pxeparent_params.Status ) ); /* If anything goes wrong, print as much debug information as * it's possible to give. diff --git a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c deleted file mode 100644 index f37286335..000000000 --- a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <string.h> -#include <ipxe/dhcp.h> -#include <ipxe/netdevice.h> -#include <undipreload.h> -#include <pxeparent.h> -#include <realmode.h> -#include <pxe_api.h> - -/** - * Present cached DHCP packet if it exists - */ -void 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/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c b/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c index 8fffd0692..75dcc238f 100644 --- a/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c +++ b/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c @@ -189,20 +189,3 @@ int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) return eax; } - -/** - * IRQ handler - */ -void __asmcall com32_irq ( uint32_t vector ) { - uint32_t *ivt_entry = phys_to_virt( vector * 4 ); - - __asm__ __volatile__ ( - REAL_CODE ( "pushfw\n\t" - "pushw %%cs\n\t" - "pushw $com32_irq_return\n\t" - "pushl %0\n\t" - "lret\n" - "com32_irq_return:\n\t" ) - : /* no outputs */ - : "r" ( *ivt_entry ) ); -} diff --git a/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S b/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S index 69cea02e8..c9d1452b4 100644 --- a/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S +++ b/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S @@ -23,26 +23,6 @@ FILE_LICENCE ( GPL2_OR_LATER ) .arch i386 .code32 - /* - * This code is entered after running the following sequence out of - * the interrupt jump buffer: - * - * pushal - * movb $vector, %al - * jmp com32_irq_wrapper - */ - - .globl com32_irq_wrapper -com32_irq_wrapper: - - movzbl %al,%eax - pushl %eax - movl $com32_irq, %eax - call com32_wrapper - popl %eax - popal - iret - .globl com32_farcall_wrapper com32_farcall_wrapper: @@ -69,9 +49,6 @@ com32_wrapper: /* Switch to internal virtual address space */ call _phys_to_virt - /* Switch to internal IDT (if we have one for debugging) */ - lidt com32_internal_idtr - mov %eax, (com32_helper_function) /* Save external COM32 stack pointer */ @@ -99,9 +76,6 @@ com32_wrapper: movl %esp, (com32_internal_esp) movl (com32_external_esp), %esp - /* Switch to com32 IDT */ - lidt com32_external_idtr - /* Switch to external flat physical address space */ call _virt_to_phys diff --git a/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c b/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c index fbf605f33..1854501de 100644 --- a/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c +++ b/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c @@ -188,7 +188,8 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file ); /* Fetch initrd */ - if ( ( rc = imgdownload_string ( initrd_file, &initrd ) ) != 0){ + if ( ( rc = imgdownload_string ( initrd_file, 0, + &initrd ) ) != 0 ) { DBG ( "COMBOOT: could not fetch initrd: %s\n", strerror ( rc ) ); return rc; @@ -202,7 +203,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file ); /* Fetch kernel */ - if ( ( rc = imgdownload_string ( kernel_file, &kernel ) ) != 0 ) { + if ( ( rc = imgdownload_string ( kernel_file, 0, &kernel ) ) != 0 ) { DBG ( "COMBOOT: could not fetch kernel: %s\n", strerror ( rc ) ); return rc; diff --git a/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c b/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c index 5e08d9471..a0530c8d1 100644 --- a/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c +++ b/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c @@ -51,14 +51,14 @@ static int guestinfo_channel; */ static int guestinfo_fetch_type ( struct settings *settings, struct setting *setting, - struct setting_type *type, + const struct setting_type *type, void *data, size_t len, int *found ) { const char *parent_name = settings->parent->name; char command[ 24 /* "info-get guestinfo.ipxe." */ + strlen ( parent_name ) + 1 /* "." */ + strlen ( setting->name ) + 1 /* "." */ + ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ]; - struct setting *named_setting; + struct setting *predefined; char *info; int info_len; int check_len; @@ -82,9 +82,8 @@ static int guestinfo_fetch_type ( struct settings *settings, /* Determine default type if necessary */ if ( ! type ) { - named_setting = find_setting ( setting->name ); - type = ( named_setting ? - named_setting->type : &setting_type_string ); + predefined = find_setting ( setting->name ); + type = ( predefined ? predefined->type : &setting_type_string ); } assert ( type != NULL ); @@ -115,7 +114,7 @@ static int guestinfo_fetch_type ( struct settings *settings, settings, &command[9] /* Skip "info-get " */, info ); /* Parse GuestInfo value according to type */ - ret = type->parse ( info, data, len ); + ret = setting_parse ( type, info, data, len ); if ( ret < 0 ) { DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: " "%s\n", settings, info, type->name, strerror ( ret ) ); @@ -224,7 +223,7 @@ static int guestinfo_net_probe ( struct net_device *netdev ) { rc = -ENOMEM; goto err_alloc; } - settings_init ( settings, &guestinfo_settings_operations, NULL, 0 ); + settings_init ( settings, &guestinfo_settings_operations, NULL, NULL ); /* Register settings */ if ( ( rc = register_settings ( settings, netdev_settings ( netdev ), @@ -245,15 +244,6 @@ static int guestinfo_net_probe ( struct net_device *netdev ) { } /** - * Handle network device or link state change - * - * @v netdev Network device - */ -static void guestinfo_net_notify ( struct net_device *netdev __unused ) { - /* Nothing to do */ -} - -/** * Remove per-netdevice GuestInfo settings * * @v netdev Network device @@ -277,6 +267,5 @@ static void guestinfo_net_remove ( struct net_device *netdev ) { struct net_driver guestinfo_net_driver __net_driver = { .name = "GuestInfo", .probe = guestinfo_net_probe, - .notify = guestinfo_net_notify, .remove = guestinfo_net_remove, }; diff --git a/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c index 485105200..c6b9fff12 100644 --- a/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c +++ b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c @@ -102,7 +102,7 @@ static void vmconsole_putchar ( int character ) { /** VMware logfile console driver */ struct console_driver vmconsole __console_driver = { .putchar = vmconsole_putchar, - .disabled = 1, + .disabled = CONSOLE_DISABLED, .usage = CONSOLE_VMWARE, }; diff --git a/roms/ipxe/src/arch/i386/prefix/exeprefix.S b/roms/ipxe/src/arch/i386/prefix/exeprefix.S index acd3f83cd..cb61287d3 100644 --- a/roms/ipxe/src/arch/i386/prefix/exeprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/exeprefix.S @@ -114,7 +114,7 @@ _exe_start: call alloc_basemem xorl %esi, %esi movl $EXE_DECOMPRESS_ADDRESS, %edi - xorl %ebp, %ebp + orl $0xffffffff, %ebp /* Allow arbitrary relocation */ call install_prealloc /* Set up real-mode stack */ diff --git a/roms/ipxe/src/arch/i386/prefix/libprefix.S b/roms/ipxe/src/arch/i386/prefix/libprefix.S index 2f8fc4e1a..3aee415f5 100644 --- a/roms/ipxe/src/arch/i386/prefix/libprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/libprefix.S @@ -522,8 +522,11 @@ alloc_basemem: subw $_data16_memsz_pgh, %ax pushw %ax - /* Calculate .text16 segment address */ + /* Calculate .text16 segment address. Round down to ensure + * low bits are zero, to speed up mode transitions under KVM. + */ subw $_text16_memsz_pgh, %ax + andb $~0x03, %al pushw %ax /* Update FBMS */ @@ -545,8 +548,7 @@ alloc_basemem: * Free space allocated with alloc_basemem. * * Parameters: - * %ax : .text16 segment address - * %bx : .data16 segment address + * none (.text16 segment address is implicit in %cs) * Returns: * %ax : 0 if successfully freed * Corrupts: @@ -559,14 +561,14 @@ alloc_basemem: free_basemem: /* Preserve registers */ pushw %fs + pushw %ax /* Check FBMS counter */ - pushw %ax + movw %cs, %ax shrw $6, %ax pushw $0x40 popw %fs cmpw %ax, %fs:0x13 - popw %ax jne 1f /* Check hooked interrupt count */ @@ -574,6 +576,7 @@ free_basemem: jne 1f /* OK to free memory */ + movw %cs, %ax addw $_text16_memsz_pgh, %ax addw $_data16_memsz_pgh, %ax shrw $6, %ax @@ -581,6 +584,7 @@ free_basemem: xorw %ax, %ax 1: /* Restore registers and return */ + popw %ax popw %fs ret .size free_basemem, . - free_basemem @@ -621,7 +625,7 @@ install: /* Image destination = default */ xorl %edi, %edi /* Allow arbitrary relocation */ - xorl %ebp, %ebp + orl $0xffffffff, %ebp /* Install text and data segments */ call install_prealloc /* Restore registers and return */ @@ -641,7 +645,9 @@ install: * %bx : .data16 segment address * %esi : Image source physical address (or zero for %cs:0000) * %edi : Decompression temporary area physical address (or zero for default) - * %ebp : Maximum end address for relocation (or zero for no maximum) + * %ebp : Maximum end address for relocation + * - 0xffffffff for no maximum + * - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801 * Corrupts: * none **************************************************************************** @@ -795,6 +801,13 @@ payload_death_message: movw %ax, (init_librm_vector+2) lcall *init_librm_vector + /* Inhibit INT 15,e820 and INT 15,e801 if applicable */ + testl %ebp, %ebp + jnz 1f + incb memmap_post + decl %ebp +1: + /* Call relocate() to determine target address for relocation. * relocate() will return with %esi, %edi and %ecx set up * ready for the copy to the new location. @@ -872,8 +885,7 @@ close_payload: * Uninstall all text and data segments. * * Parameters: - * %ax : .text16 segment address - * %bx : .data16 segment address + * none (.text16 segment address is implicit in %cs) * Returns: * none * Corrupts: diff --git a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S index 768903326..624f9b0ad 100644 --- a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S @@ -127,7 +127,7 @@ realmode_swtch: start_sys: .word 0 kernel_version: - .word 0 + .word version_string - 0x200 type_of_loader: .byte 0 loadflags: @@ -166,6 +166,9 @@ hardware_subarch: hardware_subarch_data: .byte 0, 0, 0, 0, 0, 0, 0, 0 +version_string: + .asciz VERSION + /* We don't need to do too much setup. @@ -231,9 +234,12 @@ run_ipxe: movzwl %sp, %edx no_cmd_line: - /* Retrieve initrd pointer and size */ - movl %ds:ramdisk_image, %ebp - movl %ds:ramdisk_size, %ecx + /* Calculate maximum relocation address */ + movl ramdisk_image, %ebp + testl %ebp, %ebp + jnz 1f + orl $0xffffffff, %ebp /* Allow arbitrary relocation if no initrd */ +1: /* Install iPXE */ call alloc_basemem @@ -251,6 +257,10 @@ no_cmd_line: lret .section ".text16", "awx", @progbits 1: + /* Retrieve initrd pointer and size */ + movl ramdisk_image, %ebp + movl ramdisk_size, %ecx + /* Set up %ds for access to .data16 */ movw %bx, %ds diff --git a/roms/ipxe/src/arch/i386/prefix/mromprefix.S b/roms/ipxe/src/arch/i386/prefix/mromprefix.S index 058663c40..0f0847e5f 100644 --- a/roms/ipxe/src/arch/i386/prefix/mromprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/mromprefix.S @@ -98,6 +98,7 @@ find_mem_bar: cmpw $PCI_BAR_5, %di jle 1f stc + movl $0xbabababa, %esi /* Report "No suitable BAR" */ jmp 99f 1: movw $4, %bp @@ -157,15 +158,17 @@ find_mem_bar: /* Locate our ROM image */ 1: addr32 es cmpw $0xaa55, (%eax) - stc - jne 99f - addr32 es cmpl $_build_id, build_id(%eax) je 2f + stc + movl %eax, %esi /* Report failure address */ + jmp 99f +2: addr32 es cmpl $_build_id, build_id(%eax) + je 3f addr32 es movzbl 2(%eax), %ecx shll $9, %ecx addl %ecx, %eax jmp 1b -2: +3: /* Copy payload to buffer, or set buffer address to BAR address */ testl %esi, %esi diff --git a/roms/ipxe/src/arch/i386/prefix/nbiprefix.S b/roms/ipxe/src/arch/i386/prefix/nbiprefix.S index 20d224d69..06e7df5b7 100644 --- a/roms/ipxe/src/arch/i386/prefix/nbiprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/nbiprefix.S @@ -54,6 +54,10 @@ _nbi_start: /* Install iPXE */ call install + /* Set up real-mode stack */ + movw %bx, %ss + movw $_estack16, %sp + /* Jump to .text16 segment */ pushw %ax pushw $1f diff --git a/roms/ipxe/src/arch/i386/prefix/pxeprefix.S b/roms/ipxe/src/arch/i386/prefix/pxeprefix.S index 05db9894c..6e29c7949 100644 --- a/roms/ipxe/src/arch/i386/prefix/pxeprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/pxeprefix.S @@ -5,6 +5,8 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PXENV_UNDI_GET_IFACE_INFO 0x0013 #define PXENV_STOP_UNDI 0x0015 #define PXENV_UNLOAD_STACK 0x0070 +#define PXENV_GET_CACHED_INFO 0x0071 +#define PXENV_PACKET_TYPE_DHCP_ACK 0x0002 #define PXENV_FILE_CMDLINE 0x00e8 #define PXE_HACK_EB54 0x0001 @@ -20,7 +22,18 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) ) #define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) ) +/* Prefix memory layout: + * + * iPXE binary image + * Temporary stack + * Temporary copy of DHCPACK packet + * Temporary copy of command line + */ #define PREFIX_STACK_SIZE 2048 +#define PREFIX_TEMP_DHCPACK PREFIX_STACK_SIZE +#define PREFIX_TEMP_DHCPACK_SIZE ( 1260 /* sizeof ( BOOTPLAYER_t ) */ ) +#define PREFIX_TEMP_CMDLINE ( PREFIX_TEMP_DHCPACK + PREFIX_TEMP_DHCPACK_SIZE ) +#define PREFIX_TEMP_CMDLINE_SIZE 4096 /***************************************************************************** * Entry point: set operating context, print welcome message @@ -382,6 +395,32 @@ get_iface_type: 99: movb $0x0a, %al call print_character +/***************************************************************************** + * Get cached DHCP_ACK packet + ***************************************************************************** + */ +get_dhcpack: + /* Issue PXENV_GET_CACHED_INFO */ + xorl %esi, %esi + movw %ss, %si + movw %si, ( pxe_parameter_structure + 0x08 ) + movw $PREFIX_TEMP_DHCPACK, ( pxe_parameter_structure + 0x06 ) + movw $PREFIX_TEMP_DHCPACK_SIZE, ( pxe_parameter_structure +0x04 ) + movw $PXENV_PACKET_TYPE_DHCP_ACK, ( pxe_parameter_structure + 0x02 ) + movw $PXENV_GET_CACHED_INFO, %bx + call pxe_call + jnc 1f + call print_pxe_error + jmp 99f +1: /* Store physical address of packet */ + shll $4, %esi + addl $PREFIX_TEMP_DHCPACK, %esi + movl %esi, pxe_cached_dhcpack +99: + .section ".prefix.data", "aw", @progbits +pxe_cached_dhcpack: + .long 0 + .previous /***************************************************************************** * Check for a command line @@ -392,8 +431,8 @@ get_cmdline: xorl %esi, %esi movw %ss, %si movw %si, ( pxe_parameter_structure + 0x06 ) - movw $PREFIX_STACK_SIZE, ( pxe_parameter_structure + 0x04 ) - movw $0xffff, ( pxe_parameter_structure + 0x02 ) + movw $PREFIX_TEMP_CMDLINE, ( pxe_parameter_structure + 0x04 ) + movw $PREFIX_TEMP_CMDLINE_SIZE, ( pxe_parameter_structure + 0x02 ) movw $PXENV_FILE_CMDLINE, %bx call pxe_call jc 99f /* Suppress errors; this is an iPXE extension API call */ @@ -403,7 +442,7 @@ get_cmdline: jz 99f /* Record command line */ shll $4, %esi - addl $PREFIX_STACK_SIZE, %esi + addl $PREFIX_TEMP_CMDLINE, %esi movl %esi, pxe_cmdline 99: .section ".prefix.data", "aw", @progbits @@ -761,6 +800,9 @@ run_ipxe: /* Retrieve PXE command line, if any */ movl pxe_cmdline, %esi + /* Retrieve cached DHCPACK, if any */ + movl pxe_cached_dhcpack, %ecx + /* Jump to .text16 segment with %ds pointing to .data16 */ movw %bx, %ds pushw %ax @@ -774,6 +816,9 @@ run_ipxe: /* Store command-line pointer */ movl %esi, cmdline_phys + /* Store cached DHCPACK pointer */ + movl %ecx, cached_dhcpack_phys + /* Run main program */ pushl $main pushw %cs diff --git a/roms/ipxe/src/arch/i386/prefix/romprefix.S b/roms/ipxe/src/arch/i386/prefix/romprefix.S index 35d037eff..ae18f05d0 100644 --- a/roms/ipxe/src/arch/i386/prefix/romprefix.S +++ b/roms/ipxe/src/arch/i386/prefix/romprefix.S @@ -23,13 +23,10 @@ FILE_LICENCE ( GPL2_OR_LATER ) ( PMM_HANDLE_BASE | 0x00001000 ) #define PMM_HANDLE_BASE_DECOMPRESS_TO \ ( PMM_HANDLE_BASE | 0x00002000 ) +#define PCI_FUNC_MASK 0x07 -/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in - * config.h, but converted to a number of (18Hz) timer ticks, and - * doubled to allow for BIOSes that switch video modes immediately - * beforehand, so rendering the message almost invisible to the user. - */ -#define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 ) +/* ROM banner timeout, converted to a number of (18Hz) timer ticks. */ +#define ROM_BANNER_TIMEOUT_TICKS ( ( 18 * ROM_BANNER_TIMEOUT ) / 10 ) /* Allow payload to be excluded from ROM size */ @@ -422,6 +419,9 @@ no_pmm: xorw %di, %di cs rep movsb + /* Skip prompt if this is not the first PCI function */ + testb $PCI_FUNC_MASK, init_pci_busdevfn + jnz no_shell /* Prompt for POST-time shell */ movw $init_message_prompt, %si xorw %di, %di @@ -440,15 +440,19 @@ no_pmm: movw $init_message_done, %si call print_message popf - jnz 2f + jnz no_shell /* Ctrl-B was pressed: invoke iPXE. The keypress will be * picked up by the initial shell prompt, and we will drop * into a shell. */ - movl $0xa0000, %ebp /* Inhibit relocation during POST */ + xorl %ebp, %ebp /* Inhibit use of INT 15,e820 and INT 15,e801 */ pushw %cs call exec -2: +no_shell: + movb $( '\n' ), %al + xorw %di, %di + call print_character + /* Restore registers */ popw %gs popw %fs @@ -595,7 +599,7 @@ init_message_done: * */ init_pci_busdevfn: - .word 0xffff + .word 0 .size init_pci_busdevfn, . - init_pci_busdevfn /* Image source area @@ -630,7 +634,7 @@ decompress_to: * Called by the PnP BIOS when it wants to boot us. */ bev_entry: - xorl %ebp, %ebp /* Allow relocation */ + orl $0xffffffff, %ebp /* Allow arbitrary relocation */ pushw %cs call exec lret @@ -665,7 +669,7 @@ int19_entry: /* Leave keypress in buffer and start iPXE. The keypress will * cause the usual initial Ctrl-B prompt to be skipped. */ - xorl %ebp, %ebp /* Allow relocation */ + orl $0xffffffff, %ebp /* Allow arbitrary relocation */ pushw %cs call exec 1: /* Try to call original INT 19 vector */ @@ -734,12 +738,25 @@ exec: /* Set %ds = %cs */ pushw $1f lret .section ".text16", "awx", @progbits -1: /* Call main() */ +1: + /* Retrieve PCI bus:dev.fn */ + movw init_pci_busdevfn, %ax + + /* Set up %ds for access to .data16 */ + movw %bx, %ds + + /* Store PCI bus:dev.fn */ + movw %ax, autoboot_busdevfn + + /* Call main() */ pushl $main pushw %cs call prot_call popl %eax /* discard */ + /* Set up flat real mode for return to BIOS */ + call flatten_real_mode + /* Uninstall iPXE */ call uninstall @@ -783,7 +800,7 @@ wait_for_key: int $0x16 jmp 1b 2: /* Wait for a key press */ - movw $ROM_BANNER_TIMEOUT, %cx + movw $ROM_BANNER_TIMEOUT_TICKS, %cx 3: decw %cx js 99f /* Exit with ZF clear */ /* Wait for timer tick to be updated */ diff --git a/roms/ipxe/src/arch/i386/prefix/undiloader.S b/roms/ipxe/src/arch/i386/prefix/undiloader.S index bb3d469be..74bb59041 100644 --- a/roms/ipxe/src/arch/i386/prefix/undiloader.S +++ b/roms/ipxe/src/arch/i386/prefix/undiloader.S @@ -23,15 +23,15 @@ undiloader: popw %ds /* UNDI loader parameter structure address into %es:%di */ movw %sp, %bx - movw %ss:18(%bx), %di - movw %ss:20(%bx), %es + movw %ss:22(%bx), %di + movw %ss:24(%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 - xorl %ebp, %ebp /* Allow relocation */ + orl $0xffffffff, %ebp /* Allow arbitrary relocation */ call install_prealloc popw %di /* Call UNDI loader C code */ diff --git a/roms/ipxe/src/arch/i386/scripts/i386-kir.lds b/roms/ipxe/src/arch/i386/scripts/i386-kir.lds index 338d6ee87..66bf804e6 100644 --- a/roms/ipxe/src/arch/i386/scripts/i386-kir.lds +++ b/roms/ipxe/src/arch/i386/scripts/i386-kir.lds @@ -98,6 +98,8 @@ SECTIONS { *(.data) *(.data.*) KEEP(*(SORT(.tbl.*))) /* Various tables. See include/tables.h */ + KEEP(*(.provided)) + KEEP(*(.provided.*)) _edata16_progbits = .; } .bss16 : AT ( _data16_load_offset + __bss16 ) { diff --git a/roms/ipxe/src/arch/i386/scripts/i386.lds b/roms/ipxe/src/arch/i386/scripts/i386.lds index fb763656c..98f95cb23 100644 --- a/roms/ipxe/src/arch/i386/scripts/i386.lds +++ b/roms/ipxe/src/arch/i386/scripts/i386.lds @@ -109,6 +109,8 @@ SECTIONS { *(.data) *(.data.*) KEEP(*(SORT(.tbl.*))) /* Various tables. See include/tables.h */ + KEEP(*(.provided)) + KEEP(*(.provided.*)) _mtextdata = .; } .bss.textdata (NOLOAD) : AT ( _end_lma ) { *(.bss) diff --git a/roms/ipxe/src/arch/i386/scripts/linux.lds b/roms/ipxe/src/arch/i386/scripts/linux.lds index 64c9b97fd..9f2eeaf3c 100644 --- a/roms/ipxe/src/arch/i386/scripts/linux.lds +++ b/roms/ipxe/src/arch/i386/scripts/linux.lds @@ -53,6 +53,8 @@ SECTIONS { *(.data) *(.data.*) KEEP(*(SORT(.tbl.*))) + KEEP(*(.provided)) + KEEP(*(.provided.*)) _edata = .; } diff --git a/roms/ipxe/src/arch/i386/transitions/librm.S b/roms/ipxe/src/arch/i386/transitions/librm.S index 02d25b22c..2e447b030 100644 --- a/roms/ipxe/src/arch/i386/transitions/librm.S +++ b/roms/ipxe/src/arch/i386/transitions/librm.S @@ -66,15 +66,15 @@ physical_ds: /* 32 bit protected mode data segment, physical addresses */ .byte 0, 0x93, 0xcf, 0 .org gdt + REAL_CS, 0 -real_cs: /* 16 bit flat real mode code segment */ +real_cs: /* 16 bit real mode code segment */ .word 0xffff, 0 - .byte 0, 0x9b, 0x8f, 0 + .byte 0, 0x9b, 0x00, 0 .org gdt + REAL_DS -real_ds: /* 16 bit flat real mode data segment */ - .word 0xffff, 0 - .byte 0, 0x93, 0x8f, 0 - +real_ds: /* 16 bit real mode data segment */ + .word 0xffff, ( REAL_DS << 4 ) + .byte 0, 0x93, 0x00, 0 + gdt_end: .equ gdt_length, gdt_end - gdt @@ -111,27 +111,30 @@ init_librm: /* Store rm_cs and text16, set up real_cs segment */ xorl %eax, %eax movw %cs, %ax - movw %ax, rm_cs + movw %ax, %cs:rm_cs shll $4, %eax movw $real_cs, %bx call set_seg_base addr32 leal (%eax, %edi), %ebx movl %ebx, rm_text16 - /* Store rm_ds and data16, set up real_ds segment */ + /* Store rm_ds and data16 */ xorl %eax, %eax movw %ds, %ax movw %ax, %cs:rm_ds shll $4, %eax - movw $real_ds, %bx - call set_seg_base addr32 leal (%eax, %edi), %ebx movl %ebx, rm_data16 - /* Set GDT and IDT base */ + /* Set GDT base */ movl %eax, gdt_base addl $gdt, gdt_base - call idt_init + + /* Initialise IDT */ + pushl $init_idt + pushw %cs + call prot_call + popl %eax /* discard */ /* Restore registers */ negl %edi @@ -141,14 +144,12 @@ init_librm: .section ".text16", "ax", @progbits .code16 - .weak idt_init set_seg_base: 1: movw %ax, 2(%bx) rorl $16, %eax movb %al, 4(%bx) movb %ah, 7(%bx) roll $16, %eax -idt_init: /* Reuse the return opcode here */ ret /**************************************************************************** @@ -199,17 +200,29 @@ real_to_prot: addr32 leal (%eax,%edx), %esi subl rm_virt_offset, %esi + /* Load protected-mode global descriptor table */ + data32 lgdt gdtr + + /* Zero segment registers. This wastes around 12 cycles on + * real hardware, but saves a substantial number of emulated + * instructions under KVM. + */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + /* Switch to protected mode */ cli - data32 lgdt gdtr - data32 lidt idtr movl %cr0, %eax orb $CR0_PE, %al movl %eax, %cr0 - data32 ljmp $VIRTUAL_CS, $1f + data32 ljmp $VIRTUAL_CS, $r2p_pmode .section ".text", "ax", @progbits .code32 -1: +r2p_pmode: /* Set up protected-mode data segments and stack pointer */ movw $VIRTUAL_DS, %ax movw %ax, %ds @@ -219,6 +232,9 @@ real_to_prot: movw %ax, %ss movl pm_esp, %esp + /* Load protected-mode interrupt descriptor table */ + lidt idtr + /* Record real-mode %ss:sp (after removal of data) */ movw %bp, rm_ss addl %ecx, %edx @@ -237,14 +253,6 @@ real_to_prot: /* Return to virtual address */ ret - /* Default IDTR with no interrupts */ - .section ".data16", "aw", @progbits - .weak idtr -idtr: -rm_idtr: - .word 0xffff /* limit */ - .long 0 /* base */ - /**************************************************************************** * prot_to_real (protected-mode near call, 32-bit real-mode return address) * @@ -261,12 +269,22 @@ rm_idtr: * * Parameters: * %ecx : number of bytes to move from PM stack to RM stack + * %esi : real-mode global and interrupt descriptor table registers * **************************************************************************** */ .section ".text", "ax", @progbits .code32 prot_to_real: + /* Copy real-mode global descriptor table register to RM code segment */ + movl text16, %edi + leal rm_gdtr(%edi), %edi + movsw + movsl + + /* Load real-mode interrupt descriptor table register */ + lidt (%esi) + /* Add return address to data to be moved to RM stack */ addl $4, %ecx @@ -293,17 +311,19 @@ prot_to_real: movw %ax, %fs movw %ax, %gs movw %ax, %ss - ljmp $REAL_CS, $1f + ljmp $REAL_CS, $p2r_rmode .section ".text16", "ax", @progbits .code16 -1: +p2r_rmode: + /* Load real-mode GDT */ + data32 lgdt %cs:rm_gdtr /* Switch to real mode */ movl %cr0, %eax andb $0!CR0_PE, %al movl %eax, %cr0 - ljmp *p2r_jump_vector -p2r_jump_target: - +p2r_ljmp_rm_cs: + ljmp $0, $1f +1: /* Set up real-mode data segments and stack pointer */ movw %cs:rm_ds, %ax movw %ax, %ds @@ -313,28 +333,31 @@ p2r_jump_target: movw %bp, %ss movl %edx, %esp - /* Reset IDTR to the real-mode defaults */ - data32 lidt rm_idtr - /* Return to real-mode address */ data32 ret /* Real-mode code and data segments. Assigned by the call to * init_librm. rm_cs doubles as the segment part of the jump - * vector used by prot_to_real. rm_ds is located in .text16 - * rather than .data16 because code needs to be able to locate - * the data segment. + * instruction used by prot_to_real. Both are located in + * .text16 rather than .data16: rm_cs since it forms part of + * the jump instruction within the code segment, and rm_ds + * since real-mode code needs to be able to locate the data + * segment with no other reference available. */ - .section ".data16", "aw", @progbits -p2r_jump_vector: - .word p2r_jump_target .globl rm_cs -rm_cs: .word 0 - .globl rm_ds + .equ rm_cs, ( p2r_ljmp_rm_cs + 3 ) + .section ".text16.data", "aw", @progbits + .globl rm_ds rm_ds: .word 0 + /* Real-mode global and interrupt descriptor table registers */ + .section ".text16.data", "aw", @progbits +rm_gdtr: + .word 0 /* Limit */ + .long 0 /* Base */ + /**************************************************************************** * prot_call (real-mode far call, 16-bit real-mode far return address) * @@ -370,8 +393,8 @@ rm_ds: .word 0 */ #define PC_OFFSET_GDT ( 0 ) -#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 8 /* pad to 8 to keep alignment */ ) -#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 8 /* pad to 8 to keep alignment */ ) +#define PC_OFFSET_IDT ( PC_OFFSET_GDT + 6 ) +#define PC_OFFSET_IX86 ( PC_OFFSET_IDT + 6 ) #define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS ) #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 ) #define PC_OFFSET_END ( PC_OFFSET_FUNCTION + 4 ) @@ -389,21 +412,21 @@ prot_call: pushw %ds pushw %ss pushw %cs - subw $16, %sp + subw $PC_OFFSET_IX86, %sp movw %sp, %bp - sidt 8(%bp) - sgdt (%bp) + sidt PC_OFFSET_IDT(%bp) + sgdt PC_OFFSET_GDT(%bp) /* For sanity's sake, clear the direction flag as soon as possible */ cld /* Switch to protected mode and move register dump to PM stack */ movl $PC_OFFSET_END, %ecx - pushl $1f + pushl $pc_pmode jmp real_to_prot .section ".text", "ax", @progbits .code32 -1: +pc_pmode: /* Call function */ leal PC_OFFSET_IX86(%esp), %eax pushl %eax @@ -412,16 +435,14 @@ prot_call: /* Switch to real mode and move register dump back to RM stack */ movl $PC_OFFSET_END, %ecx - pushl $1f + movl %esp, %esi + pushl $pc_rmode jmp prot_to_real .section ".text16", "ax", @progbits .code16 -1: - /* Reload GDT and IDT, restore registers and flags and return */ - movw %sp, %bp - data32 lgdt (%bp) - data32 lidt 8(%bp) - addw $20, %sp /* also skip %cs and %ss */ +pc_rmode: + /* Restore registers and flags and return */ + addw $( PC_OFFSET_IX86 + 4 /* also skip %cs and %ss */ ), %sp popw %ds popw %es popw %fs @@ -474,11 +495,12 @@ real_call: /* Switch to real mode and move register dump to RM stack */ movl $( RC_OFFSET_RETADDR + 4 /* function pointer copy */ ), %ecx - pushl $1f + pushl $rc_rmode + movl $rm_default_gdtr_idtr, %esi jmp prot_to_real .section ".text16", "ax", @progbits .code16 -1: +rc_rmode: /* Call real-mode function */ popl rc_function popal @@ -490,11 +512,11 @@ real_call: /* Switch to protected mode and move register dump back to PM stack */ movl $RC_OFFSET_RETADDR, %ecx - pushl $1f + pushl $rc_pmode jmp real_to_prot .section ".text", "ax", @progbits .code32 -1: +rc_pmode: /* Restore registers and return */ popal ret @@ -506,6 +528,84 @@ real_call: .section ".data16", "aw", @progbits rc_function: .word 0, 0 + /* Default real-mode global and interrupt descriptor table registers */ + .section ".data", "aw", @progbits +rm_default_gdtr_idtr: + .word 0 /* Global descriptor table limit */ + .long 0 /* Global descriptor table base */ + .word 0x03ff /* Interrupt descriptor table limit */ + .long 0 /* Interrupt descriptor table base */ + +/**************************************************************************** + * flatten_real_mode (real-mode near call) + * + * Switch to flat real mode + * + **************************************************************************** + */ + .section ".text16", "ax", @progbits + .code16 + .globl flatten_real_mode +flatten_real_mode: + /* Modify GDT to use flat real mode */ + movb $0x8f, real_cs + 6 + movb $0x8f, real_ds + 6 + /* Call dummy protected-mode function */ + pushl $flatten_dummy + pushw %cs + call prot_call + addw $4, %sp + /* Restore GDT */ + movb $0x00, real_cs + 6 + movb $0x00, real_ds + 6 + /* Return */ + ret + + .section ".text", "ax", @progbits + .code32 +flatten_dummy: + ret + +/**************************************************************************** + * Interrupt wrapper + * + * Used by the protected-mode interrupt vectors to call the + * interrupt() function. + * + * May be entered with either physical or virtual stack segment. + **************************************************************************** + */ + .globl interrupt_wrapper +interrupt_wrapper: + /* Preserve segment registers and original %esp */ + pushl %ds + pushl %es + pushl %fs + pushl %gs + pushl %ss + pushl %esp + + /* Switch to virtual addressing */ + call _intr_to_virt + + /* Expand IRQ number to whole %eax register */ + movzbl %al, %eax + + /* Call interrupt handler */ + call interrupt + + /* Restore original stack and segment registers */ + lss (%esp), %esp + popl %ss + popl %gs + popl %fs + popl %es + popl %ds + + /* Restore registers and return */ + popal + iret + /**************************************************************************** * Stored real-mode and protected-mode stack pointers * diff --git a/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c b/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c index f00be8117..f90d49b02 100644 --- a/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c +++ b/roms/ipxe/src/arch/i386/transitions/librm_mgmt.c @@ -9,19 +9,34 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> #include <realmode.h> +#include <pic8259.h> /* * This file provides functions for managing librm. * */ +/** The interrupt wrapper */ +extern char interrupt_wrapper[]; + +/** The interrupt vectors */ +static struct interrupt_vector intr_vec[ IRQ_MAX + 1 ]; + +/** The interrupt descriptor table */ +struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) )); + +/** The interrupt descriptor table register */ +struct idtr idtr = { + .limit = ( sizeof ( idt ) - 1 ), +}; + /** * Allocate space on the real-mode stack and copy data there from a * user buffer * - * @v data User buffer - * @v size Size of stack data - * @ret sp New value of real-mode stack pointer + * @v data User buffer + * @v size Size of stack data + * @ret sp New value of real-mode stack pointer */ uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { userptr_t rm_stack; @@ -35,8 +50,8 @@ uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { * Deallocate space on the real-mode stack, optionally copying back * data to a user buffer. * - * @v data User buffer - * @v size Size of stack data + * @v data User buffer + * @v size Size of stack data */ void remove_user_from_rm_stack ( userptr_t data, size_t size ) { if ( data ) { @@ -46,6 +61,63 @@ void remove_user_from_rm_stack ( userptr_t data, size_t size ) { rm_sp += size; }; +/** + * Set interrupt vector + * + * @v intr Interrupt number + * @v vector Interrupt vector, or NULL to disable + */ +void set_interrupt_vector ( unsigned int intr, void *vector ) { + struct interrupt_descriptor *idte; + + idte = &idt[intr]; + idte->segment = VIRTUAL_CS; + idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 ); + idte->low = ( ( ( uint32_t ) vector ) & 0xffff ); + idte->high = ( ( ( uint32_t ) vector ) >> 16 ); +} + +/** + * Initialise interrupt descriptor table + * + */ +void init_idt ( void ) { + struct interrupt_vector *vec; + unsigned int irq; + unsigned int intr; + + /* Initialise the interrupt descriptor table and interrupt vectors */ + for ( irq = 0 ; irq <= IRQ_MAX ; irq++ ) { + intr = IRQ_INT ( irq ); + vec = &intr_vec[irq]; + vec->pushal = PUSHAL_INSN; + vec->movb = MOVB_INSN; + vec->intr = intr; + vec->jmp = JMP_INSN; + vec->offset = ( ( uint32_t ) interrupt_wrapper - + ( uint32_t ) vec->next ); + set_interrupt_vector ( intr, vec ); + } + + /* Initialise the interrupt descriptor table register */ + idtr.base = virt_to_phys ( idt ); +} + +/** + * Interrupt handler + * + * @v irq Interrupt number + */ +void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int irq ) { + uint32_t discard_eax; + + /* Reissue interrupt in real mode */ + __asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t" + "\n1:\n\t" + "int $0x00\n\t" ) + : "=a" ( discard_eax ) : "0" ( irq ) ); +} + PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); diff --git a/roms/ipxe/src/arch/i386/transitions/librm_test.c b/roms/ipxe/src/arch/i386/transitions/librm_test.c new file mode 100644 index 000000000..e07cfccdd --- /dev/null +++ b/roms/ipxe/src/arch/i386/transitions/librm_test.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Real mode transition self-tests + * + * This file allows for easy measurement of the time taken to perform + * real mode transitions, which may have a substantial overhead when + * running under a hypervisor. + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <ipxe/test.h> +#include <ipxe/profile.h> +#include <realmode.h> + +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 4096 + +/** Protected-to-real mode transition profiler */ +static struct profiler p2r_profiler __profiler = { .name = "p2r" }; + +/** Real-to-protected mode transition profiler */ +static struct profiler r2p_profiler __profiler = { .name = "r2p" }; + +/** Real-mode call profiler */ +static struct profiler real_call_profiler __profiler = { .name = "real_call" }; + +/** Protected-mode call profiler */ +static struct profiler prot_call_profiler __profiler = { .name = "prot_call" }; + +/** + * Dummy protected-mode function + */ +static void librm_test_prot_call ( void ) { + /* Do nothing */ +} + +/** + * Perform real mode transition self-tests + * + */ +static void librm_test_exec ( void ) { + unsigned int i; + unsigned long timestamp; + unsigned long started; + unsigned long stopped; + unsigned int discard_d; + + /* Profile mode transitions. We want to profile each + * direction of the transition separately, so perform an RDTSC + * while in real mode and tweak the profilers' start/stop + * times appropriately. + */ + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &p2r_profiler ); + __asm__ __volatile__ ( REAL_CODE ( "rdtsc\n\t" ) + : "=a" ( timestamp ), "=d" ( discard_d ) + : ); + profile_start_at ( &r2p_profiler, timestamp ); + profile_stop ( &r2p_profiler ); + profile_stop_at ( &p2r_profiler, timestamp ); + } + + /* Profile complete real-mode call cycle */ + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &real_call_profiler ); + __asm__ __volatile__ ( REAL_CODE ( "" ) : : ); + profile_stop ( &real_call_profiler ); + } + + /* Profile complete protected-mode call cycle */ + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + __asm__ __volatile__ ( REAL_CODE ( "rdtsc\n\t" + "movl %0, %2\n\t" + "pushl %3\n\t" + "pushw %%cs\n\t" + "call prot_call\n\t" + "addw $4, %%sp\n\t" + "rdtsc\n\t" ) + : "=a" ( stopped ), "=d" ( discard_d ), + "=r" ( started ) + : "i" ( librm_test_prot_call ) ); + profile_start_at ( &prot_call_profiler, started ); + profile_stop_at ( &prot_call_profiler, stopped ); + } +} + +/** Real mode transition self-test */ +struct self_test librm_test __self_test = { + .name = "librm", + .exec = librm_test_exec, +}; + +REQUIRE_OBJECT ( test ); diff --git a/roms/ipxe/src/arch/x86/Makefile.efi b/roms/ipxe/src/arch/x86/Makefile.efi index bef8d59d8..3e3fbe3ca 100644 --- a/roms/ipxe/src/arch/x86/Makefile.efi +++ b/roms/ipxe/src/arch/x86/Makefile.efi @@ -12,6 +12,8 @@ LDFLAGS += -q -S # NON_AUTO_MEDIA += efi NON_AUTO_MEDIA += efidrv +NON_AUTO_MEDIA += drv.efi +NON_AUTO_MEDIA += efirom # Rules for building EFI files # @@ -23,6 +25,14 @@ $(BIN)/%.efidrv : $(BIN)/%.efidrv.tmp $(ELF2EFI) $(QM)$(ECHO) " [FINISH] $@" $(Q)$(ELF2EFI) --subsystem=11 $< $@ +$(BIN)/%.drv.efi : $(BIN)/%.efidrv + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(CP) $< $@ + $(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM) $(QM)$(ECHO) " [FINISH] $@" $(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) $< $@ + +$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined + $(QM)$(ECHO) " [CAB] $@" + $(Q)$(LCAB) -n -q $(ALL_drv.efi) $@ diff --git a/roms/ipxe/src/arch/x86/core/cpuid.c b/roms/ipxe/src/arch/x86/core/cpuid.c index 96f794095..5908f4419 100644 --- a/roms/ipxe/src/arch/x86/core/cpuid.c +++ b/roms/ipxe/src/arch/x86/core/cpuid.c @@ -33,7 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * @ret is_supported CPUID instruction is supported */ -static int cpuid_is_supported ( void ) { +int cpuid_is_supported ( void ) { unsigned long original; unsigned long inverted; @@ -53,24 +53,6 @@ static int cpuid_is_supported ( void ) { } /** - * Issue CPUID instruction - * - * @v operation CPUID operation - * @v eax Output via %eax - * @v ebx Output via %ebx - * @v ecx Output via %ecx - * @v edx Output via %edx - */ -static inline __attribute__ (( always_inline )) void -cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, - uint32_t *edx ) { - - __asm__ ( "cpuid" - : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx ) - : "0" ( operation ) ); -} - -/** * Get Intel-defined x86 CPU features * * @v features x86 CPU features to fill in diff --git a/roms/ipxe/src/arch/x86/core/cpuid_settings.c b/roms/ipxe/src/arch/x86/core/cpuid_settings.c new file mode 100644 index 000000000..42dea9336 --- /dev/null +++ b/roms/ipxe/src/arch/x86/core/cpuid_settings.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/init.h> +#include <ipxe/settings.h> +#include <ipxe/cpuid.h> + +/** @file + * + * x86 CPUID settings + * + * CPUID settings are numerically encoded as: + * + * Bit 31 Extended function + * Bits 30-28 Unused + * Bits 27-24 Number of consecutive functions to call, minus one + * Bit 23 Return result as little-endian (used for strings) + * Bits 22-18 Unused + * Bits 17-16 Number of registers in register array, minus one + * Bits 15-8 Array of register indices. First entry in array is in + * bits 9-8. Indices are 0-%eax, 1-%ebx, 2-%ecx, 3-%edx. + * Bits 7-0 Starting function number (excluding "extended" bit) + * + * This encoding scheme is designed to allow the common case of + * extracting a single register from a single function to be encoded + * using "cpuid/<register>.<function>", e.g. "cpuid/2.0x80000001" to + * retrieve the value of %ecx from calling CPUID with %eax=0x80000001. + */ + +/** CPUID setting tag register indices */ +enum cpuid_registers { + CPUID_EAX = 0, + CPUID_EBX = 1, + CPUID_ECX = 2, + CPUID_EDX = 3, +}; + +/** + * Construct CPUID setting tag + * + * @v function Starting function number + * @v num_functions Number of consecutive functions + * @v little_endian Return result as little-endian + * @v num_registers Number of registers in register array + * @v register1 First register in register array (or zero, if empty) + * @v register2 Second register in register array (or zero, if empty) + * @v register3 Third register in register array (or zero, if empty) + * @v register4 Fourth register in register array (or zero, if empty) + * @ret tag Setting tag + */ +#define CPUID_TAG( function, num_functions, little_endian, num_registers, \ + register1, register2, register3, register4 ) \ + ( (function) | ( ( (num_functions) - 1 ) << 24 ) | \ + ( (little_endian) << 23 ) | ( ( (num_registers) - 1) << 16 ) | \ + ( (register1) << 8 ) | ( (register2) << 10 ) | \ + ( (register3) << 12 ) | ( (register4) << 14 ) ) + +/** + * Extract endianness from CPUID setting tag + * + * @v tag Setting tag + * @ret little_endian Result should be returned as little-endian + */ +#define CPUID_LITTLE_ENDIAN( tag ) ( (tag) & 0x00800000UL ) + +/** + * Extract starting function number from CPUID setting tag + * + * @v tag Setting tag + * @ret function Starting function number + */ +#define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL ) + +/** + * Extract number of consecutive functions from CPUID setting tag + * + * @v tag Setting tag + * @ret num_functions Number of consecutive functions + */ +#define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0xf ) + 1 ) + +/** + * Extract register array from CPUID setting tag + * + * @v tag Setting tag + * @ret registers Register array + */ +#define CPUID_REGISTERS( tag ) ( ( (tag) >> 8 ) & 0xff ) + +/** + * Extract number of registers from CPUID setting tag + * + * @v tag Setting tag + * @ret num_registers Number of registers within register array + */ +#define CPUID_NUM_REGISTERS( tag ) ( ( ( (tag) >> 16 ) & 0x3 ) + 1 ) + +/** CPUID settings scope */ +static const struct settings_scope cpuid_settings_scope; + +/** + * Check applicability of CPUID setting + * + * @v settings Settings block + * @v setting Setting + * @ret applies Setting applies within this settings block + */ +static int cpuid_settings_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &cpuid_settings_scope ); +} + +/** + * Fetch value of CPUID setting + * + * @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 + */ +static int cpuid_settings_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + uint32_t function; + uint32_t max_function; + uint32_t num_functions; + uint32_t registers; + uint32_t num_registers; + uint32_t buf[4]; + uint32_t output; + uint32_t discard_b; + uint32_t discard_c; + uint32_t discard_d; + size_t frag_len; + size_t result_len = 0; + + /* Fail unless CPUID is supported */ + if ( ! cpuid_is_supported() ) { + DBGC ( settings, "CPUID not supported\n" ); + return -ENOTSUP; + } + + /* Find highest supported function number within this set */ + function = CPUID_FUNCTION ( setting->tag ); + cpuid ( function & CPUID_EXTENDED, &max_function, &discard_b, + &discard_c, &discard_d ); + + /* Fail if maximum function number is meaningless (e.g. if we + * are attempting to call an extended function on a CPU which + * does not support them). + */ + if ( ( max_function & CPUID_AMD_CHECK_MASK ) != + ( function & CPUID_AMD_CHECK_MASK ) ) { + DBGC ( settings, "CPUID invalid maximum function\n" ); + return -ENOTSUP; + } + + /* Call each function in turn */ + num_functions = CPUID_NUM_FUNCTIONS ( setting->tag ); + for ( ; num_functions-- ; function++ ) { + + /* Fail if this function is not supported */ + if ( function > max_function ) { + DBGC ( settings, "CPUID function %#08x not supported\n", + function ); + return -ENOTSUP; + } + + /* Issue CPUID */ + cpuid ( function, &buf[CPUID_EAX], &buf[CPUID_EBX], + &buf[CPUID_ECX], &buf[CPUID_EDX] ); + DBGC ( settings, "CPUID %#08x => %#08x:%#08x:%#08x:%#08x\n", + function, buf[0], buf[1], buf[2], buf[3] ); + + /* Copy results to buffer */ + registers = CPUID_REGISTERS ( setting->tag ); + num_registers = CPUID_NUM_REGISTERS ( setting->tag ); + for ( ; num_registers-- ; registers >>= 2 ) { + output = buf[ registers & 0x3 ]; + if ( ! CPUID_LITTLE_ENDIAN ( setting->tag ) ) + output = cpu_to_be32 ( output ); + frag_len = sizeof ( output ); + if ( frag_len > len ) + frag_len = len; + memcpy ( data, &output, frag_len ); + data += frag_len; + len -= frag_len; + result_len += sizeof ( output ); + } + } + + /* Set type if not already specified */ + if ( ! setting->type ) + setting->type = &setting_type_hexraw; + + return result_len; +} + +/** CPUID settings operations */ +static struct settings_operations cpuid_settings_operations = { + .applies = cpuid_settings_applies, + .fetch = cpuid_settings_fetch, +}; + +/** CPUID settings */ +static struct settings cpuid_settings = { + .refcnt = NULL, + .siblings = LIST_HEAD_INIT ( cpuid_settings.siblings ), + .children = LIST_HEAD_INIT ( cpuid_settings.children ), + .op = &cpuid_settings_operations, + .default_scope = &cpuid_settings_scope, +}; + +/** Initialise CPUID settings */ +static void cpuid_settings_init ( void ) { + int rc; + + if ( ( rc = register_settings ( &cpuid_settings, NULL, + "cpuid" ) ) != 0 ) { + DBG ( "CPUID could not register settings: %s\n", + strerror ( rc ) ); + return; + } +} + +/** CPUID settings initialiser */ +struct init_fn cpuid_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = cpuid_settings_init, +}; + +/** CPU vendor setting */ +const struct setting cpuvendor_setting __setting ( SETTING_HOST_EXTRA, + cpuvendor ) = { + .name = "cpuvendor", + .description = "CPU vendor", + .tag = CPUID_TAG ( CPUID_VENDOR_ID, 1, 1, 3, + CPUID_EBX, CPUID_EDX, CPUID_ECX, 0 ), + .type = &setting_type_string, + .scope = &cpuid_settings_scope, +}; + +/** CPU model setting */ +const struct setting cpumodel_setting __setting ( SETTING_HOST_EXTRA, + cpumodel ) = { + .name = "cpumodel", + .description = "CPU model", + .tag = CPUID_TAG ( CPUID_MODEL, 3, 1, 4, + CPUID_EAX, CPUID_EBX, CPUID_ECX, CPUID_EDX ), + .type = &setting_type_string, + .scope = &cpuid_settings_scope, +}; diff --git a/roms/ipxe/src/arch/x86/core/debugcon.c b/roms/ipxe/src/arch/x86/core/debugcon.c index b89480aa5..263cb4af1 100644 --- a/roms/ipxe/src/arch/x86/core/debugcon.c +++ b/roms/ipxe/src/arch/x86/core/debugcon.c @@ -74,7 +74,7 @@ static void debugcon_init ( void ) { check = inb ( DEBUG_PORT ); if ( check != DEBUG_PORT_CHECK ) { DBG ( "Debug port not present; disabling console\n" ); - debugcon_console.disabled = 1; + debugcon_console.disabled = CONSOLE_DISABLED; } } diff --git a/roms/ipxe/src/arch/x86/core/linux/linux_api.c b/roms/ipxe/src/arch/x86/core/linux/linux_api.c index c8a09b7d8..0bed9fd57 100644 --- a/roms/ipxe/src/arch/x86/core/linux/linux_api.c +++ b/roms/ipxe/src/arch/x86/core/linux/linux_api.c @@ -37,6 +37,10 @@ int linux_close ( int fd ) { return linux_syscall ( __NR_close, fd ); } +off_t linux_lseek ( int fd, off_t offset, int whence ) { + return linux_syscall ( __NR_lseek, fd, offset, whence ); +} + __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ) { return linux_syscall ( __NR_read, fd, buf, count ); } diff --git a/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c b/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c index 981143308..c4e35d179 100644 --- a/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c +++ b/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c @@ -54,8 +54,7 @@ static struct option_descriptor cpuid_opts[] = { /** "cpuid" command descriptor */ static struct command_descriptor cpuid_cmd = - COMMAND_DESC ( struct cpuid_options, cpuid_opts, 1, 1, - "[--ext] [--ecx] <bit>" ); + COMMAND_DESC ( struct cpuid_options, cpuid_opts, 1, 1, "<bit>" ); /** * The "cpuid" command diff --git a/roms/ipxe/src/arch/x86/include/bits/errfile.h b/roms/ipxe/src/arch/x86/include/bits/errfile.h index 7b9f3702e..acf8c3e39 100644 --- a/roms/ipxe/src/arch/x86/include/bits/errfile.h +++ b/roms/ipxe/src/arch/x86/include/bits/errfile.h @@ -19,6 +19,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_vmware ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 ) #define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 ) #define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 ) +#define ERRFILE_apm ( ERRFILE_ARCH | ERRFILE_CORE | 0x000b0000 ) +#define ERRFILE_vesafb ( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) @@ -33,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 ) #define ERRFILE_sdi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 ) #define ERRFILE_initrd ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000c0000 ) +#define ERRFILE_pxe_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000d0000 ) #define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 ) #define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 ) @@ -44,6 +47,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 ) #define ERRFILE_cpuid_cmd ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00000000 ) +#define ERRFILE_cpuid_settings ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00010000 ) /** @} */ diff --git a/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h b/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h index 9705137c6..2f78dfca1 100644 --- a/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h +++ b/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h @@ -30,6 +30,9 @@ struct x86_features { /** CPUID support flag */ #define CPUID_FLAG 0x00200000UL +/** CPUID extended function */ +#define CPUID_EXTENDED 0x80000000UL + /** Get vendor ID and largest standard function */ #define CPUID_VENDOR_ID 0x00000000UL @@ -48,6 +51,28 @@ struct x86_features { /** Get extended features */ #define CPUID_AMD_FEATURES 0x80000001UL +/** Get CPU model */ +#define CPUID_MODEL 0x80000002UL + +/** + * Issue CPUID instruction + * + * @v operation CPUID operation + * @v eax Output via %eax + * @v ebx Output via %ebx + * @v ecx Output via %ecx + * @v edx Output via %edx + */ +static inline __attribute__ (( always_inline )) void +cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, + uint32_t *edx ) { + + __asm__ ( "cpuid" + : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx ) + : "0" ( operation ) ); +} + +extern int cpuid_is_supported ( void ); extern void x86_features ( struct x86_features *features ); #endif /* _IPXE_CPUID_H */ diff --git a/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h b/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h index 46d234324..7d4b56d31 100644 --- a/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h +++ b/roms/ipxe/src/arch/x86/include/valgrind/memcheck.h @@ -60,6 +60,8 @@ #ifndef __MEMCHECK_H #define __MEMCHECK_H +FILE_LICENCE ( BSD3 ); + /* This file is for inclusion into client (your!) code. diff --git a/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h b/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h index d72754b05..d48bbccae 100644 --- a/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h +++ b/roms/ipxe/src/arch/x86/include/valgrind/valgrind.h @@ -73,6 +73,8 @@ #ifndef __VALGRIND_H #define __VALGRIND_H +FILE_LICENCE ( BSD3 ); + /* ------------------------------------------------------------------ */ /* VERSION NUMBER OF VALGRIND */ diff --git a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c index 8a31df56d..280e33535 100644 --- a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c +++ b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <ipxe/init.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_snp.h> /** * EFI entry point @@ -42,7 +43,8 @@ EFI_STATUS EFIAPI _efidrv_start ( EFI_HANDLE image_handle, initialise(); startup(); + /* Release network devices for use via SNP */ + efi_snp_release(); + return 0; } - -REQUIRE_OBJECT ( efi_snp ); diff --git a/roms/ipxe/src/arch/x86/prefix/efiprefix.c b/roms/ipxe/src/arch/x86/prefix/efiprefix.c index bfa94d404..eb8aa738a 100644 --- a/roms/ipxe/src/arch/x86/prefix/efiprefix.c +++ b/roms/ipxe/src/arch/x86/prefix/efiprefix.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> +#include <errno.h> #include <ipxe/efi/efi.h> /** @@ -32,11 +33,20 @@ FILE_LICENCE ( GPL2_OR_LATER ); EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ) { EFI_STATUS efirc; + int rc; /* Initialise EFI environment */ if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) - return efirc; + goto err_init; /* Call to main() */ - return RC_TO_EFIRC ( main () ); + if ( ( rc = main() ) != 0 ) { + efirc = EFIRC ( rc ); + goto err_main; + } + + err_main: + efi_loaded_image->Unload ( image_handle ); + err_init: + return efirc; } diff --git a/roms/ipxe/src/arch/x86/scripts/efi.lds b/roms/ipxe/src/arch/x86/scripts/efi.lds index 1a16c29bd..f1049f24b 100644 --- a/roms/ipxe/src/arch/x86/scripts/efi.lds +++ b/roms/ipxe/src/arch/x86/scripts/efi.lds @@ -55,6 +55,8 @@ SECTIONS { *(.data) *(.data.*) KEEP(*(SORT(.tbl.*))) /* Various tables. See include/tables.h */ + KEEP(*(.provided)) + KEEP(*(.provided.*)) _edata = .; } diff --git a/roms/ipxe/src/arch/x86_64/include/bits/profile.h b/roms/ipxe/src/arch/x86_64/include/bits/profile.h new file mode 100644 index 000000000..6fc16d84b --- /dev/null +++ b/roms/ipxe/src/arch/x86_64/include/bits/profile.h @@ -0,0 +1,29 @@ +#ifndef _BITS_PROFILE_H +#define _BITS_PROFILE_H + +/** @file + * + * Profiling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> + +/** + * Get profiling timestamp + * + * @ret timestamp Timestamp + */ +static inline __attribute__ (( always_inline )) uint64_t +profile_timestamp ( void ) { + uint32_t eax; + uint32_t edx; + + /* Read timestamp counter */ + __asm__ __volatile__ ( "rdtsc" : "=a" ( eax ), "=d" ( edx ) ); + return ( ( ( ( uint64_t ) edx ) << 32 ) | eax ); +} + +#endif /* _BITS_PROFILE_H */ diff --git a/roms/ipxe/src/arch/x86_64/include/bits/reboot.h b/roms/ipxe/src/arch/x86_64/include/bits/reboot.h new file mode 100644 index 000000000..f1bce0540 --- /dev/null +++ b/roms/ipxe/src/arch/x86_64/include/bits/reboot.h @@ -0,0 +1,12 @@ +#ifndef _BITS_REBOOT_H +#define _BITS_REBOOT_H + +/** @file + * + * x86_64-specific reboot API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#endif /* _BITS_REBOOT_H */ diff --git a/roms/ipxe/src/arch/x86_64/include/bits/strings.h b/roms/ipxe/src/arch/x86_64/include/bits/strings.h new file mode 100644 index 000000000..6ee99a500 --- /dev/null +++ b/roms/ipxe/src/arch/x86_64/include/bits/strings.h @@ -0,0 +1,42 @@ +#ifndef _BITS_STRINGS_H +#define _BITS_STRINGS_H + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsll ( long long value ){ + long long msb_minus_one; + + /* If the input value is zero, the BSR instruction returns + * ZF=1 and leaves an undefined value in the output register. + * Perform this check in C rather than asm so that it can be + * omitted in cases where the compiler is able to prove that + * the input is non-zero. + */ + if ( value ) { + __asm__ ( "bsrq %1, %0" + : "=r" ( msb_minus_one ) + : "rm" ( value ) ); + return ( msb_minus_one + 1 ); + } else { + return 0; + } +} + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsl ( long value ) { + + return __flsll ( value ); +} + +#endif /* _BITS_STRINGS_H */ diff --git a/roms/ipxe/src/arch/x86_64/include/gdbmach.h b/roms/ipxe/src/arch/x86_64/include/gdbmach.h index fcf8e94e6..6dadbbdd3 100644 --- a/roms/ipxe/src/arch/x86_64/include/gdbmach.h +++ b/roms/ipxe/src/arch/x86_64/include/gdbmach.h @@ -48,4 +48,6 @@ static inline void gdbmach_breakpoint ( void ) { extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ); +extern void gdbmach_init ( void ); + #endif /* GDBMACH_H */ diff --git a/roms/ipxe/src/arch/x86_64/scripts/linux.lds b/roms/ipxe/src/arch/x86_64/scripts/linux.lds index 85e548ffe..47db21745 100644 --- a/roms/ipxe/src/arch/x86_64/scripts/linux.lds +++ b/roms/ipxe/src/arch/x86_64/scripts/linux.lds @@ -53,6 +53,8 @@ SECTIONS { *(.data) *(.data.*) KEEP(*(SORT(.tbl.*))) + KEEP(*(.provided)) + KEEP(*(.provided.*)) _edata = .; } diff --git a/roms/ipxe/src/config/colour.h b/roms/ipxe/src/config/colour.h index d32d46dc5..c75f65e6d 100644 --- a/roms/ipxe/src/config/colour.h +++ b/roms/ipxe/src/config/colour.h @@ -27,6 +27,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define COLOR_URL_FG COLOR_CYAN #define COLOR_URL_BG COLOR_BLUE +#define COLOR_PXE_FG COLOR_BLACK +#define COLOR_PXE_BG COLOR_WHITE + #include <config/local/colour.h> #endif /* CONFIG_COLOUR_H */ diff --git a/roms/ipxe/src/config/config.c b/roms/ipxe/src/config/config.c index bd1d98856..6c8b9551a 100644 --- a/roms/ipxe/src/config/config.c +++ b/roms/ipxe/src/config/config.c @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <config/general.h> #include <config/console.h> #include <config/sideband.h> +#include <config/settings.h> /** @file * @@ -92,6 +93,9 @@ REQUIRE_OBJECT ( vmconsole ); #ifdef CONSOLE_DEBUGCON REQUIRE_OBJECT ( debugcon ); #endif +#ifdef CONSOLE_VESAFB +REQUIRE_OBJECT ( vesafb ); +#endif /* * Drag in all requested network protocols @@ -100,6 +104,9 @@ REQUIRE_OBJECT ( debugcon ); #ifdef NET_PROTO_IPV4 REQUIRE_OBJECT ( ipv4 ); #endif +#ifdef NET_PROTO_IPV6 +REQUIRE_OBJECT ( ipv6 ); +#endif /* * Drag in all requested PXE support @@ -128,6 +135,9 @@ REQUIRE_OBJECT ( https ); #ifdef DOWNLOAD_PROTO_FTP REQUIRE_OBJECT ( ftp ); #endif +#ifdef DOWNLOAD_PROTO_NFS +REQUIRE_OBJECT ( nfs_open ); +#endif #ifdef DOWNLOAD_PROTO_SLAM REQUIRE_OBJECT ( slam ); #endif @@ -187,6 +197,12 @@ REQUIRE_OBJECT ( efi_image ); #ifdef IMAGE_SDI REQUIRE_OBJECT ( sdi ); #endif +#ifdef IMAGE_PNM +REQUIRE_OBJECT ( pnm ); +#endif +#ifdef IMAGE_PNG +REQUIRE_OBJECT ( png ); +#endif /* * Drag in all requested commands @@ -241,6 +257,9 @@ REQUIRE_OBJECT ( lotest_cmd ); #ifdef VLAN_CMD REQUIRE_OBJECT ( vlan_cmd ); #endif +#ifdef POWEROFF_CMD +REQUIRE_OBJECT ( poweroff_cmd ); +#endif #ifdef REBOOT_CMD REQUIRE_OBJECT ( reboot_cmd ); #endif @@ -253,6 +272,27 @@ REQUIRE_OBJECT ( sync_cmd ); #ifdef NSLOOKUP_CMD REQUIRE_OBJECT ( nslookup_cmd ); #endif +#ifdef PCI_CMD +REQUIRE_OBJECT ( pci_cmd ); +#endif +#ifdef PARAM_CMD +REQUIRE_OBJECT ( param_cmd ); +#endif +#ifdef NEIGHBOUR_CMD +REQUIRE_OBJECT ( neighbour_cmd ); +#endif +#ifdef PING_CMD +REQUIRE_OBJECT ( ping_cmd ); +#endif +#ifdef CONSOLE_CMD +REQUIRE_OBJECT ( console_cmd ); +#endif +#ifdef IPSTAT_CMD +REQUIRE_OBJECT ( ipstat_cmd ); +#endif +#ifdef PROFSTAT_CMD +REQUIRE_OBJECT ( profstat_cmd ); +#endif /* * Drag in miscellaneous objects @@ -293,9 +333,22 @@ REQUIRE_OBJECT ( tap ); REQUIRE_OBJECT ( efi_bofm ); #endif /* BOFM_EFI */ #endif /* CONFIG_BOFM */ + +/* + * Drag in relevant settings sources + */ +#ifdef PCI_SETTINGS +REQUIRE_OBJECT ( pci_settings ); +#endif #ifdef VMWARE_SETTINGS REQUIRE_OBJECT ( guestinfo ); -#endif /* VMWARE_SETTINGS */ +#endif +#ifdef CPUID_SETTINGS +REQUIRE_OBJECT ( cpuid_settings ); +#endif +#ifdef MEMMAP_SETTINGS +REQUIRE_OBJECT ( memmap_settings ); +#endif /* * Drag in selected keyboard map diff --git a/roms/ipxe/src/config/config_route.c b/roms/ipxe/src/config/config_route.c new file mode 100644 index 000000000..33e18cdd3 --- /dev/null +++ b/roms/ipxe/src/config/config_route.c @@ -0,0 +1,27 @@ +/* + * 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 + * + * Routing management configuration options + * + */ + +/* + * Drag in routing management for relevant protocols + * + */ +#ifdef NET_PROTO_IPV4 +REQUIRE_OBJECT ( route_ipv4 ); +#endif +#ifdef NET_PROTO_IPV6 +REQUIRE_OBJECT ( route_ipv6 ); +#endif diff --git a/roms/ipxe/src/config/console.h b/roms/ipxe/src/config/console.h index 04be02dc4..5d2cc1dce 100644 --- a/roms/ipxe/src/config/console.h +++ b/roms/ipxe/src/config/console.h @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONSOLE_SYSLOGS /* Encrypted syslog console */ //#define CONSOLE_VMWARE /* VMware logfile console */ //#define CONSOLE_DEBUGCON /* Debug port console */ +//#define CONSOLE_VESAFB /* VESA framebuffer console */ #define KEYBOARD_MAP us diff --git a/roms/ipxe/src/config/crypto.h b/roms/ipxe/src/config/crypto.h new file mode 100644 index 000000000..95c73d477 --- /dev/null +++ b/roms/ipxe/src/config/crypto.h @@ -0,0 +1,22 @@ +#ifndef CONFIG_CRYPTO_H +#define CONFIG_CRYPTO_H + +/** @file + * + * Cryptographic configuration + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** Margin of error (in seconds) allowed in signed timestamps + * + * We default to allowing a reasonable margin of error: 12 hours to + * allow for the local time zone being non-GMT, plus 30 minutes to + * allow for general clock drift. + */ +#define TIMESTAMP_ERROR_MARGIN ( ( 12 * 60 + 30 ) * 60 ) + +#include <config/local/crypto.h> + +#endif /* CONFIG_CRYPTO_H */ diff --git a/roms/ipxe/src/config/defaults/efi.h b/roms/ipxe/src/config/defaults/efi.h index 923360ae8..4276d9366 100644 --- a/roms/ipxe/src/config/defaults/efi.h +++ b/roms/ipxe/src/config/defaults/efi.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #define UACCESS_EFI #define IOAPI_X86 #define PCIAPI_EFI @@ -19,8 +21,12 @@ #define BOFM_EFI #define ENTROPY_NULL #define TIME_NULL +#define REBOOT_EFI #define IMAGE_EFI /* EFI image support */ #define IMAGE_SCRIPT /* iPXE script image support */ +#define REBOOT_CMD /* Reboot command */ +#define CPUID_CMD /* x86 CPU feature detection command */ + #endif /* CONFIG_DEFAULTS_EFI_H */ diff --git a/roms/ipxe/src/config/defaults/linux.h b/roms/ipxe/src/config/defaults/linux.h index 50897560d..bc5ba7851 100644 --- a/roms/ipxe/src/config/defaults/linux.h +++ b/roms/ipxe/src/config/defaults/linux.h @@ -7,6 +7,8 @@ * */ +FILE_LICENCE ( GPL2_OR_LATER ); + #define CONSOLE_LINUX #define TIMER_LINUX #define UACCESS_LINUX @@ -16,6 +18,8 @@ #define SANBOOT_NULL #define ENTROPY_LINUX #define TIME_LINUX +#define REBOOT_NULL +#define PCIAPI_LINUX #define DRIVERS_LINUX diff --git a/roms/ipxe/src/config/defaults/pcbios.h b/roms/ipxe/src/config/defaults/pcbios.h index c52fca972..7debc8d2f 100644 --- a/roms/ipxe/src/config/defaults/pcbios.h +++ b/roms/ipxe/src/config/defaults/pcbios.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define SANBOOT_PCBIOS #define ENTROPY_RTC #define TIME_RTC +#define REBOOT_PCBIOS #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ diff --git a/roms/ipxe/src/config/general.h b/roms/ipxe/src/config/general.h index 9f0bb521b..72cfc3b86 100644 --- a/roms/ipxe/src/config/general.h +++ b/roms/ipxe/src/config/general.h @@ -28,11 +28,22 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define PRODUCT_SHORT_NAME "iPXE" /* - * Timer configuration - * + * Banner timeout configuration + * + * This controls the timeout for the "Press Ctrl-B for the iPXE + * command line" banner displayed when iPXE starts up. The value is + * specified in tenths of a second for which the banner should appear. + * A value of 0 disables the banner. + * + * ROM_BANNER_TIMEOUT controls the "Press Ctrl-B to configure iPXE" + * banner displayed only by ROM builds of iPXE during POST. This + * defaults to being twice the length of BANNER_TIMEOUT, to allow for + * BIOSes that switch video modes immediately before calling the + * initialisation vector, thus rendering the banner almost invisible + * to the user. */ -#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell - banner should appear */ +#define BANNER_TIMEOUT 20 +#define ROM_BANNER_TIMEOUT ( 2 * BANNER_TIMEOUT ) /* * Network protocols @@ -40,6 +51,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #define NET_PROTO_IPV4 /* IPv4 protocol */ +#undef NET_PROTO_IPV6 /* IPv6 protocol */ #undef NET_PROTO_FCOE /* Fibre Channel over Ethernet protocol */ /* @@ -59,6 +71,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ #undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ #undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ +#undef DOWNLOAD_PROTO_NFS /* Network File System Protocol */ /* * SAN boot protocols @@ -101,6 +114,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ //#define IMAGE_EFI /* EFI image support */ //#define IMAGE_SDI /* SDI image support */ +//#define IMAGE_PNM /* PNM image support */ +//#define IMAGE_PNG /* PNG image support */ /* * Command-line commands to include @@ -126,7 +141,15 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define VLAN_CMD /* VLAN commands */ //#define PXE_CMD /* PXE commands */ //#define REBOOT_CMD /* Reboot command */ +//#define POWEROFF_CMD /* Power off command */ //#define IMAGE_TRUST_CMD /* Image trust management commands */ +//#define PCI_CMD /* PCI commands */ +//#define PARAM_CMD /* Form parameter commands */ +//#define NEIGHBOUR_CMD /* Neighbour management commands */ +//#define PING_CMD /* Ping command */ +//#define CONSOLE_CMD /* Console command */ +//#define IPSTAT_CMD /* IP statistics commands */ +//#define PROFSTAT_CMD /* Profiling commands */ /* * ROM-specific options diff --git a/roms/ipxe/src/config/reboot.h b/roms/ipxe/src/config/reboot.h new file mode 100644 index 000000000..240ef87be --- /dev/null +++ b/roms/ipxe/src/config/reboot.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_REBOOT_H +#define CONFIG_REBOOT_H + +/** @file + * + * Reboot API configuration + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <config/defaults.h> + +#include <config/local/reboot.h> + +#endif /* CONFIG_REBOOT_H */ diff --git a/roms/ipxe/src/config/settings.h b/roms/ipxe/src/config/settings.h new file mode 100644 index 000000000..b06f2901b --- /dev/null +++ b/roms/ipxe/src/config/settings.h @@ -0,0 +1,19 @@ +#ifndef CONFIG_SETTINGS_H +#define CONFIG_SETTINGS_H + +/** @file + * + * Configuration settings sources + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#define PCI_SETTINGS /* PCI device settings */ +//#define CPUID_SETTINGS /* CPUID settings */ +//#define MEMMAP_SETTINGS /* Memory map settings */ +//#define VMWARE_SETTINGS /* VMware GuestInfo settings */ + +#include <config/local/settings.h> + +#endif /* CONFIG_SETTINGS_H */ diff --git a/roms/ipxe/src/config/sideband.h b/roms/ipxe/src/config/sideband.h index 52339993e..2e2a8d419 100644 --- a/roms/ipxe/src/config/sideband.h +++ b/roms/ipxe/src/config/sideband.h @@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */ -//#define VMWARE_SETTINGS /* VMware GuestInfo settings */ #include <config/local/sideband.h> diff --git a/roms/ipxe/src/core/ansicol.c b/roms/ipxe/src/core/ansicol.c new file mode 100644 index 000000000..142a00f8d --- /dev/null +++ b/roms/ipxe/src/core/ansicol.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <errno.h> +#include <assert.h> +#include <ipxe/ansiesc.h> +#include <ipxe/ansicol.h> +#include <config/colour.h> + +/** @file + * + * ANSI colours + * + */ + +/** ANSI colour pair definitions */ +static struct ansicol_pair ansicol_pairs[] = { + [CPAIR_DEFAULT] = { COLOR_DEFAULT, COLOR_DEFAULT }, + [CPAIR_NORMAL] = { COLOR_NORMAL_FG, COLOR_NORMAL_BG }, + [CPAIR_SELECT] = { COLOR_SELECT_FG, COLOR_SELECT_BG }, + [CPAIR_SEPARATOR] = { COLOR_SEPARATOR_FG, COLOR_SEPARATOR_BG }, + [CPAIR_EDIT] = { COLOR_EDIT_FG, COLOR_EDIT_BG }, + [CPAIR_ALERT] = { COLOR_ALERT_FG, COLOR_ALERT_BG }, + [CPAIR_URL] = { COLOR_URL_FG, COLOR_URL_BG }, + [CPAIR_PXE] = { COLOR_PXE_FG, COLOR_PXE_BG }, +}; + +/** + * Set ANSI colour (when no colour definition support is present) + * + * @v colour Colour index + * @v which Foreground/background selector + */ +__weak void ansicol_set ( unsigned int colour, unsigned int which ) { + + /* Colour indices are hardcoded and should never be out of range */ + assert ( colour < 10 ); + + /* Set basic colour */ + printf ( CSI "%c%dm", which, colour ); +} + +/** + * Set ANSI foreground colour + * + * @v colour Colour index + */ +static void ansicol_foreground ( unsigned int colour ) { + ansicol_set ( colour, '3' ); +} + +/** + * Set ANSI background colour + * + * @v colour Colour index + */ +static void ansicol_background ( unsigned int colour ) { + ansicol_set ( colour, '4' ); +} + +/** + * Set ANSI foreground and background colour + * + * @v cpair Colour pair index + */ +void ansicol_set_pair ( unsigned int cpair ) { + struct ansicol_pair *pair; + + /* Colour pair indices are hardcoded and should never be out of range */ + assert ( cpair < ( sizeof ( ansicol_pairs ) / + sizeof ( ansicol_pairs[0] ) ) ); + + /* Set both foreground and background colours */ + pair = &ansicol_pairs[cpair]; + ansicol_foreground ( pair->foreground ); + ansicol_background ( pair->background ); +} + +/** + * Define ANSI colour pair + * + * @v cpair Colour pair index + * @v foreground Foreground colour index + * @v background Background colour index + * @ret rc Return status code + */ +int ansicol_define_pair ( unsigned int cpair, unsigned int foreground, + unsigned int background ) { + struct ansicol_pair *pair; + + /* Fail if colour index is out of range */ + if ( cpair >= ( sizeof ( ansicol_pairs ) / sizeof ( ansicol_pairs[0] ))) + return -EINVAL; + + /* Update colour pair definition */ + pair = &ansicol_pairs[cpair]; + pair->foreground = foreground; + pair->background = background; + DBGC ( &ansicol_pairs[0], "ANSICOL redefined colour pair %d as " + "foreground %d background %d\n", cpair, foreground, background ); + + return 0; +} diff --git a/roms/ipxe/src/core/ansicoldef.c b/roms/ipxe/src/core/ansicoldef.c new file mode 100644 index 000000000..dd89f3b70 --- /dev/null +++ b/roms/ipxe/src/core/ansicoldef.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <errno.h> +#include <ipxe/ansiesc.h> +#include <ipxe/ansicol.h> +#include <config/colour.h> + +/** @file + * + * ANSI colour definitions + * + */ + +/** + * Construct ANSI colour definition + * + * @v basic Basic colour + * @v rgb 24-bit RGB value (or ANSICOL_NO_RGB) + * @ret ansicol ANSI colour definition + */ +#define ANSICOL_DEFINE( basic, rgb ) ( ( (basic) << 28 ) | (rgb) ) + +/** + * Extract basic colour from ANSI colour definition + * + * @v ansicol ANSI colour definition + * @ret basic Basic colour + */ +#define ANSICOL_BASIC( ansicol ) ( (ansicol) >> 28 ) + +/** + * Extract 24-bit RGB value from ANSI colour definition + * + * @v ansicol ANSI colour definition + * @ret rgb 24-bit RGB value + */ +#define ANSICOL_RGB( ansicol ) ( ( (ansicol) >> 0 ) & 0xffffffUL ) + +/** + * Extract 24-bit RGB value red component from ANSI colour definition + * + * @v ansicol ANSI colour definition + * @ret red Red component + */ +#define ANSICOL_RED( ansicol ) ( ( (ansicol) >> 16 ) & 0xff ) + +/** + * Extract 24-bit RGB value green component from ANSI colour definition + * + * @v ansicol ANSI colour definition + * @ret green Green component + */ +#define ANSICOL_GREEN( ansicol ) ( ( (ansicol) >> 8 ) & 0xff ) + +/** + * Extract 24-bit RGB value blue component from ANSI colour definition + * + * @v ansicol ANSI colour definition + * @ret blue Blue component + */ +#define ANSICOL_BLUE( ansicol ) ( ( (ansicol) >> 0 ) & 0xff ) + +/** + * Construct default ANSI colour definition + * + * @v basic Basic colour + * @ret ansicol ANSI colour definition + * + * Colours default to being just a basic colour. If the colour + * matches the normal UI text background colour, then its basic colour + * value is set to @c ANSICOL_MAGIC. + */ +#define ANSICOL_DEFAULT( basic ) \ + ANSICOL_DEFINE ( ( ( (basic) == COLOR_NORMAL_BG ) ? \ + ANSICOL_MAGIC : (basic) ), \ + ANSICOL_NO_RGB ) + +/** ANSI colour definitions */ +static uint32_t ansicols[] = { + [COLOR_BLACK] = ANSICOL_DEFAULT ( COLOR_BLACK ), + [COLOR_RED] = ANSICOL_DEFAULT ( COLOR_RED ), + [COLOR_GREEN] = ANSICOL_DEFAULT ( COLOR_GREEN ), + [COLOR_YELLOW] = ANSICOL_DEFAULT ( COLOR_YELLOW ), + [COLOR_BLUE] = ANSICOL_DEFAULT ( COLOR_BLUE ), + [COLOR_MAGENTA] = ANSICOL_DEFAULT ( COLOR_MAGENTA ), + [COLOR_CYAN] = ANSICOL_DEFAULT ( COLOR_CYAN ), + [COLOR_WHITE] = ANSICOL_DEFAULT ( COLOR_WHITE ), +}; + +/** Magic basic colour */ +static uint8_t ansicol_magic = COLOR_NORMAL_BG; + +/** + * Define ANSI colour + * + * @v colour Colour index + * @v basic Basic colour + * @v rgb 24-bit RGB value (or ANSICOL_NO_RGB) + * @ret rc Return status code + */ +int ansicol_define ( unsigned int colour, unsigned int basic, uint32_t rgb ) { + uint32_t ansicol; + + /* Fail if colour index is out of range */ + if ( colour >= ( sizeof ( ansicols ) / sizeof ( ansicols[0] ) ) ) + return -EINVAL; + + /* Update colour definition */ + ansicol = ANSICOL_DEFINE ( basic, rgb ); + ansicols[colour] = ansicol; + DBGC ( &ansicols[0], "ANSICOL redefined colour %d as basic %d RGB " + "%#06lx%s\n", colour, ANSICOL_BASIC ( ansicol ), + ANSICOL_RGB ( ansicol ), + ( ( ansicol & ANSICOL_NO_RGB ) ? " [norgb]" : "" ) ); + + return 0; +} + +/** + * Set ANSI colour (using colour definitions) + * + * @v colour Colour index + * @v which Foreground/background selector + */ +void ansicol_set ( unsigned int colour, unsigned int which ) { + uint32_t ansicol; + unsigned int basic; + + /* Use default colour if colour index is out of range */ + if ( colour < ( sizeof ( ansicols ) / sizeof ( ansicols[0] ) ) ) { + ansicol = ansicols[colour]; + } else { + ansicol = ANSICOL_DEFINE ( COLOUR_DEFAULT, ANSICOL_NO_RGB ); + } + + /* If basic colour is out of range, use the magic colour */ + basic = ANSICOL_BASIC ( ansicol ); + if ( basic >= 10 ) + basic = ansicol_magic; + + /* Set basic colour first */ + printf ( CSI "%c%dm", which, basic ); + + /* Set 24-bit RGB colour, if applicable */ + if ( ! ( ansicol & ANSICOL_NO_RGB ) ) { + printf ( CSI "%c8;2;%d;%d;%dm", which, ANSICOL_RED ( ansicol ), + ANSICOL_GREEN ( ansicol ), ANSICOL_BLUE ( ansicol ) ); + } +} + +/** + * Reset magic colour + * + */ +void ansicol_reset_magic ( void ) { + + /* Set to the compile-time default background colour */ + ansicol_magic = COLOR_NORMAL_BG; +} + +/** + * Set magic colour to transparent + * + */ +void ansicol_set_magic_transparent ( void ) { + + /* Set to the console default colour (which will give a + * transparent background on the framebuffer console). + */ + ansicol_magic = COLOR_DEFAULT; +} diff --git a/roms/ipxe/src/core/ansiesc.c b/roms/ipxe/src/core/ansiesc.c index 32e9d7c9f..ca9a73ce0 100644 --- a/roms/ipxe/src/core/ansiesc.c +++ b/roms/ipxe/src/core/ansiesc.c @@ -32,19 +32,20 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Call ANSI escape sequence handler * - * @v handlers List of escape sequence handlers + * @v ctx ANSI escape sequence context * @v function Control function identifier * @v count Parameter count * @v params Parameter list */ -static void ansiesc_call_handler ( struct ansiesc_handler *handlers, +static void ansiesc_call_handler ( struct ansiesc_context *ctx, unsigned int function, int count, int params[] ) { + struct ansiesc_handler *handlers = ctx->handlers; struct ansiesc_handler *handler; for ( handler = handlers ; handler->function ; handler++ ) { if ( handler->function == function ) { - handler->handle ( count, params ); + handler->handle ( ctx, count, params ); break; } } @@ -67,6 +68,7 @@ static void ansiesc_call_handler ( struct ansiesc_handler *handlers, * sequences we are prepared to accept as valid. */ int ansiesc_process ( struct ansiesc_context *ctx, int c ) { + if ( ctx->count == 0 ) { if ( c == ESC ) { /* First byte of CSI : begin escape sequence */ @@ -97,7 +99,8 @@ int ansiesc_process ( struct ansiesc_context *ctx, int c ) { DBG ( "Too many parameters in ANSI escape " "sequence\n" ); } - } else if ( ( c >= 0x20 ) && ( c <= 0x2f ) ) { + } else if ( ( ( c >= 0x20 ) && ( c <= 0x2f ) ) || + ( c == '?' ) ) { /* Intermediate Byte */ ctx->function <<= 8; ctx->function |= c; @@ -109,7 +112,7 @@ int ansiesc_process ( struct ansiesc_context *ctx, int c ) { ctx->count = 0; ctx->function <<= 8; ctx->function |= c; - ansiesc_call_handler ( ctx->handlers, ctx->function, + ansiesc_call_handler ( ctx, ctx->function, count, ctx->params ); } return -1; diff --git a/roms/ipxe/src/core/base16.c b/roms/ipxe/src/core/base16.c index 1f0e536c5..bf9cc21bb 100644 --- a/roms/ipxe/src/core/base16.c +++ b/roms/ipxe/src/core/base16.c @@ -51,16 +51,62 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) { char *encoded_bytes = encoded; size_t remaining = len; + /* Encode each byte */ for ( ; remaining-- ; encoded_bytes += 2 ) { sprintf ( encoded_bytes, "%02x", *(raw_bytes++) ); } + /* Ensure terminating NUL exists even if length was zero */ + *encoded_bytes = '\0'; + DBG ( "Base16-encoded to \"%s\":\n", encoded ); DBG_HDA ( 0, raw, len ); assert ( strlen ( encoded ) == base16_encoded_len ( len ) ); } /** + * Decode hexadecimal string + * + * @v encoded Encoded string + * @v separator Byte separator character, or 0 for no separator + * @v data Buffer + * @v len Length of buffer + * @ret len Length of data, or negative error + */ +int hex_decode ( const char *encoded, char separator, void *data, size_t len ) { + uint8_t *out = data; + unsigned int count = 0; + unsigned int sixteens; + unsigned int units; + + while ( *encoded ) { + + /* Check separator, if applicable */ + if ( count && separator && ( ( *(encoded++) != separator ) ) ) + return -EINVAL; + + /* Extract digits. Note that either digit may be NUL, + * which would be interpreted as an invalid value by + * strtoul_charval(); there is therefore no need for an + * explicit end-of-string check. + */ + sixteens = strtoul_charval ( *(encoded++) ); + if ( sixteens >= 16 ) + return -EINVAL; + units = strtoul_charval ( *(encoded++) ); + if ( units >= 16 ) + return -EINVAL; + + /* Store result */ + if ( count < len ) + out[count] = ( ( sixteens << 4 ) | units ); + count++; + + } + return count; +} + +/** * Base16-decode data * * @v encoded Encoded string @@ -75,33 +121,15 @@ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) { * to provide a buffer of the correct size. */ int base16_decode ( const char *encoded, uint8_t *raw ) { - const char *encoded_bytes = encoded; - uint8_t *raw_bytes = raw; - char buf[3]; - char *endp; - size_t len; - - while ( encoded_bytes[0] ) { - if ( ! encoded_bytes[1] ) { - DBG ( "Base16-encoded string \"%s\" has invalid " - "length\n", encoded ); - return -EINVAL; - } - memcpy ( buf, encoded_bytes, 2 ); - buf[2] = '\0'; - *(raw_bytes++) = strtoul ( buf, &endp, 16 ); - if ( *endp != '\0' ) { - DBG ( "Base16-encoded string \"%s\" has invalid " - "byte \"%s\"\n", encoded, buf ); - return -EINVAL; - } - encoded_bytes += 2; - } - len = ( raw_bytes - raw ); + int len; + + len = hex_decode ( encoded, 0, raw, -1UL ); + if ( len < 0 ) + return len; DBG ( "Base16-decoded \"%s\" to:\n", encoded ); DBG_HDA ( 0, raw, len ); - assert ( len <= base16_decoded_max_len ( encoded ) ); + assert ( len <= ( int ) base16_decoded_max_len ( encoded ) ); - return ( len ); + return len; } diff --git a/roms/ipxe/src/core/bitops.c b/roms/ipxe/src/core/bitops.c deleted file mode 100644 index 1bca9e47b..000000000 --- a/roms/ipxe/src/core/bitops.c +++ /dev/null @@ -1,13 +0,0 @@ -#include <strings.h> - -FILE_LICENCE ( GPL2_OR_LATER ); - -int __flsl ( long x ) { - unsigned long value = x; - int ls = 0; - - for ( ls = 0 ; value ; ls++ ) { - value >>= 1; - } - return ls; -} diff --git a/roms/ipxe/src/core/console.c b/roms/ipxe/src/core/console.c index a26a3ef63..141d8f0f0 100644 --- a/roms/ipxe/src/core/console.c +++ b/roms/ipxe/src/core/console.c @@ -10,16 +10,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Current console usage */ int console_usage = CONSOLE_USAGE_STDOUT; +/** Console width */ +unsigned int console_width = CONSOLE_DEFAULT_WIDTH; + +/** Console height */ +unsigned int console_height = CONSOLE_DEFAULT_HEIGHT; + /** - * Write a single character to each console device. + * Write a single character to each console device * * @v character Character to be written - * @ret None - - * @err None - * * The character is written out to all enabled console devices, using * each device's console_driver::putchar() method. - * */ void putchar ( int character ) { struct console_driver *console; @@ -29,7 +32,7 @@ void putchar ( int character ) { putchar ( '\r' ); for_each_table_entry ( console, CONSOLES ) { - if ( ( ! console->disabled ) && + if ( ( ! ( console->disabled & CONSOLE_DISABLED_OUTPUT ) ) && ( console_usage & console->usage ) && console->putchar ) console->putchar ( character ); @@ -37,23 +40,20 @@ void putchar ( int character ) { } /** - * Check to see if any input is available on any console. + * Check to see if any input is available on any console * - * @v None - - * @ret console Console device that has input available, if any. - * @ret NULL No console device has input available. - * @err None - + * @ret console Console device that has input available, or NULL * * All enabled console devices are checked once for available input * using each device's console_driver::iskey() method. The first * console device that has available input will be returned, if any. - * */ static struct console_driver * has_input ( void ) { struct console_driver *console; for_each_table_entry ( console, CONSOLES ) { - if ( ( ! console->disabled ) && console->iskey ) { + if ( ( ! ( console->disabled & CONSOLE_DISABLED_INPUT ) ) && + console->iskey ) { if ( console->iskey () ) return console; } @@ -62,11 +62,9 @@ static struct console_driver * has_input ( void ) { } /** - * Read a single character from any console. + * Read a single character from any console * - * @v None - * @ret character Character read from a console. - * @err None - * * A character will be read from the first enabled console device that * has input available using that console's console_driver::getchar() @@ -80,7 +78,6 @@ static struct console_driver * has_input ( void ) { * @endcode * * The character read will not be echoed back to any console. - * */ int getchar ( void ) { struct console_driver *console; @@ -116,20 +113,52 @@ int getchar ( void ) { return character; } -/** Check for available input on any console. +/** + * Check for available input on any console * - * @v None - - * @ret True Input is available on a console - * @ret False Input is not available on any console - * @err None - + * @ret is_available Input is available on a console * * All enabled console devices are checked once for available input * using each device's console_driver::iskey() method. If any console - * device has input available, this call will return True. If this - * call returns True, you can then safely call getchar() without + * device has input available, this call will return true. If this + * call returns true, you can then safely call getchar() without * blocking. - * */ int iskey ( void ) { return has_input() ? 1 : 0; } + +/** + * Configure console + * + * @v config Console configuration + * @ret rc Return status code + * + * The configuration is passed to all configurable consoles, including + * those which are currently disabled. Consoles may choose to enable + * or disable themselves depending upon the configuration. + * + * If configuration fails, then all consoles will be reset. + */ +int console_configure ( struct console_configuration *config ) { + struct console_driver *console; + int rc; + + /* Reset console width and height */ + console_set_size ( CONSOLE_DEFAULT_WIDTH, CONSOLE_DEFAULT_HEIGHT ); + + /* Try to configure each console */ + for_each_table_entry ( console, CONSOLES ) { + if ( ( console->configure ) && + ( ( rc = console->configure ( config ) ) != 0 ) ) + goto err; + } + + return 0; + + err: + /* Reset all consoles, avoiding a potential infinite loop */ + if ( config ) + console_reset(); + return rc; +} diff --git a/roms/ipxe/src/core/debug.c b/roms/ipxe/src/core/debug.c index 627d5d9a1..2161f9731 100644 --- a/roms/ipxe/src/core/debug.c +++ b/roms/ipxe/src/core/debug.c @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdio.h> #include <stdint.h> #include <stdarg.h> +#include <ctype.h> #include <ipxe/console.h> /** @@ -96,9 +97,7 @@ static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data, continue; } byte = bytes[i]; - if ( ( byte < 0x20 ) || ( byte >= 0x7f ) ) - byte = '.'; - dbg_printf ( "%c", byte ); + dbg_printf ( "%c", ( isprint ( byte ) ? byte : '.' ) ); } dbg_printf ( "\n" ); } diff --git a/roms/ipxe/src/core/downloader.c b/roms/ipxe/src/core/downloader.c index 4f3fc2c81..ec69db6b1 100644 --- a/roms/ipxe/src/core/downloader.c +++ b/roms/ipxe/src/core/downloader.c @@ -20,7 +20,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> -#include <stdarg.h> #include <errno.h> #include <syslog.h> #include <ipxe/iobuf.h> @@ -30,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/uaccess.h> #include <ipxe/umalloc.h> #include <ipxe/image.h> +#include <ipxe/profile.h> #include <ipxe/downloader.h> /** @file @@ -38,6 +38,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Receive profiler */ +static struct profiler downloader_rx_profiler __profiler = + { .name = "downloader.rx" }; + +/** Data copy profiler */ +static struct profiler downloader_copy_profiler __profiler = + { .name = "downloader.copy" }; + /** A downloader */ struct downloader { /** Reference count for this object */ @@ -131,9 +139,10 @@ static int downloader_ensure_size ( struct downloader *downloader, * * @v downloader Downloader * @v progress Progress report to fill in + * @ret ongoing_rc Ongoing job status code (if known) */ -static void downloader_progress ( struct downloader *downloader, - struct job_progress *progress ) { +static int downloader_progress ( struct downloader *downloader, + struct job_progress *progress ) { /* This is not entirely accurate, since downloaded data may * arrive out of order (e.g. with multicast protocols), but @@ -141,6 +150,8 @@ static void downloader_progress ( struct downloader *downloader, */ progress->completed = downloader->pos; progress->total = downloader->image->len; + + return 0; } /**************************************************************************** @@ -164,6 +175,9 @@ static int downloader_xfer_deliver ( struct downloader *downloader, size_t max; int rc; + /* Start profiling */ + profile_start ( &downloader_rx_profiler ); + /* Calculate new buffer position */ if ( meta->flags & XFER_FL_ABS_OFFSET ) downloader->pos = 0; @@ -176,8 +190,10 @@ static int downloader_xfer_deliver ( struct downloader *downloader, goto done; /* Copy data to buffer */ + profile_start ( &downloader_copy_profiler ); copy_to_user ( downloader->image->data, downloader->pos, iobuf->data, len ); + profile_stop ( &downloader_copy_profiler ); /* Update current buffer position */ downloader->pos += len; @@ -186,6 +202,7 @@ static int downloader_xfer_deliver ( struct downloader *downloader, free_iob ( iobuf ); if ( rc != 0 ) downloader_finished ( downloader, rc ); + profile_stop ( &downloader_rx_profiler ); return rc; } @@ -226,17 +243,13 @@ static struct interface_descriptor downloader_job_desc = * * @v job Job control interface * @v image Image to fill with downloaded file - * @v type Location type to pass to xfer_open() - * @v ... Remaining arguments to pass to xfer_open() * @ret rc Return status code * - * Instantiates a downloader object to download the specified URI into - * the specified image object. + * Instantiates a downloader object to download the content of the + * specified image from its URI. */ -int create_downloader ( struct interface *job, struct image *image, - int type, ... ) { +int create_downloader ( struct interface *job, struct image *image ) { struct downloader *downloader; - va_list args; int rc; /* Allocate and initialise structure */ @@ -249,21 +262,18 @@ int create_downloader ( struct interface *job, struct image *image, intf_init ( &downloader->xfer, &downloader_xfer_desc, &downloader->refcnt ); downloader->image = image_get ( image ); - va_start ( args, type ); /* Instantiate child objects and attach to our interfaces */ - if ( ( rc = xfer_vopen ( &downloader->xfer, type, args ) ) != 0 ) + if ( ( rc = xfer_open_uri ( &downloader->xfer, image->uri ) ) != 0 ) goto err; /* Attach parent interface, mortalise self, and return */ intf_plug_plug ( &downloader->job, job ); ref_put ( &downloader->refcnt ); - va_end ( args ); return 0; err: downloader_finished ( downloader, rc ); ref_put ( &downloader->refcnt ); - va_end ( args ); return rc; } diff --git a/roms/ipxe/src/core/errno.c b/roms/ipxe/src/core/errno.c index b4f44cecf..06905561f 100644 --- a/roms/ipxe/src/core/errno.c +++ b/roms/ipxe/src/core/errno.c @@ -1,5 +1,7 @@ #include <errno.h> +FILE_LICENCE ( GPL2_OR_LATER ); + /** @file * * Error codes diff --git a/roms/ipxe/src/core/exec.c b/roms/ipxe/src/core/exec.c index 843a51db7..1c85705ae 100644 --- a/roms/ipxe/src/core/exec.c +++ b/roms/ipxe/src/core/exec.c @@ -397,7 +397,7 @@ static struct option_descriptor echo_opts[] = { /** "echo" command descriptor */ static struct command_descriptor echo_cmd = COMMAND_DESC ( struct echo_options, echo_opts, 0, MAX_ARGUMENTS, - "[-n] [...]" ); + "[...]" ); /** * "echo" command diff --git a/roms/ipxe/src/core/fbcon.c b/roms/ipxe/src/core/fbcon.c new file mode 100644 index 000000000..72d6a6789 --- /dev/null +++ b/roms/ipxe/src/core/fbcon.c @@ -0,0 +1,692 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Frame buffer console + * + */ + +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <byteswap.h> +#include <ipxe/ansiesc.h> +#include <ipxe/image.h> +#include <ipxe/pixbuf.h> +#include <ipxe/umalloc.h> +#include <ipxe/console.h> +#include <ipxe/fbcon.h> + +/** + * Calculate raw colour value + * + * @v fbcon Frame buffer console + * @v rgb 24-bit RGB value + * @ret raw Raw colour + */ +static uint32_t fbcon_colour ( struct fbcon *fbcon, uint32_t rgb ) { + struct fbcon_colour_map *map = fbcon->map; + uint8_t red = ( rgb >> 16 ); + uint8_t green = ( rgb >> 8 ); + uint8_t blue = ( rgb >> 0 ); + uint32_t mapped; + + mapped = ( ( ( red >> map->red_scale ) << map->red_lsb ) | + ( ( green >> map->green_scale ) << map->green_lsb ) | + ( ( blue >> map->blue_scale ) << map->blue_lsb ) ); + return cpu_to_le32 ( mapped ); +} + +/** + * Calculate ANSI font colour + * + * @v fbcon Frame buffer console + * @v ansicol ANSI colour value (0-based) + * @ret colour Raw colour + */ +static uint32_t fbcon_ansi_colour ( struct fbcon *fbcon, + unsigned int ansicol ) { + uint32_t rgb; + + /* Treat ansicol as 3-bit BGR with intensity 0xaa */ + rgb = ( ( ( ansicol & ( 1 << 0 ) ) ? 0xaa0000 : 0 ) | + ( ( ansicol & ( 1 << 1 ) ) ? 0x00aa00 : 0 ) | + ( ( ansicol & ( 1 << 2 ) ) ? 0x0000aa : 0 ) ); + + return fbcon_colour ( fbcon, rgb ); +} + +/** + * Set default foreground colour + * + * @v fbcon Frame buffer console + */ +static void fbcon_set_default_foreground ( struct fbcon *fbcon ) { + + /* Default to non-bold white foreground */ + fbcon->foreground = fbcon_ansi_colour ( fbcon, 0x7 ); + fbcon->bold = 0; +} + +/** + * Set default background colour + * + * @v fbcon Frame buffer console + */ +static void fbcon_set_default_background ( struct fbcon *fbcon ) { + + /* Default to transparent background */ + fbcon->background = FBCON_TRANSPARENT; +} + +/** + * Clear rows of characters + * + * @v fbcon Frame buffer console + * @v ypos Starting Y position + */ +static void fbcon_clear ( struct fbcon *fbcon, unsigned int ypos ) { + struct fbcon_text_cell cell = { + .foreground = fbcon->foreground, + .background = fbcon->background, + .character = ' ', + }; + size_t offset; + unsigned int xpos; + + /* Clear stored character array */ + for ( ; ypos < fbcon->character.height ; ypos++ ) { + offset = ( ypos * fbcon->character.width * sizeof ( cell ) ); + for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) { + copy_to_user ( fbcon->text.start, offset, &cell, + sizeof ( cell ) ); + offset += sizeof ( cell ); + } + } +} + +/** + * Store character at specified position + * + * @v fbcon Frame buffer console + * @v cell Text cell + * @v xpos X position + * @v ypos Y position + */ +static void fbcon_store ( struct fbcon *fbcon, struct fbcon_text_cell *cell, + unsigned int xpos, unsigned int ypos ) { + size_t offset; + + /* Store cell */ + offset = ( ( ( ypos * fbcon->character.width ) + xpos ) * + sizeof ( *cell ) ); + copy_to_user ( fbcon->text.start, offset, cell, sizeof ( *cell ) ); +} + +/** + * Draw character at specified position + * + * @v fbcon Frame buffer console + * @v cell Text cell + * @v xpos X position + * @v ypos Y position + */ +static void fbcon_draw ( struct fbcon *fbcon, struct fbcon_text_cell *cell, + unsigned int xpos, unsigned int ypos ) { + struct fbcon_font_glyph glyph; + size_t offset; + size_t pixel_len; + size_t skip_len; + unsigned int row; + unsigned int column; + uint8_t bitmask; + int transparent; + void *src; + + /* Get font character */ + copy_from_user ( &glyph, fbcon->font->start, + ( cell->character * sizeof ( glyph ) ), + sizeof ( glyph ) ); + + /* Calculate pixel geometry */ + offset = ( fbcon->indent + + ( ypos * fbcon->character.stride ) + + ( xpos * fbcon->character.len ) ); + pixel_len = fbcon->pixel->len; + skip_len = ( fbcon->pixel->stride - fbcon->character.len ); + + /* Check for transparent background colour */ + transparent = ( cell->background == FBCON_TRANSPARENT ); + + /* Draw character rows */ + for ( row = 0 ; row < FBCON_CHAR_HEIGHT ; row++ ) { + + /* Draw background picture, if applicable */ + if ( transparent ) { + if ( fbcon->picture.start ) { + memcpy_user ( fbcon->start, offset, + fbcon->picture.start, offset, + fbcon->character.len ); + } else { + memset_user ( fbcon->start, offset, 0, + fbcon->character.len ); + } + } + + /* Draw character row */ + for ( column = FBCON_CHAR_WIDTH, bitmask = glyph.bitmask[row] ; + column ; column--, bitmask <<= 1, offset += pixel_len ) { + if ( bitmask & 0x80 ) { + src = &cell->foreground; + } else if ( ! transparent ) { + src = &cell->background; + } else { + continue; + } + copy_to_user ( fbcon->start, offset, src, pixel_len ); + } + + /* Move to next row */ + offset += skip_len; + } +} + +/** + * Redraw all characters + * + * @v fbcon Frame buffer console + */ +static void fbcon_redraw ( struct fbcon *fbcon ) { + struct fbcon_text_cell cell; + size_t offset = 0; + unsigned int xpos; + unsigned int ypos; + + /* Redraw characters */ + for ( ypos = 0 ; ypos < fbcon->character.height ; ypos++ ) { + for ( xpos = 0 ; xpos < fbcon->character.width ; xpos++ ) { + copy_from_user ( &cell, fbcon->text.start, offset, + sizeof ( cell ) ); + fbcon_draw ( fbcon, &cell, xpos, ypos ); + offset += sizeof ( cell ); + } + } +} + +/** + * Scroll screen + * + * @v fbcon Frame buffer console + */ +static void fbcon_scroll ( struct fbcon *fbcon ) { + size_t row_len; + + /* Sanity check */ + assert ( fbcon->ypos == fbcon->character.height ); + + /* Scroll up character array */ + row_len = ( fbcon->character.width * sizeof ( struct fbcon_text_cell )); + memmove_user ( fbcon->text.start, 0, fbcon->text.start, row_len, + ( row_len * ( fbcon->character.height - 1 ) ) ); + fbcon_clear ( fbcon, ( fbcon->character.height - 1 ) ); + + /* Update cursor position */ + fbcon->ypos--; + + /* Redraw all characters */ + fbcon_redraw ( fbcon ); +} + +/** + * Draw character at cursor position + * + * @v fbcon Frame buffer console + * @v show_cursor Show cursor + */ +static void fbcon_draw_cursor ( struct fbcon *fbcon, int show_cursor ) { + struct fbcon_text_cell cell; + size_t offset; + + offset = ( ( ( fbcon->ypos * fbcon->character.width ) + fbcon->xpos ) * + sizeof ( cell ) ); + copy_from_user ( &cell, fbcon->text.start, offset, sizeof ( cell ) ); + if ( show_cursor ) { + cell.background = fbcon->foreground; + cell.foreground = ( ( fbcon->background == FBCON_TRANSPARENT ) ? + 0 : fbcon->background ); + } + fbcon_draw ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); +} + +/** + * Handle ANSI CUP (cursor position) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params[0] Row (1 is top) + * @v params[1] Column (1 is left) + */ +static void fbcon_handle_cup ( struct ansiesc_context *ctx, + unsigned int count __unused, int params[] ) { + struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx ); + int cx = ( params[1] - 1 ); + int cy = ( params[0] - 1 ); + + fbcon_draw_cursor ( fbcon, 0 ); + fbcon->xpos = cx; + if ( fbcon->xpos >= fbcon->character.width ) + fbcon->xpos = 0; + fbcon->ypos = cy; + if ( fbcon->ypos >= fbcon->character.height ) + fbcon->ypos = 0; + fbcon_draw_cursor ( fbcon, fbcon->show_cursor ); +} + +/** + * Handle ANSI ED (erase in page) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params[0] Region to erase + */ +static void fbcon_handle_ed ( struct ansiesc_context *ctx, + unsigned int count __unused, + int params[] __unused ) { + struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx ); + + /* We assume that we always clear the whole screen */ + assert ( params[0] == ANSIESC_ED_ALL ); + + /* Clear character array */ + fbcon_clear ( fbcon, 0 ); + + /* Redraw all characters */ + fbcon_redraw ( fbcon ); + + /* Reset cursor position */ + fbcon->xpos = 0; + fbcon->ypos = 0; + fbcon_draw_cursor ( fbcon, fbcon->show_cursor ); +} + +/** + * Handle ANSI SGR (set graphics rendition) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void fbcon_handle_sgr ( struct ansiesc_context *ctx, unsigned int count, + int params[] ) { + struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx ); + uint32_t *custom = NULL; + uint32_t rgb; + unsigned int end; + unsigned int i; + int aspect; + + for ( i = 0 ; i < count ; i++ ) { + + /* Process aspect */ + aspect = params[i]; + if ( aspect == 0 ) { + fbcon_set_default_foreground ( fbcon ); + fbcon_set_default_background ( fbcon ); + } else if ( aspect == 1 ) { + fbcon->bold = fbcon_colour ( fbcon, FBCON_BOLD ); + } else if ( aspect == 22 ) { + fbcon->bold = 0; + } else if ( ( aspect >= 30 ) && ( aspect <= 37 ) ) { + fbcon->foreground = + fbcon_ansi_colour ( fbcon, aspect - 30 ); + } else if ( aspect == 38 ) { + custom = &fbcon->foreground; + } else if ( aspect == 39 ) { + fbcon_set_default_foreground ( fbcon ); + } else if ( ( aspect >= 40 ) && ( aspect <= 47 ) ) { + fbcon->background = + fbcon_ansi_colour ( fbcon, aspect - 40 ); + } else if ( aspect == 48 ) { + custom = &fbcon->background; + } else if ( aspect == 49 ) { + fbcon_set_default_background ( fbcon ); + } + + /* Process custom RGB colour, if applicable + * + * We support the xterm-compatible + * "<ESC>[38;2;<red>;<green>;<blue>m" and + * "<ESC>[48;2;<red>;<green>;<blue>m" sequences. + */ + if ( custom ) { + rgb = 0; + end = ( i + 5 ); + for ( ; ( i < count ) && ( i < end ) ; i++ ) + rgb = ( ( rgb << 8 ) | params[i] ); + *custom = fbcon_colour ( fbcon, rgb ); + custom = NULL; + } + } +} + +/** + * Handle ANSI DECTCEM set (show cursor) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void fbcon_handle_dectcem_set ( struct ansiesc_context *ctx, + unsigned int count __unused, + int params[] __unused ) { + struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx ); + + fbcon->show_cursor = 1; + fbcon_draw_cursor ( fbcon, 1 ); +} + +/** + * Handle ANSI DECTCEM reset (hide cursor) + * + * @v ctx ANSI escape sequence context + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void fbcon_handle_dectcem_reset ( struct ansiesc_context *ctx, + unsigned int count __unused, + int params[] __unused ) { + struct fbcon *fbcon = container_of ( ctx, struct fbcon, ctx ); + + fbcon->show_cursor = 0; + fbcon_draw_cursor ( fbcon, 0 ); +} + +/** ANSI escape sequence handlers */ +static struct ansiesc_handler fbcon_ansiesc_handlers[] = { + { ANSIESC_CUP, fbcon_handle_cup }, + { ANSIESC_ED, fbcon_handle_ed }, + { ANSIESC_SGR, fbcon_handle_sgr }, + { ANSIESC_DECTCEM_SET, fbcon_handle_dectcem_set }, + { ANSIESC_DECTCEM_RESET, fbcon_handle_dectcem_reset }, + { 0, NULL } +}; + +/** + * Print a character to current cursor position + * + * @v fbcon Frame buffer console + * @v character Character + */ +void fbcon_putchar ( struct fbcon *fbcon, int character ) { + struct fbcon_text_cell cell; + + /* Intercept ANSI escape sequences */ + character = ansiesc_process ( &fbcon->ctx, character ); + if ( character < 0 ) + return; + + /* Handle control characters */ + switch ( character ) { + case '\r': + fbcon_draw_cursor ( fbcon, 0 ); + fbcon->xpos = 0; + break; + case '\n': + fbcon_draw_cursor ( fbcon, 0 ); + fbcon->xpos = 0; + fbcon->ypos++; + break; + case '\b': + fbcon_draw_cursor ( fbcon, 0 ); + if ( fbcon->xpos ) { + fbcon->xpos--; + } else if ( fbcon->ypos ) { + fbcon->xpos = ( fbcon->character.width - 1 ); + fbcon->ypos--; + } + break; + default: + /* Print character at current cursor position */ + cell.foreground = ( fbcon->foreground | fbcon->bold ); + cell.background = fbcon->background; + cell.character = character; + fbcon_store ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); + fbcon_draw ( fbcon, &cell, fbcon->xpos, fbcon->ypos ); + + /* Advance cursor */ + fbcon->xpos++; + if ( fbcon->xpos >= fbcon->character.width ) { + fbcon->xpos = 0; + fbcon->ypos++; + } + break; + } + + /* Scroll screen if necessary */ + if ( fbcon->ypos >= fbcon->character.height ) + fbcon_scroll ( fbcon ); + + /* Show cursor */ + fbcon_draw_cursor ( fbcon, fbcon->show_cursor ); +} + +/** + * Initialise background picture + * + * @v fbcon Frame buffer console + * @v pixbuf Background picture + * @ret rc Return status code + */ +static int fbcon_picture_init ( struct fbcon *fbcon, + struct pixel_buffer *pixbuf ) { + struct fbcon_geometry *pixel = fbcon->pixel; + struct fbcon_picture *picture = &fbcon->picture; + size_t len; + size_t pixbuf_stride; + size_t indent; + size_t pixbuf_indent; + size_t offset; + size_t pixbuf_offset; + uint32_t rgb; + uint32_t raw; + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + int xgap; + int ygap; + int rc; + + /* Allocate buffer */ + len = ( pixel->height * pixel->stride ); + picture->start = umalloc ( len ); + if ( ! picture->start ) { + DBGC ( fbcon, "FBCON %p could not allocate %zd bytes for " + "picture\n", fbcon, len ); + rc = -ENOMEM; + goto err_umalloc; + } + + /* Centre picture on console */ + pixbuf_stride = ( pixbuf->width * sizeof ( rgb ) ); + xgap = ( ( ( int ) ( pixel->width - pixbuf->width ) ) / 2 ); + ygap = ( ( ( int ) ( pixel->height - pixbuf->height ) ) / 2 ); + indent = ( ( ( ( ygap >= 0 ) ? ygap : 0 ) * pixel->stride ) + + ( ( ( xgap >= 0 ) ? xgap : 0 ) * pixel->len ) ); + pixbuf_indent = ( ( ( ( ygap < 0 ) ? -ygap : 0 ) * pixbuf_stride ) + + ( ( ( xgap < 0 ) ? -xgap : 0 ) * sizeof ( rgb ) ) ); + width = pixbuf->width; + if ( width > pixel->width ) + width = pixel->width; + height = pixbuf->height; + if ( height > pixel->height ) + height = pixel->height; + DBGC ( fbcon, "FBCON %p picture is pixel %dx%d at [%d,%d),[%d,%d)\n", + fbcon, width, height, xgap, ( xgap + pixbuf->width ), ygap, + ( ygap + pixbuf->height ) ); + + /* Convert to frame buffer raw format */ + memset_user ( picture->start, 0, 0, len ); + for ( y = 0 ; y < height ; y++ ) { + offset = ( indent + ( y * pixel->stride ) ); + pixbuf_offset = ( pixbuf_indent + ( y * pixbuf_stride ) ); + for ( x = 0 ; x < width ; x++ ) { + copy_from_user ( &rgb, pixbuf->data, pixbuf_offset, + sizeof ( rgb ) ); + raw = fbcon_colour ( fbcon, rgb ); + copy_to_user ( picture->start, offset, &raw, + pixel->len ); + offset += pixel->len; + pixbuf_offset += sizeof ( rgb ); + } + } + + return 0; + + ufree ( picture->start ); + err_umalloc: + return rc; +} + +/** + * Initialise frame buffer console + * + * @v fbcon Frame buffer console + * @v start Start address + * @v pixel Pixel geometry + * @v margin Minimum margin + * @v map Colour mapping + * @v font Font definition + * @v pixbuf Background picture (if any) + * @ret rc Return status code + */ +int fbcon_init ( struct fbcon *fbcon, userptr_t start, + struct fbcon_geometry *pixel, + struct fbcon_margin *margin, + struct fbcon_colour_map *map, + struct fbcon_font *font, + struct pixel_buffer *pixbuf ) { + int width; + int height; + unsigned int xgap; + unsigned int ygap; + int rc; + + /* Initialise data structure */ + memset ( fbcon, 0, sizeof ( *fbcon ) ); + fbcon->start = start; + fbcon->pixel = pixel; + assert ( pixel->len <= sizeof ( uint32_t ) ); + fbcon->map = map; + fbcon->font = font; + fbcon->ctx.handlers = fbcon_ansiesc_handlers; + fbcon->show_cursor = 1; + + /* Derive overall length */ + fbcon->len = ( pixel->height * pixel->stride ); + DBGC ( fbcon, "FBCON %p at [%08lx,%08lx)\n", fbcon, + user_to_phys ( fbcon->start, 0 ), + user_to_phys ( fbcon->start, fbcon->len ) ); + + /* Expand margin to accommodate whole characters */ + width = ( pixel->width - margin->left - margin->right ); + height = ( pixel->height - margin->top - margin->bottom ); + if ( ( width < FBCON_CHAR_WIDTH ) || ( height < FBCON_CHAR_HEIGHT ) ) { + DBGC ( fbcon, "FBCON %p has unusable character area " + "[%d-%d),[%d-%d)\n", fbcon, + margin->left, ( pixel->width - margin->right ), + margin->top, ( pixel->height - margin->bottom ) ); + rc = -EINVAL; + goto err_margin; + } + xgap = ( width % FBCON_CHAR_WIDTH ); + ygap = ( height % FBCON_CHAR_HEIGHT ); + fbcon->margin.left = ( margin->left + ( xgap / 2 ) ); + fbcon->margin.top = ( margin->top + ( ygap / 2 ) ); + fbcon->margin.right = ( margin->right + ( xgap - ( xgap / 2 ) ) ); + fbcon->margin.bottom = ( margin->bottom + ( ygap - ( ygap / 2 ) ) ); + fbcon->indent = ( ( fbcon->margin.top * pixel->stride ) + + ( fbcon->margin.left * pixel->len ) ); + + /* Derive character geometry from pixel geometry */ + fbcon->character.width = ( width / FBCON_CHAR_WIDTH ); + fbcon->character.height = ( height / FBCON_CHAR_HEIGHT ); + fbcon->character.len = ( pixel->len * FBCON_CHAR_WIDTH ); + fbcon->character.stride = ( pixel->stride * FBCON_CHAR_HEIGHT ); + DBGC ( fbcon, "FBCON %p is pixel %dx%d, char %dx%d at " + "[%d-%d),[%d-%d)\n", fbcon, fbcon->pixel->width, + fbcon->pixel->height, fbcon->character.width, + fbcon->character.height, fbcon->margin.left, + ( fbcon->pixel->width - fbcon->margin.right ), + fbcon->margin.top, + ( fbcon->pixel->height - fbcon->margin.bottom ) ); + + /* Set default colours */ + fbcon_set_default_foreground ( fbcon ); + fbcon_set_default_background ( fbcon ); + + /* Allocate and initialise stored character array */ + fbcon->text.start = umalloc ( fbcon->character.width * + fbcon->character.height * + sizeof ( struct fbcon_text_cell ) ); + if ( ! fbcon->text.start ) { + rc = -ENOMEM; + goto err_text; + } + fbcon_clear ( fbcon, 0 ); + + /* Set framebuffer to all black (including margins) */ + memset_user ( fbcon->start, 0, 0, fbcon->len ); + + /* Generate pixel buffer from background image, if applicable */ + if ( pixbuf && ( ( rc = fbcon_picture_init ( fbcon, pixbuf ) ) != 0 ) ) + goto err_picture; + + /* Draw background picture (including margins), if applicable */ + if ( fbcon->picture.start ) { + memcpy_user ( fbcon->start, 0, fbcon->picture.start, 0, + fbcon->len ); + } + + /* Update console width and height */ + console_set_size ( fbcon->character.width, fbcon->character.height ); + + return 0; + + ufree ( fbcon->picture.start ); + err_picture: + ufree ( fbcon->text.start ); + err_text: + err_margin: + return rc; +} + +/** + * Finalise frame buffer console + * + * @v fbcon Frame buffer console + */ +void fbcon_fini ( struct fbcon *fbcon ) { + + ufree ( fbcon->text.start ); + ufree ( fbcon->picture.start ); +} diff --git a/roms/ipxe/src/core/gdbstub.c b/roms/ipxe/src/core/gdbstub.c index cbe328f9f..af06118b2 100644 --- a/roms/ipxe/src/core/gdbstub.c +++ b/roms/ipxe/src/core/gdbstub.c @@ -396,5 +396,6 @@ struct gdb_transport *find_gdb_transport ( const char *name ) { void gdbstub_start ( struct gdb_transport *trans ) { stub.trans = trans; stub.payload = &stub.buf [ 1 ]; + gdbmach_init(); gdbmach_breakpoint(); } diff --git a/roms/ipxe/src/core/image.c b/roms/ipxe/src/core/image.c index 4101ff3b5..ec4480238 100644 --- a/roms/ipxe/src/core/image.c +++ b/roms/ipxe/src/core/image.c @@ -409,6 +409,8 @@ int image_select ( struct image *image ) { /* Check that this image can be executed */ if ( ( rc = image_probe ( image ) ) != 0 ) return rc; + if ( ! image->type->exec ) + return -ENOEXEC; /* Mark image as selected */ image->flags |= IMAGE_SELECTED; @@ -454,3 +456,29 @@ int image_set_trust ( int require_trusted, int permanent ) { return 0; } + +/** + * Create pixel buffer from image + * + * @v image Image + * @v pixbuf Pixel buffer to fill in + * @ret rc Return status code + */ +int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) { + int rc; + + /* Check that this image can be used to create a pixel buffer */ + if ( ( rc = image_probe ( image ) ) != 0 ) + return rc; + if ( ! image->type->pixbuf ) + return -ENOTSUP; + + /* Try creating pixel buffer */ + if ( ( rc = image->type->pixbuf ( image, pixbuf ) ) != 0 ) { + DBGC ( image, "IMAGE %s could not create pixel buffer: %s\n", + image->name, strerror ( rc ) ); + return rc; + } + + return 0; +} diff --git a/roms/ipxe/src/core/init.c b/roms/ipxe/src/core/init.c index 562744194..7ea0730fa 100644 --- a/roms/ipxe/src/core/init.c +++ b/roms/ipxe/src/core/init.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/device.h> +#include <ipxe/console.h> #include <ipxe/init.h> /** @file @@ -95,5 +96,8 @@ void shutdown ( int flags ) { startup_fn->shutdown ( flags ); } + /* Reset console */ + console_reset(); + started = 0; } diff --git a/roms/ipxe/src/core/interface.c b/roms/ipxe/src/core/interface.c index 97caac804..62f4621db 100644 --- a/roms/ipxe/src/core/interface.c +++ b/roms/ipxe/src/core/interface.c @@ -34,8 +34,24 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** + * Close null interface + * + * @v intf Null interface + * @v rc Reason for close + */ +static void null_intf_close ( struct interface *intf __unused, + int rc __unused ) { + + /* Do nothing. In particular, do not call intf_restart(), + * since that would result in an infinite loop. + */ +} + /** Null interface operations */ -static struct interface_operation null_intf_op[] = {}; +static struct interface_operation null_intf_op[] = { + INTF_OP ( intf_close, struct interface *, null_intf_close ), +}; /** Null interface descriptor */ struct interface_descriptor null_intf_desc = @@ -233,7 +249,8 @@ void intf_close ( struct interface *intf, int rc ) { if ( op ) { op ( object, rc ); } else { - /* Default is to ignore intf_close() */ + /* Default is to restart the interface */ + intf_restart ( dest, rc ); } intf_put ( dest ); diff --git a/roms/ipxe/src/core/isqrt.c b/roms/ipxe/src/core/isqrt.c new file mode 100644 index 000000000..35c918d19 --- /dev/null +++ b/roms/ipxe/src/core/isqrt.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Integer square root + * + */ + +#include <ipxe/isqrt.h> + +/** + * Find integer square root + * + * @v value Value + * @v isqrt Integer square root of value + */ +unsigned long isqrt ( unsigned long value ) { + unsigned long result = 0; + unsigned long bit = ( 1UL << ( ( 8 * sizeof ( bit ) ) - 2 ) ); + + while ( bit > value ) + bit >>= 2; + while ( bit ) { + if ( value >= ( result + bit ) ) { + value -= ( result + bit ); + result = ( ( result >> 1 ) + bit ); + } else { + result >>= 1; + } + bit >>= 2; + } + return result; +} diff --git a/roms/ipxe/src/core/job.c b/roms/ipxe/src/core/job.c index 64d184ec3..674bec8b5 100644 --- a/roms/ipxe/src/core/job.c +++ b/roms/ipxe/src/core/job.c @@ -34,22 +34,30 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * @v intf Object interface * @v progress Progress data to fill in + * @ret ongoing_rc Ongoing job status code (if known) */ -void job_progress ( struct interface *intf, struct job_progress *progress ) { +int job_progress ( struct interface *intf, struct job_progress *progress ) { struct interface *dest; job_progress_TYPE ( void * ) *op = intf_get_dest_op ( intf, job_progress, &dest ); void *object = intf_object ( dest ); + int ongoing_rc; DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " job_progress\n", INTF_INTF_DBG ( intf, dest ) ); + /* Initialise progress to zero */ + memset ( progress, 0, sizeof ( *progress ) ); + if ( op ) { - op ( object, progress ); + ongoing_rc = op ( object, progress ); } else { - /* Default is to mark progress as zero */ - memset ( progress, 0, sizeof ( *progress ) ); + /* Default is to leave progress as zero and have no + * known return status code. + */ + ongoing_rc = 0; } intf_put ( dest ); + return ongoing_rc; } diff --git a/roms/ipxe/src/core/main.c b/roms/ipxe/src/core/main.c index 7b7755c94..c55ca26cb 100644 --- a/roms/ipxe/src/core/main.c +++ b/roms/ipxe/src/core/main.c @@ -14,106 +14,28 @@ Literature dealing with the network protocols: FILE_LICENCE ( GPL2_OR_LATER ); +#include <stddef.h> #include <stdio.h> -#include <stdlib.h> #include <ipxe/init.h> -#include <ipxe/features.h> -#include <ipxe/shell.h> -#include <ipxe/image.h> -#include <ipxe/keys.h> -#include <ipxe/version.h> -#include <usr/prompt.h> #include <usr/autoboot.h> #include <config/general.h> -#define NORMAL "\033[0m" -#define BOLD "\033[1m" -#define CYAN "\033[36m" - -/** The "scriptlet" setting */ -struct setting scriptlet_setting __setting ( SETTING_MISC ) = { - .name = "scriptlet", - .description = "Boot scriptlet", - .tag = DHCP_EB_SCRIPTLET, - .type = &setting_type_string, -}; - -/** - * Prompt for shell entry - * - * @ret enter_shell User wants to enter shell - */ -static int shell_banner ( void ) { - - /* Skip prompt if timeout is zero */ - if ( BANNER_TIMEOUT <= 0 ) - return 0; - - /* Prompt user */ - printf ( "\n" ); - return ( prompt ( "Press Ctrl-B for the iPXE command line...", - ( BANNER_TIMEOUT * 100 ), CTRL_B ) == 0 ); -} - /** * Main entry point * * @ret rc Return status code */ __asmcall int main ( void ) { - struct feature *feature; - struct image *image; - char *scriptlet; + + /* Perform one-time-only initialisation (e.g. heap) */ + initialise(); /* Some devices take an unreasonably long time to initialise */ printf ( PRODUCT_SHORT_NAME " initialising devices..." ); - initialise(); startup(); printf ( "ok\n" ); - /* - * Print welcome banner - * - * - * If you wish to brand this build of iPXE, please do so by - * defining the string PRODUCT_NAME in config/general.h. - * - * While nothing in the GPL prevents you from removing all - * references to iPXE or http://ipxe.org, we prefer you not to - * do so. - * - */ - printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "iPXE %s" - NORMAL " -- Open Source Network Boot Firmware -- " - CYAN "http://ipxe.org" NORMAL "\n" - "Features:", product_version ); - for_each_table_entry ( feature, FEATURES ) - printf ( " %s", feature->name ); - printf ( "\n" ); - - /* Boot system */ - if ( ( image = first_image() ) != NULL ) { - /* We have an embedded image; execute it */ - image_exec ( image ); - } else if ( shell_banner() ) { - /* User wants shell; just give them a shell */ - shell(); - } else { - fetch_string_setting_copy ( NULL, &scriptlet_setting, - &scriptlet ); - if ( scriptlet ) { - /* User has defined a scriptlet; execute it */ - system ( scriptlet ); - free ( scriptlet ); - } else { - /* Try booting. If booting fails, offer the - * user another chance to enter the shell. - */ - autoboot(); - if ( shell_banner() ) - shell(); - } - } + ipxe ( NULL ); shutdown_exit(); diff --git a/roms/ipxe/src/core/memmap_settings.c b/roms/ipxe/src/core/memmap_settings.c new file mode 100644 index 000000000..0f6d0abf5 --- /dev/null +++ b/roms/ipxe/src/core/memmap_settings.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/init.h> +#include <ipxe/settings.h> +#include <ipxe/io.h> + +/** @file + * + * Memory map settings + * + * Memory map settings are numerically encoded as: + * + * Bits 31-24 Number of regions, minus one + * Bits 23-16 Starting region + * Bits 15-11 Unused + * Bit 10 Ignore non-existent regions (rather than generating an error) + * Bit 9 Include length + * Bit 8 Include start address + * Bits 7-6 Unused + * Bits 5-0 Scale factor (i.e. right shift count) + */ + +/** + * Construct memory map setting tag + * + * @v start Starting region + * @v count Number of regions + * @v include_start Include start address + * @v include_length Include length + * @v ignore Ignore non-existent regions + * @v scale Scale factor + * @ret tag Setting tag + */ +#define MEMMAP_TAG( start, count, include_start, include_length, \ + ignore, scale ) \ + ( ( (start) << 16 ) | ( ( (count) - 1 ) << 24 ) | \ + ( (ignore) << 10 ) | ( (include_length) << 9 ) | \ + ( (include_start) << 8 ) | (scale) ) + +/** + * Extract number of regions from setting tag + * + * @v tag Setting tag + * @ret count Number of regions + */ +#define MEMMAP_COUNT( tag ) ( ( ( (tag) >> 24 ) & 0xff ) + 1 ) + +/** + * Extract starting region from setting tag + * + * @v tag Setting tag + * @ret start Starting region + */ +#define MEMMAP_START( tag ) ( ( (tag) >> 16 ) & 0xff ) + +/** + * Extract ignore flag from setting tag + * + * @v tag Setting tag + * @ret ignore Ignore non-existent regions + */ +#define MEMMAP_IGNORE_NONEXISTENT( tag ) ( (tag) & 0x00000400UL ) + +/** + * Extract length inclusion flag from setting tag + * + * @v tag Setting tag + * @ret include_length Include length + */ +#define MEMMAP_INCLUDE_LENGTH( tag ) ( (tag) & 0x00000200UL ) + +/** + * Extract start address inclusion flag from setting tag + * + * @v tag Setting tag + * @ret include_start Include start address + */ +#define MEMMAP_INCLUDE_START( tag ) ( (tag) & 0x00000100UL ) + +/** + * Extract scale factor from setting tag + * + * @v tag Setting tag + * @v scale Scale factor + */ +#define MEMMAP_SCALE( tag ) ( (tag) & 0x3f ) + +/** Memory map settings scope */ +static const struct settings_scope memmap_settings_scope; + +/** + * Check applicability of memory map setting + * + * @v settings Settings block + * @v setting Setting + * @ret applies Setting applies within this settings block + */ +static int memmap_settings_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &memmap_settings_scope ); +} + +/** + * Fetch value of memory map setting + * + * @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 + */ +static int memmap_settings_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct memory_map memmap; + struct memory_region *region; + uint64_t result = 0; + unsigned int i; + unsigned int count; + + DBGC ( settings, "MEMMAP start %d count %d %s%s%s%s scale %d\n", + MEMMAP_START ( setting->tag ), MEMMAP_COUNT ( setting->tag ), + ( MEMMAP_INCLUDE_START ( setting->tag ) ? "start" : "" ), + ( ( MEMMAP_INCLUDE_START ( setting->tag ) && + MEMMAP_INCLUDE_LENGTH ( setting->tag ) ) ? "+" : "" ), + ( MEMMAP_INCLUDE_LENGTH ( setting->tag ) ? "length" : "" ), + ( MEMMAP_IGNORE_NONEXISTENT ( setting->tag ) ? " ignore" : "" ), + MEMMAP_SCALE ( setting->tag ) ); + + /* Fetch memory map */ + get_memmap ( &memmap ); + + /* Extract results from memory map */ + count = MEMMAP_COUNT ( setting->tag ); + for ( i = MEMMAP_START ( setting->tag ) ; count-- ; i++ ) { + + /* Check that region exists */ + if ( i >= memmap.count ) { + if ( MEMMAP_IGNORE_NONEXISTENT ( setting->tag ) ) { + continue; + } else { + DBGC ( settings, "MEMMAP region %d does not " + "exist\n", i ); + return -ENOENT; + } + } + + /* Extract results from this region */ + region = &memmap.regions[i]; + if ( MEMMAP_INCLUDE_START ( setting->tag ) ) { + result += region->start; + DBGC ( settings, "MEMMAP %d start %08llx\n", + i, region->start ); + } + if ( MEMMAP_INCLUDE_LENGTH ( setting->tag ) ) { + result += ( region->end - region->start ); + DBGC ( settings, "MEMMAP %d length %08llx\n", + i, ( region->end - region->start ) ); + } + } + + /* Scale result */ + result >>= MEMMAP_SCALE ( setting->tag ); + + /* Return result */ + result = cpu_to_be64 ( result ); + if ( len > sizeof ( result ) ) + len = sizeof ( result ); + memcpy ( data, &result, len ); + + /* Set type if not already specified */ + if ( ! setting->type ) + setting->type = &setting_type_hexraw; + + return sizeof ( result ); +} + +/** Memory map settings operations */ +static struct settings_operations memmap_settings_operations = { + .applies = memmap_settings_applies, + .fetch = memmap_settings_fetch, +}; + +/** Memory map settings */ +static struct settings memmap_settings = { + .refcnt = NULL, + .siblings = LIST_HEAD_INIT ( memmap_settings.siblings ), + .children = LIST_HEAD_INIT ( memmap_settings.children ), + .op = &memmap_settings_operations, + .default_scope = &memmap_settings_scope, +}; + +/** Initialise memory map settings */ +static void memmap_settings_init ( void ) { + int rc; + + if ( ( rc = register_settings ( &memmap_settings, NULL, + "memmap" ) ) != 0 ) { + DBG ( "MEMMAP could not register settings: %s\n", + strerror ( rc ) ); + return; + } +} + +/** Memory map settings initialiser */ +struct init_fn memmap_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = memmap_settings_init, +}; + +/** Memory map predefined settings */ +const struct setting memsize_setting __setting ( SETTING_MISC, memsize ) = { + .name = "memsize", + .description = "Memory size (in MB)", + .tag = MEMMAP_TAG ( 0, 0x100, 0, 1, 1, 20 ), + .type = &setting_type_int32, + .scope = &memmap_settings_scope, +}; diff --git a/roms/ipxe/src/core/misc.c b/roms/ipxe/src/core/misc.c index 11342481a..eaceddfea 100644 --- a/roms/ipxe/src/core/misc.c +++ b/roms/ipxe/src/core/misc.c @@ -33,6 +33,19 @@ int inet_aton ( const char *cp, struct in_addr *inp ) { return 0; } +unsigned int strtoul_charval ( unsigned int charval ) { + + if ( charval >= 'a' ) { + charval = ( charval - 'a' + 10 ); + } else if ( charval >= 'A' ) { + charval = ( charval - 'A' + 10 ); + } else if ( charval <= '9' ) { + charval = ( charval - '0' ); + } + + return charval; +} + unsigned long strtoul ( const char *p, char **endp, int base ) { unsigned long ret = 0; int negative = 0; diff --git a/roms/ipxe/src/core/monojob.c b/roms/ipxe/src/core/monojob.c index d262f70b2..820fa31dc 100644 --- a/roms/ipxe/src/core/monojob.c +++ b/roms/ipxe/src/core/monojob.c @@ -55,25 +55,29 @@ struct interface monojob = INTF_INIT ( monojob_intf_desc ); * Wait for single foreground job to complete * * @v string Job description to display, or NULL to be silent + * @v timeout Timeout period, in ticks (0=indefinite) * @ret rc Job final status code */ -int monojob_wait ( const char *string ) { +int monojob_wait ( const char *string, unsigned long timeout ) { struct job_progress progress; - int key; - int rc; unsigned long last_keycheck; unsigned long last_progress; + unsigned long last_display; unsigned long now; unsigned long elapsed; - unsigned long completed; - unsigned long total; + unsigned long completed = 0; + unsigned long scaled_completed; + unsigned long scaled_total; unsigned int percentage; int shown_percentage = 0; + int ongoing_rc; + int key; + int rc; if ( string ) printf ( "%s...", string ); monojob_rc = -EINPROGRESS; - last_keycheck = last_progress = currticks(); + last_keycheck = last_progress = last_display = currticks(); while ( monojob_rc == -EINPROGRESS ) { /* Allow job to progress */ @@ -83,41 +87,55 @@ int monojob_wait ( const char *string ) { /* Check for keypresses. This can be time-consuming, * so check only once per clock tick. */ - if ( now != last_keycheck ) { + elapsed = ( now - last_keycheck ); + if ( elapsed ) { if ( iskey() ) { key = getchar(); - switch ( key ) { - case CTRL_C: - monojob_close ( &monojob, -ECANCELED ); - break; - default: + if ( key == CTRL_C ) { + monojob_rc = -ECANCELED; break; } } last_keycheck = now; } - /* Display progress, if applicable */ + /* Monitor progress */ + ongoing_rc = job_progress ( &monojob, &progress ); + + /* Reset timeout if progress has been made */ + if ( completed != progress.completed ) + last_progress = now; + completed = progress.completed; + + /* Check for timeout, if applicable */ elapsed = ( now - last_progress ); + if ( timeout && ( elapsed >= timeout ) ) { + monojob_rc = ( ongoing_rc ? ongoing_rc : -ETIMEDOUT ); + break; + } + + /* Display progress, if applicable */ + elapsed = ( now - last_display ); if ( string && ( elapsed >= TICKS_PER_SEC ) ) { if ( shown_percentage ) printf ( "\b\b\b\b \b\b\b\b" ); - job_progress ( &monojob, &progress ); /* Normalise progress figures to avoid overflow */ - completed = ( progress.completed / 128 ); - total = ( progress.total / 128 ); - if ( total ) { - percentage = ( ( 100 * completed ) / total ); + scaled_completed = ( progress.completed / 128 ); + scaled_total = ( progress.total / 128 ); + if ( scaled_total ) { + percentage = ( ( 100 * scaled_completed ) / + scaled_total ); printf ( "%3d%%", percentage ); shown_percentage = 1; } else { printf ( "." ); shown_percentage = 0; } - last_progress = now; + last_display = now; } } rc = monojob_rc; + monojob_close ( &monojob, rc ); if ( shown_percentage ) printf ( "\b\b\b\b \b\b\b\b" ); diff --git a/roms/ipxe/src/core/null_reboot.c b/roms/ipxe/src/core/null_reboot.c new file mode 100644 index 000000000..a3d5b2ef8 --- /dev/null +++ b/roms/ipxe/src/core/null_reboot.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * Null reboot mechanism + * + */ + +#include <stdio.h> +#include <errno.h> +#include <ipxe/reboot.h> + +/** + * Reboot system + * + * @v warm Perform a warm reboot + */ +static void null_reboot ( int warm __unused ) { + + printf ( "Cannot reboot; not implemented\n" ); + while ( 1 ) {} +} + +/** + * Power off system + * + * @ret rc Return status code + */ +static int null_poweroff ( void ) { + + return -ENOTSUP; +} + +PROVIDE_REBOOT ( null, reboot, null_reboot ); +PROVIDE_REBOOT ( null, poweroff, null_poweroff ); diff --git a/roms/ipxe/src/core/nvo.c b/roms/ipxe/src/core/nvo.c index 5383fe5c3..e135d2b41 100644 --- a/roms/ipxe/src/core/nvo.c +++ b/roms/ipxe/src/core/nvo.c @@ -193,9 +193,10 @@ static int nvo_save ( struct nvo_block *nvo ) { * @ret applies Setting applies within this settings block */ int nvo_applies ( struct settings *settings __unused, - struct setting *setting ) { + const struct setting *setting ) { - return dhcpopt_applies ( setting->tag ); + return ( ( setting->scope == NULL ) && + dhcpopt_applies ( setting->tag ) ); } /** @@ -207,7 +208,7 @@ int nvo_applies ( struct settings *settings __unused, * @v len Length of setting data * @ret rc Return status code */ -static int nvo_store ( struct settings *settings, struct setting *setting, +static int nvo_store ( struct settings *settings, const struct setting *setting, const void *data, size_t len ) { struct nvo_block *nvo = container_of ( settings, struct nvo_block, settings ); @@ -274,7 +275,8 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs, nvo->len = len; nvo->resize = resize; dhcpopt_init ( &nvo->dhcpopts, NULL, 0, nvo_realloc_dhcpopt ); - settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, 0 ); + settings_init ( &nvo->settings, &nvo_settings_operations, + refcnt, NULL ); } /** diff --git a/roms/ipxe/src/core/params.c b/roms/ipxe/src/core/params.c new file mode 100644 index 000000000..93b834419 --- /dev/null +++ b/roms/ipxe/src/core/params.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Form parameters + * + */ + +#include <stdlib.h> +#include <string.h> +#include <ipxe/params.h> + +/** List of all parameter lists */ +static LIST_HEAD ( parameters ); + +/** + * Free form parameter list + * + * @v refcnt Reference count + */ +static void free_parameters ( struct refcnt *refcnt ) { + struct parameters *params = + container_of ( refcnt, struct parameters, refcnt ); + struct parameter *param; + struct parameter *tmp; + + DBGC ( params, "PARAMS \"%s\" destroyed\n", params->name ); + + /* Free all parameters */ + list_for_each_entry_safe ( param, tmp, ¶ms->entries, list ) { + list_del ( ¶m->list ); + free ( param ); + } + + /* Free parameter list */ + free ( params ); +} + +/** + * Find form parameter list by name + * + * @v name Parameter list name (may be NULL) + * @ret params Parameter list, or NULL if not found + */ +struct parameters * find_parameters ( const char *name ) { + struct parameters *params; + + list_for_each_entry ( params, ¶meters, list ) { + if ( ( params->name == name ) || + ( strcmp ( params->name, name ) == 0 ) ) { + return params; + } + } + return NULL; +} + +/** + * Create form parameter list + * + * @v name Parameter list name (may be NULL) + * @ret params Parameter list, or NULL on failure + */ +struct parameters * create_parameters ( const char *name ) { + struct parameters *params; + size_t name_len; + char *name_copy; + + /* Destroy any existing parameter list of this name */ + params = find_parameters ( name ); + if ( params ) { + claim_parameters ( params ); + params_put ( params ); + } + + /* Allocate parameter list */ + name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 ); + params = zalloc ( sizeof ( *params ) + name_len ); + if ( ! params ) + return NULL; + ref_init ( ¶ms->refcnt, free_parameters ); + name_copy = ( ( void * ) ( params + 1 ) ); + + /* Populate parameter list */ + if ( name ) { + strcpy ( name_copy, name ); + params->name = name_copy; + } + INIT_LIST_HEAD ( ¶ms->entries ); + + /* Add to list of parameter lists */ + list_add_tail ( ¶ms->list, ¶meters ); + + DBGC ( params, "PARAMS \"%s\" created\n", params->name ); + return params; +} + +/** + * Add form parameter + * + * @v params Parameter list + * @v key Parameter key + * @v value Parameter value + * @ret param Parameter, or NULL on failure + */ +struct parameter * add_parameter ( struct parameters *params, + const char *key, const char *value ) { + struct parameter *param; + size_t key_len; + size_t value_len; + char *key_copy; + char *value_copy; + + /* Allocate parameter */ + key_len = ( strlen ( key ) + 1 /* NUL */ ); + value_len = ( strlen ( value ) + 1 /* NUL */ ); + param = zalloc ( sizeof ( *param ) + key_len + value_len ); + if ( ! param ) + return NULL; + key_copy = ( ( void * ) ( param + 1 ) ); + value_copy = ( key_copy + key_len ); + + /* Populate parameter */ + strcpy ( key_copy, key ); + param->key = key_copy; + strcpy ( value_copy, value ); + param->value = value_copy; + + /* Add to list of parameters */ + list_add_tail ( ¶m->list, ¶ms->entries ); + + DBGC ( params, "PARAMS \"%s\" added \"%s\"=\"%s\"\n", + params->name, param->key, param->value ); + return param; +} diff --git a/roms/ipxe/src/core/parseopt.c b/roms/ipxe/src/core/parseopt.c index 659d20ee9..d268c0594 100644 --- a/roms/ipxe/src/core/parseopt.c +++ b/roms/ipxe/src/core/parseopt.c @@ -28,6 +28,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <getopt.h> #include <ipxe/netdevice.h> #include <ipxe/menu.h> +#include <ipxe/settings.h> +#include <ipxe/params.h> +#include <ipxe/timer.h> #include <ipxe/parseopt.h> /** @file @@ -59,7 +62,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret value String value * @ret rc Return status code */ -int parse_string ( const char *text, const char **value ) { +int parse_string ( char *text, char **value ) { /* Sanity check */ assert ( text != NULL ); @@ -77,7 +80,7 @@ int parse_string ( const char *text, const char **value ) { * @ret value Integer value * @ret rc Return status code */ -int parse_integer ( const char *text, unsigned int *value ) { +int parse_integer ( char *text, unsigned int *value ) { char *endp; /* Sanity check */ @@ -94,13 +97,34 @@ int parse_integer ( const char *text, unsigned int *value ) { } /** + * Parse timeout value (in ms) + * + * @v text Text + * @ret value Integer value + * @ret rc Return status code + */ +int parse_timeout ( char *text, unsigned long *value ) { + unsigned int value_ms; + int rc; + + /* Parse raw integer value */ + if ( ( rc = parse_integer ( text, &value_ms ) ) != 0 ) + return rc; + + /* Convert to a number of timer ticks */ + *value = ( ( value_ms * TICKS_PER_SEC ) / 1000 ); + + return 0; +} + +/** * Parse network device name * * @v text Text * @ret netdev Network device * @ret rc Return status code */ -int parse_netdev ( const char *text, struct net_device **netdev ) { +int parse_netdev ( char *text, struct net_device **netdev ) { /* Sanity check */ assert ( text != NULL ); @@ -116,13 +140,36 @@ int parse_netdev ( const char *text, struct net_device **netdev ) { } /** + * Parse network device configurator name + * + * @v text Text + * @ret configurator Network device configurator + * @ret rc Return status code + */ +int parse_netdev_configurator ( char *text, + struct net_device_configurator **configurator ){ + + /* Sanity check */ + assert ( text != NULL ); + + /* Find network device configurator */ + *configurator = find_netdev_configurator ( text ); + if ( ! *configurator ) { + printf ( "\"%s\": no such configurator\n", text ); + return -ENOTSUP; + } + + return 0; +} + +/** * Parse menu name * * @v text Text * @ret menu Menu * @ret rc Return status code */ -int parse_menu ( const char *text, struct menu **menu ) { +int parse_menu ( char *text, struct menu **menu ) { /* Find menu */ *menu = find_menu ( text ); @@ -145,7 +192,7 @@ int parse_menu ( const char *text, struct menu **menu ) { * @ret flag Flag to set * @ret rc Return status code */ -int parse_flag ( const char *text __unused, int *flag ) { +int parse_flag ( char *text __unused, int *flag ) { /* Set flag */ *flag = 1; @@ -160,7 +207,7 @@ int parse_flag ( const char *text __unused, int *flag ) { * @ret key Key * @ret rc Return status code */ -int parse_key ( const char *text, unsigned int *key ) { +int parse_key ( char *text, unsigned int *key ) { /* Interpret single characters as being a literal key character */ if ( text[0] && ! text[1] ) { @@ -173,14 +220,131 @@ int parse_key ( const char *text, unsigned int *key ) { } /** + * Parse settings block name + * + * @v text Text + * @ret value Integer value + * @ret rc Return status code + */ +int parse_settings ( char *text, struct settings **value ) { + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse scope name */ + *value = find_settings ( text ); + if ( ! *value ) { + printf ( "\"%s\": no such scope\n", text ); + return -EINVAL; + } + + return 0; +} + +/** + * Parse setting name + * + * @v text Text + * @v setting Named setting to fill in + * @v get_child Function to find or create child settings block + * @ret rc Return status code + * + * Note that this function modifies the original @c text. + */ +int parse_setting ( char *text, struct named_setting *setting, + get_child_settings_t get_child ) { + int rc; + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse setting name */ + if ( ( rc = parse_setting_name ( text, get_child, &setting->settings, + &setting->setting ) ) != 0 ) { + printf ( "\"%s\": invalid setting\n", text ); + return rc; + } + + return 0; +} + +/** + * Parse existing setting name + * + * @v text Text + * @v setting Named setting to fill in + * @ret rc Return status code + * + * Note that this function modifies the original @c text. + */ +int parse_existing_setting ( char *text, struct named_setting *setting ) { + + return parse_setting ( text, setting, find_child_settings ); +} + +/** + * Parse and autovivify setting name + * + * @v text Text + * @v setting Named setting to fill in + * @ret rc Return status code + * + * Note that this function modifies the original @c text. + */ +int parse_autovivified_setting ( char *text, struct named_setting *setting ) { + + return parse_setting ( text, setting, autovivify_child_settings ); +} + +/** + * Parse form parameter list name + * + * @v text Text + * @ret params Parameter list + * @ret rc Return status code + */ +int parse_parameters ( char *text, struct parameters **params ) { + + /* Find parameter list */ + *params = find_parameters ( text ); + if ( ! *params ) { + if ( text ) { + printf ( "\"%s\": no such parameter list\n", text ); + } else { + printf ( "No default parameter list\n" ); + } + return -ENOENT; + } + + return 0; +} + +/** * Print command usage message * * @v cmd Command descriptor * @v argv Argument list */ void print_usage ( struct command_descriptor *cmd, char **argv ) { - printf ( "Usage:\n\n %s %s\n\nSee http://ipxe.org/cmd/%s for further " - "information\n", argv[0], cmd->usage, argv[0] ); + struct option_descriptor *option; + unsigned int i; + int is_optional; + + printf ( "Usage:\n\n %s", argv[0] ); + for ( i = 0 ; i < cmd->num_options ; i++ ) { + option = &cmd->options[i]; + printf ( " [-%c|--%s", option->shortopt, option->longopt ); + if ( option->has_arg ) { + is_optional = ( option->has_arg == optional_argument ); + printf ( " %s<%s>%s", ( is_optional ? "[" : "" ), + option->longopt, ( is_optional ? "]" : "" ) ); + } + printf ( "]" ); + } + if ( cmd->usage ) + printf ( " %s", cmd->usage ); + printf ( "\n\nSee http://ipxe.org/cmd/%s for further information\n", + argv[0] ); } /** @@ -198,7 +362,7 @@ int reparse_options ( int argc, char **argv, struct command_descriptor *cmd, char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */ + 1 /* NUL */ ]; unsigned int shortopt_idx = 0; - int ( * parse ) ( const char *text, void *value ); + int ( * parse ) ( char *text, void *value ); void *value; unsigned int i; unsigned int j; diff --git a/roms/ipxe/src/core/pending.c b/roms/ipxe/src/core/pending.c index c2671a688..7bb0c2e00 100644 --- a/roms/ipxe/src/core/pending.c +++ b/roms/ipxe/src/core/pending.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ /** Total count of pending operations */ -static int pending_total; +int pending_total; /** * Mark an operation as pending @@ -60,21 +60,3 @@ void pending_put ( struct pending_operation *pending ) { pending, pending->count, pending_total ); } } - -/** - * Wait for pending operations to complete - * - * @v timeout Timeout period, in ticks (0=indefinite) - * @ret rc Return status code - */ -int pending_wait ( unsigned long timeout ) { - unsigned long start = currticks(); - - do { - if ( pending_total == 0 ) - return 0; - step(); - } while ( ( timeout == 0 ) || ( ( currticks() - start ) < timeout ) ); - - return -ETIMEDOUT; -} diff --git a/roms/ipxe/src/core/pinger.c b/roms/ipxe/src/core/pinger.c new file mode 100644 index 000000000..c912a64d7 --- /dev/null +++ b/roms/ipxe/src/core/pinger.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ipxe/refcnt.h> +#include <ipxe/interface.h> +#include <ipxe/job.h> +#include <ipxe/xfer.h> +#include <ipxe/iobuf.h> +#include <ipxe/open.h> +#include <ipxe/socket.h> +#include <ipxe/retry.h> +#include <ipxe/pinger.h> + +/** @file + * + * ICMP ping sender + * + */ + +/* Disambiguate the various error causes */ +#define EPROTO_LEN __einfo_error ( EINFO_EPROTO_LEN ) +#define EINFO_EPROTO_LEN __einfo_uniqify ( EINFO_EPROTO, 0x01, \ + "Incorrect reply length" ) +#define EPROTO_DATA __einfo_error ( EINFO_EPROTO_DATA ) +#define EINFO_EPROTO_DATA __einfo_uniqify ( EINFO_EPROTO, 0x02, \ + "Incorrect reply data" ) +#define EPROTO_SEQ __einfo_error ( EINFO_EPROTO_SEQ ) +#define EINFO_EPROTO_SEQ __einfo_uniqify ( EINFO_EPROTO, 0x03, \ + "Delayed or out-of-sequence reply" ) + +/** A pinger */ +struct pinger { + /** Reference count */ + struct refcnt refcnt; + + /** Job control interface */ + struct interface job; + /** Data transfer interface */ + struct interface xfer; + + /** Timer */ + struct retry_timer timer; + /** Timeout */ + unsigned long timeout; + + /** Payload length */ + size_t len; + /** Current sequence number */ + uint16_t sequence; + + /** Callback function + * + * @v src Source socket address + * @v sequence Sequence number + * @v len Payload length + * @v rc Status code + */ + void ( * callback ) ( struct sockaddr *src, unsigned int sequence, + size_t len, int rc ); +}; + +/** + * Generate payload + * + * @v pinger Pinger + * @v data Data buffer + */ +static void pinger_generate ( struct pinger *pinger, void *data ) { + uint8_t *bytes = data; + unsigned int i; + + /* Generate byte sequence */ + for ( i = 0 ; i < pinger->len ; i++ ) + bytes[i] = ( i & 0xff ); +} + +/** + * Verify payload + * + * @v pinger Pinger + * @v data Data buffer + * @ret rc Return status code + */ +static int pinger_verify ( struct pinger *pinger, const void *data ) { + const uint8_t *bytes = data; + unsigned int i; + + /* Check byte sequence */ + for ( i = 0 ; i < pinger->len ; i++ ) { + if ( bytes[i] != ( i & 0xff ) ) + return -EPROTO_DATA; + } + + return 0; +} + +/** + * Close pinger + * + * @v pinger Pinger + * @v rc Reason for close + */ +static void pinger_close ( struct pinger *pinger, int rc ) { + + /* Stop timer */ + stop_timer ( &pinger->timer ); + + /* Shut down interfaces */ + intf_shutdown ( &pinger->xfer, rc ); + intf_shutdown ( &pinger->job, rc ); +} + +/** + * Handle data transfer window change + * + * @v pinger Pinger + */ +static void pinger_window_changed ( struct pinger *pinger ) { + + /* Do nothing if timer is already running */ + if ( timer_running ( &pinger->timer ) ) + return; + + /* Start timer when window opens for the first time */ + if ( xfer_window ( &pinger->xfer ) ) + start_timer_nodelay ( &pinger->timer ); +} + +/** + * Handle timer expiry + * + * @v timer Timer + * @v over Failure indicator + */ +static void pinger_expired ( struct retry_timer *timer, int over __unused ) { + struct pinger *pinger = container_of ( timer, struct pinger, timer ); + struct xfer_metadata meta; + struct io_buffer *iobuf; + int rc; + + /* Increase sequence number */ + pinger->sequence++; + + /* Restart timer. Do this before attempting to transmit, in + * case the transmission attempt fails. + */ + start_timer_fixed ( &pinger->timer, pinger->timeout ); + + /* Allocate I/O buffer */ + iobuf = xfer_alloc_iob ( &pinger->xfer, pinger->len ); + if ( ! iobuf ) { + DBGC ( pinger, "PINGER %p could not allocate I/O buffer\n", + pinger ); + return; + } + + /* Generate payload */ + pinger_generate ( pinger, iob_put ( iobuf, pinger->len ) ); + + /* Generate metadata */ + memset ( &meta, 0, sizeof ( meta ) ); + meta.flags = XFER_FL_ABS_OFFSET; + meta.offset = pinger->sequence; + + /* Transmit packet */ + if ( ( rc = xfer_deliver ( &pinger->xfer, iobuf, &meta ) ) != 0 ) { + DBGC ( pinger, "PINGER %p could not transmit: %s\n", + pinger, strerror ( rc ) ); + return; + } +} + +/** + * Handle received data + * + * @v pinger Pinger + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf, + struct xfer_metadata *meta ) { + size_t len = iob_len ( iobuf ); + uint16_t sequence = meta->offset; + int rc; + + /* Check for errors */ + if ( len != pinger->len ) { + DBGC ( pinger, "PINGER %p received incorrect length %zd " + "(expected %zd)\n", pinger, len, pinger->len ); + rc = -EPROTO_LEN; + } else if ( ( rc = pinger_verify ( pinger, iobuf->data ) ) != 0 ) { + DBGC ( pinger, "PINGER %p received incorrect data:\n", pinger ); + DBGC_HDA ( pinger, 0, iobuf->data, iob_len ( iobuf ) ); + } else if ( sequence != pinger->sequence ) { + DBGC ( pinger, "PINGER %p received sequence %d (expected %d)\n", + pinger, sequence, pinger->sequence ); + rc = -EPROTO_SEQ; + } else { + rc = 0; + } + + /* Discard I/O buffer */ + free_iob ( iobuf ); + + /* Notify callback function */ + pinger->callback ( meta->src, sequence, len, rc ); + + return rc; +} + +/** Pinger data transfer interface operations */ +static struct interface_operation pinger_xfer_op[] = { + INTF_OP ( xfer_deliver, struct pinger *, pinger_deliver ), + INTF_OP ( xfer_window_changed, struct pinger *, pinger_window_changed ), + INTF_OP ( intf_close, struct pinger *, pinger_close ), +}; + +/** Pinger data transfer interface descriptor */ +static struct interface_descriptor pinger_xfer_desc = + INTF_DESC ( struct pinger, xfer, pinger_xfer_op ); + +/** Pinger job control interface operations */ +static struct interface_operation pinger_job_op[] = { + INTF_OP ( intf_close, struct pinger *, pinger_close ), +}; + +/** Pinger job control interface descriptor */ +static struct interface_descriptor pinger_job_desc = + INTF_DESC ( struct pinger, job, pinger_job_op ); + +/** + * Create pinger + * + * @v job Job control interface + * @v hostname Hostname to ping + * @v timeout Timeout (in ticks) + * @v len Payload length + * @ret rc Return status code + */ +int create_pinger ( struct interface *job, const char *hostname, + unsigned long timeout, size_t len, + void ( * callback ) ( struct sockaddr *src, + unsigned int sequence, size_t len, + int rc ) ) { + struct pinger *pinger; + int rc; + + /* Sanity check */ + if ( ! timeout ) + return -EINVAL; + + /* Allocate and initialise structure */ + pinger = zalloc ( sizeof ( *pinger ) ); + if ( ! pinger ) + return -ENOMEM; + ref_init ( &pinger->refcnt, NULL ); + intf_init ( &pinger->job, &pinger_job_desc, &pinger->refcnt ); + intf_init ( &pinger->xfer, &pinger_xfer_desc, &pinger->refcnt ); + timer_init ( &pinger->timer, pinger_expired, &pinger->refcnt ); + pinger->timeout = timeout; + pinger->len = len; + pinger->callback = callback; + + /* Open socket */ + if ( ( rc = xfer_open_named_socket ( &pinger->xfer, SOCK_ECHO, NULL, + hostname, NULL ) ) != 0 ) { + DBGC ( pinger, "PINGER %p could not open socket: %s\n", + pinger, strerror ( rc ) ); + goto err; + } + + /* Attach parent interface, mortalise self, and return */ + intf_plug_plug ( &pinger->job, job ); + ref_put ( &pinger->refcnt ); + return 0; + + err: + pinger_close ( pinger, rc ); + ref_put ( &pinger->refcnt ); + return rc; +} diff --git a/roms/ipxe/src/core/pixbuf.c b/roms/ipxe/src/core/pixbuf.c new file mode 100644 index 000000000..48f8e9f9a --- /dev/null +++ b/roms/ipxe/src/core/pixbuf.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Pixel buffer + * + */ + +#include <stdlib.h> +#include <ipxe/umalloc.h> +#include <ipxe/pixbuf.h> + +/** + * Free pixel buffer + * + * @v refcnt Reference count + */ +static void free_pixbuf ( struct refcnt *refcnt ) { + struct pixel_buffer *pixbuf = + container_of ( refcnt, struct pixel_buffer, refcnt ); + + ufree ( pixbuf->data ); + free ( pixbuf ); +} + +/** + * Allocate pixel buffer + * + * @v width Width + * @h height Height + * @ret pixbuf Pixel buffer, or NULL on failure + */ +struct pixel_buffer * alloc_pixbuf ( unsigned int width, unsigned int height ) { + struct pixel_buffer *pixbuf; + + /* Allocate and initialise structure */ + pixbuf = zalloc ( sizeof ( *pixbuf ) ); + if ( ! pixbuf ) + goto err_alloc_pixbuf; + ref_init ( &pixbuf->refcnt, free_pixbuf ); + pixbuf->width = width; + pixbuf->height = height; + pixbuf->len = ( width * height * sizeof ( uint32_t ) ); + + /* Allocate pixel data buffer */ + pixbuf->data = umalloc ( pixbuf->len ); + if ( ! pixbuf->data ) + goto err_alloc_data; + + return pixbuf; + + err_alloc_data: + pixbuf_put ( pixbuf ); + err_alloc_pixbuf: + return NULL; +} diff --git a/roms/ipxe/src/core/profile.c b/roms/ipxe/src/core/profile.c new file mode 100644 index 000000000..ceaadd6ce --- /dev/null +++ b/roms/ipxe/src/core/profile.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdio.h> +#include <strings.h> +#include <assert.h> +#include <ipxe/isqrt.h> +#include <ipxe/profile.h> + +/** @file + * + * Profiling + * + * The profiler computes basic statistics (mean, variance, and + * standard deviation) for the samples which it records. Note that + * these statistics need not be completely accurate; it is sufficient + * to give a rough approximation. + * + * The algorithm for updating the mean and variance estimators is from + * The Art of Computer Programming (via Wikipedia), with adjustments + * to avoid the use of floating-point instructions. + */ + +/** + * Format a hex fraction (for debugging) + * + * @v value Value + * @v shift Bit shift + * @ret string Formatted hex fraction + */ +static const char * profile_hex_fraction ( signed long long value, + unsigned int shift ) { + static char buf[23] = "-"; /* -0xXXXXXXXXXXXXXXXX.XX + NUL */ + unsigned long long int_part; + uint8_t frac_part; + char *ptr; + + if ( value < 0 ) { + value = -value; + ptr = &buf[0]; + } else { + ptr = &buf[1]; + } + int_part = ( value >> shift ); + frac_part = ( value >> ( shift - ( 8 * sizeof ( frac_part ) ) ) ); + snprintf ( &buf[1], ( sizeof ( buf ) - 1 ), "%#llx.%02x", + int_part, frac_part ); + return ptr; +} + +/** + * Calculate bit shift for mean sample value + * + * @v profiler Profiler + * @ret shift Bit shift + */ +static inline unsigned int profile_mean_shift ( struct profiler *profiler ) { + + return ( ( ( 8 * sizeof ( profiler->mean ) ) - 1 ) /* MSB */ + - 1 /* Leave sign bit unused */ + - profiler->mean_msb ); +} + +/** + * Calculate bit shift for accumulated variance value + * + * @v profiler Profiler + * @ret shift Bit shift + */ +static inline unsigned int profile_accvar_shift ( struct profiler *profiler ) { + + return ( ( ( 8 * sizeof ( profiler->accvar ) ) - 1 ) /* MSB */ + - 1 /* Leave top bit unused */ + - profiler->accvar_msb ); +} + +/** + * Update profiler with a new sample + * + * @v profiler Profiler + * @v sample Sample value + */ +void profile_update ( struct profiler *profiler, unsigned long sample ) { + unsigned int sample_msb; + unsigned int mean_shift; + unsigned int delta_shift; + signed long pre_delta; + signed long post_delta; + signed long long accvar_delta; + unsigned int accvar_delta_shift; + unsigned int accvar_delta_msb; + unsigned int accvar_shift; + + /* Our scaling logic assumes that sample values never overflow + * a signed long (i.e. that the high bit is always zero). + */ + assert ( ( ( signed ) sample ) >= 0 ); + + /* Update sample count */ + profiler->count++; + + /* Adjust mean sample value scale if necessary. Skip if + * sample is zero (in which case flsl(sample)-1 would + * underflow): in the case of a zero sample we have no need to + * adjust the scale anyway. + */ + if ( sample ) { + sample_msb = ( flsl ( sample ) - 1 ); + if ( profiler->mean_msb < sample_msb ) { + profiler->mean >>= ( sample_msb - profiler->mean_msb ); + profiler->mean_msb = sample_msb; + } + } + + /* Scale sample to internal units */ + mean_shift = profile_mean_shift ( profiler ); + sample <<= mean_shift; + + /* Update mean */ + pre_delta = ( sample - profiler->mean ); + profiler->mean += ( pre_delta / ( ( signed ) profiler->count ) ); + post_delta = ( sample - profiler->mean ); + delta_shift = mean_shift; + DBGC ( profiler, "PROFILER %p sample %#lx mean %s", profiler, + ( sample >> mean_shift ), + profile_hex_fraction ( profiler->mean, mean_shift ) ); + DBGC ( profiler, " pre %s", + profile_hex_fraction ( pre_delta, delta_shift ) ); + DBGC ( profiler, " post %s\n", + profile_hex_fraction ( post_delta, delta_shift ) ); + + /* Scale both deltas to fit in half of an unsigned long long + * to avoid potential overflow on multiplication. Note that + * shifting a signed quantity is "implementation-defined" + * behaviour in the C standard, but gcc documents that it will + * always perform sign extension. + */ + if ( sizeof ( pre_delta ) > ( sizeof ( accvar_delta ) / 2 ) ) { + unsigned int shift = ( 8 * ( sizeof ( pre_delta ) - + ( sizeof ( accvar_delta ) / 2 ) )); + pre_delta >>= shift; + post_delta >>= shift; + delta_shift -= shift; + } + + /* Update variance, if applicable. Skip if either delta is + * zero (in which case flsl(delta)-1 would underflow): in the + * case of a zero delta there is no change to the accumulated + * variance anyway. + */ + if ( pre_delta && post_delta ) { + + /* Calculate variance delta */ + accvar_delta = ( ( ( signed long long ) pre_delta ) * + ( ( signed long long ) post_delta ) ); + accvar_delta_shift = ( 2 * delta_shift ); + assert ( accvar_delta > 0 ); + + /* Calculate variance delta MSB, using flsl() on each + * delta individually to provide an upper bound rather + * than requiring the existence of flsll(). + */ + accvar_delta_msb = ( flsll ( accvar_delta ) - 1 ); + if ( accvar_delta_msb > accvar_delta_shift ) { + accvar_delta_msb -= accvar_delta_shift; + } else { + accvar_delta_msb = 0; + } + + /* Adjust scales as necessary */ + if ( profiler->accvar_msb < accvar_delta_msb ) { + /* Rescale accumulated variance */ + profiler->accvar >>= ( accvar_delta_msb - + profiler->accvar_msb ); + profiler->accvar_msb = accvar_delta_msb; + } else { + /* Rescale variance delta */ + accvar_delta >>= ( profiler->accvar_msb - + accvar_delta_msb ); + accvar_delta_shift -= ( profiler->accvar_msb - + accvar_delta_msb ); + } + + /* Scale delta to internal units */ + accvar_shift = profile_accvar_shift ( profiler ); + accvar_delta <<= ( accvar_shift - accvar_delta_shift ); + + /* Accumulate variance */ + profiler->accvar += accvar_delta; + + /* Adjust scale if necessary */ + if ( profiler->accvar & + ( 1ULL << ( ( 8 * sizeof ( profiler->accvar ) ) - 1 ) ) ) { + profiler->accvar >>= 1; + profiler->accvar_msb++; + accvar_delta >>= 1; + accvar_shift--; + } + + DBGC ( profiler, "PROFILER %p accvar %s", profiler, + profile_hex_fraction ( profiler->accvar, accvar_shift )); + DBGC ( profiler, " delta %s\n", + profile_hex_fraction ( accvar_delta, accvar_shift ) ); + } +} + +/** + * Get mean sample value + * + * @v profiler Profiler + * @ret mean Mean sample value + */ +unsigned long profile_mean ( struct profiler *profiler ) { + unsigned int mean_shift = profile_mean_shift ( profiler ); + + /* Round to nearest and scale down to original units */ + return ( ( profiler->mean + ( 1UL << ( mean_shift - 1 ) ) ) + >> mean_shift ); +} + +/** + * Get sample variance + * + * @v profiler Profiler + * @ret variance Sample variance + */ +unsigned long profile_variance ( struct profiler *profiler ) { + unsigned int accvar_shift = profile_accvar_shift ( profiler ); + + /* Variance is zero if fewer than two samples exist (avoiding + * division by zero error). + */ + if ( profiler->count < 2 ) + return 0; + + /* Calculate variance, round to nearest, and scale to original units */ + return ( ( ( profiler->accvar / ( profiler->count - 1 ) ) + + ( 1ULL << ( accvar_shift - 1 ) ) ) >> accvar_shift ); +} + +/** + * Get sample standard deviation + * + * @v profiler Profiler + * @ret stddev Sample standard deviation + */ +unsigned long profile_stddev ( struct profiler *profiler ) { + + return isqrt ( profile_variance ( profiler ) ); +} diff --git a/roms/ipxe/src/core/resolv.c b/roms/ipxe/src/core/resolv.c index 86f19ee2d..d59a8c0ad 100644 --- a/roms/ipxe/src/core/resolv.c +++ b/roms/ipxe/src/core/resolv.c @@ -23,10 +23,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <string.h> #include <errno.h> -#include <ipxe/in.h> #include <ipxe/xfer.h> #include <ipxe/open.h> #include <ipxe/process.h> +#include <ipxe/socket.h> #include <ipxe/resolv.h> /** @file @@ -100,7 +100,6 @@ static struct process_descriptor numeric_process_desc = static int numeric_resolv ( struct interface *resolv, const char *name, struct sockaddr *sa ) { struct numeric_resolv *numeric; - struct sockaddr_in *sin; /* Allocate and initialise structure */ numeric = zalloc ( sizeof ( *numeric ) ); @@ -112,16 +111,8 @@ static int numeric_resolv ( struct interface *resolv, &numeric->refcnt ); memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) ); - DBGC ( numeric, "NUMERIC %p attempting to resolve \"%s\"\n", - numeric, name ); - /* Attempt to resolve name */ - sin = ( ( struct sockaddr_in * ) &numeric->sa ); - if ( inet_aton ( name, &sin->sin_addr ) != 0 ) { - sin->sin_family = AF_INET; - } else { - numeric->rc = -EINVAL; - } + numeric->rc = sock_aton ( name, &numeric->sa ); /* Attach to parent interface, mortalise self, and return */ intf_plug_plug ( &numeric->resolv, resolv ); @@ -193,8 +184,8 @@ static int resmux_try ( struct resolv_mux *mux ) { static void resmux_child_resolv_done ( struct resolv_mux *mux, struct sockaddr *sa ) { - DBGC ( mux, "RESOLV %p resolved \"%s\" using method %s\n", - mux, mux->name, mux->resolver->name ); + DBGC ( mux, "RESOLV %p resolved \"%s\" to %s using method %s\n", + mux, mux->name, sock_ntoa ( sa ), mux->resolver->name ); /* Pass resolution to parent */ resolv_done ( &mux->parent, sa ); diff --git a/roms/ipxe/src/core/serial.c b/roms/ipxe/src/core/serial.c index 8f5a159c4..7e4460ab9 100644 --- a/roms/ipxe/src/core/serial.c +++ b/roms/ipxe/src/core/serial.c @@ -204,8 +204,8 @@ static void serial_init ( void ) { /* disable interrupts */ uart_writeb(0x0, UART_BASE + UART_IER); - /* disable fifo's */ - uart_writeb(0x00, UART_BASE + UART_FCR); + /* enable fifos */ + uart_writeb(0x01, UART_BASE + UART_FCR); /* Set clear to send, so flow control works... */ uart_writeb((1<<1), UART_BASE + UART_MCR); diff --git a/roms/ipxe/src/core/serial_console.c b/roms/ipxe/src/core/serial_console.c index 3852a308c..de9b84ca7 100644 --- a/roms/ipxe/src/core/serial_console.c +++ b/roms/ipxe/src/core/serial_console.c @@ -30,7 +30,7 @@ struct console_driver serial_console __console_driver = { .putchar = serial_putc, .getchar = serial_getc, .iskey = serial_ischar, - .disabled = 1, + .disabled = CONSOLE_DISABLED, .usage = CONSOLE_SERIAL, }; diff --git a/roms/ipxe/src/core/settings.c b/roms/ipxe/src/core/settings.c index 656ae19fe..5e16b27d0 100644 --- a/roms/ipxe/src/core/settings.c +++ b/roms/ipxe/src/core/settings.c @@ -28,11 +28,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> #include <assert.h> #include <ipxe/in.h> +#include <ipxe/ip.h> +#include <ipxe/ipv6.h> #include <ipxe/vsprintf.h> #include <ipxe/dhcp.h> #include <ipxe/uuid.h> #include <ipxe/uri.h> +#include <ipxe/base16.h> +#include <ipxe/pci.h> #include <ipxe/init.h> +#include <ipxe/version.h> #include <ipxe/settings.h> /** @file @@ -93,7 +98,7 @@ static inline void * generic_setting_data ( struct generic_setting *generic ) { */ static struct generic_setting * find_generic_setting ( struct generic_settings *generics, - struct setting *setting ) { + const struct setting *setting ) { struct generic_setting *generic; list_for_each_entry ( generic, &generics->list, list ) { @@ -113,7 +118,7 @@ find_generic_setting ( struct generic_settings *generics, * @ret rc Return status code */ int generic_settings_store ( struct settings *settings, - struct setting *setting, + const struct setting *setting, const void *data, size_t len ) { struct generic_settings *generics = container_of ( settings, struct generic_settings, settings ); @@ -259,7 +264,7 @@ static void autovivified_settings_free ( struct refcnt *refcnt ) { } /** - * Find child named settings block + * Find child settings block * * @v parent Parent settings block * @v name Name within this parent @@ -269,6 +274,9 @@ struct settings * find_child_settings ( struct settings *parent, const char *name ) { struct settings *settings; + /* Find target parent settings block */ + parent = settings_target ( parent ); + /* Treat empty name as meaning "this block" */ if ( ! *name ) return parent; @@ -276,27 +284,30 @@ struct settings * find_child_settings ( struct settings *parent, /* Look for child with matching name */ list_for_each_entry ( settings, &parent->children, siblings ) { if ( strcmp ( settings->name, name ) == 0 ) - return settings; + return settings_target ( settings ); } return NULL; } /** - * Find or create child named settings block + * Find or create child 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 settings * autovivify_child_settings ( struct settings *parent, + const char *name ) { struct { struct autovivified_settings autovivified; char name[ strlen ( name ) + 1 /* NUL */ ]; } *new_child; struct settings *settings; + /* Find target parent settings block */ + parent = settings_target ( parent ); + /* Return existing settings, if existent */ if ( ( settings = find_child_settings ( parent, name ) ) != NULL ) return settings; @@ -328,6 +339,10 @@ const char * settings_name ( struct settings *settings ) { static char buf[16]; char tmp[ sizeof ( buf ) ]; + /* Find target settings block */ + settings = settings_target ( settings ); + + /* Construct name */ for ( buf[2] = buf[0] = 0 ; settings ; settings = settings->parent ) { memcpy ( tmp, buf, sizeof ( tmp ) ); snprintf ( buf, sizeof ( buf ), ".%s%s", settings->name, tmp ); @@ -343,9 +358,7 @@ const char * settings_name ( struct settings *settings ) { * @ret settings Settings block, or NULL */ static struct settings * -parse_settings_name ( const char *name, - struct settings * ( * get_child ) ( struct settings *, - const char * ) ) { +parse_settings_name ( const char *name, get_child_settings_t get_child ) { struct settings *settings = &settings_root; char name_copy[ strlen ( name ) + 1 ]; char *subname; @@ -357,20 +370,11 @@ parse_settings_name ( const char *name, /* 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 ); - + settings = get_child ( settings, subname ); if ( ! settings ) break; } @@ -379,7 +383,7 @@ parse_settings_name ( const char *name, } /** - * Find named settings block + * Find settings block * * @v name Name * @ret settings Settings block, or NULL @@ -458,10 +462,11 @@ int register_settings ( struct settings *settings, struct settings *parent, const char *name ) { struct settings *old_settings; - /* NULL parent => add to settings root */ + /* Sanity check */ assert ( settings != NULL ); - if ( parent == NULL ) - parent = &settings_root; + + /* Find target parent settings block */ + parent = settings_target ( parent ); /* Apply settings block name */ settings->name = name; @@ -522,19 +527,69 @@ void unregister_settings ( struct settings *settings ) { */ /** + * Redirect to target settings block + * + * @v settings Settings block, or NULL + * @ret settings Underlying settings block + */ +struct settings * settings_target ( struct settings *settings ) { + + /* NULL settings implies the global settings root */ + if ( ! settings ) + settings = &settings_root; + + /* Redirect to underlying settings block, if applicable */ + if ( settings->op->redirect ) + return settings->op->redirect ( settings ); + + /* Otherwise, return this settings block */ + return settings; +} + +/** * Check applicability of setting * * @v settings Settings block * @v setting Setting * @ret applies Setting applies within this settings block */ -int setting_applies ( struct settings *settings, struct setting *setting ) { +int setting_applies ( struct settings *settings, + const struct setting *setting ) { + /* Find target settings block */ + settings = settings_target ( settings ); + + /* Check applicability of setting */ return ( settings->op->applies ? settings->op->applies ( settings, setting ) : 1 ); } /** + * Find setting applicable to settings block, if any + * + * @v settings Settings block + * @v setting Setting + * @ret setting Applicable setting, if any + */ +static const struct setting * +applicable_setting ( struct settings *settings, const struct setting *setting ){ + const struct setting *applicable; + + /* If setting is already applicable, use it */ + if ( setting_applies ( settings, setting ) ) + return setting; + + /* Otherwise, look for a matching predefined setting which does apply */ + for_each_table_entry ( applicable, SETTINGS ) { + if ( ( setting_cmp ( setting, applicable ) == 0 ) && + ( setting_applies ( settings, applicable ) ) ) + return applicable; + } + + return NULL; +} + +/** * Store value of setting * * @v settings Settings block, or NULL @@ -543,15 +598,14 @@ int setting_applies ( struct settings *settings, struct setting *setting ) { * @v len Length of setting data * @ret rc Return status code */ -int store_setting ( struct settings *settings, struct setting *setting, +int store_setting ( struct settings *settings, const struct setting *setting, const void *data, size_t len ) { int rc; - /* NULL settings implies storing into the global settings root */ - if ( ! settings ) - settings = &settings_root; + /* Find target settings block */ + settings = settings_target ( settings ); - /* Fail if tag does not apply to this settings block */ + /* Fail if setting does not apply to this settings block */ if ( ! setting_applies ( settings, setting ) ) return -ENOTTY; @@ -583,11 +637,12 @@ int store_setting ( struct settings *settings, struct setting *setting, } /** - * Fetch value and origin of setting + * Fetch setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch - * @v origin Origin of setting to fill in + * @v origin Origin of setting to fill in, or NULL + * @v fetched Fetched setting to fill in, or NULL * @v data Buffer to fill with setting data * @v len Length of buffer * @ret len Length of setting data, or negative error @@ -595,43 +650,56 @@ int store_setting ( struct settings *settings, struct setting *setting, * The actual length of the setting will be returned even if * the buffer was too small. */ -static int fetch_setting_and_origin ( struct settings *settings, - struct setting *setting, - struct settings **origin, - void *data, size_t len ) { +int fetch_setting ( struct settings *settings, const struct setting *setting, + struct settings **origin, struct setting *fetched, + void *data, size_t len ) { + const struct setting *applicable; struct settings *child; + struct setting tmp; int ret; /* Avoid returning uninitialised data on error */ memset ( data, 0, len ); if ( origin ) *origin = NULL; + if ( fetched ) + memcpy ( fetched, setting, sizeof ( *fetched ) ); - /* NULL settings implies starting at the global settings root */ - if ( ! settings ) - settings = &settings_root; + /* Find target settings block */ + settings = settings_target ( settings ); /* Sanity check */ if ( ! settings->op->fetch ) return -ENOTSUP; - /* Try this block first, if applicable */ - if ( setting_applies ( settings, setting ) && - ( ( ret = settings->op->fetch ( settings, setting, - data, len ) ) >= 0 ) ) { - /* Record origin, if applicable */ - if ( origin ) - *origin = settings; - /* Default to string setting type, if not yet specified */ - if ( ! setting->type ) - setting->type = &setting_type_string; - return ret; + /* Try this block first, if an applicable setting exists */ + if ( ( applicable = applicable_setting ( settings, setting ) ) ) { + + /* Create modifiable copy of setting */ + memcpy ( &tmp, applicable, sizeof ( tmp ) ); + if ( ( ret = settings->op->fetch ( settings, &tmp, + data, len ) ) >= 0 ) { + + /* Default to string type, if not yet specified */ + if ( ! tmp.type ) + tmp.type = &setting_type_string; + + /* Record origin, if applicable */ + if ( origin ) + *origin = settings; + + /* Record fetched setting, if applicable */ + if ( fetched ) + memcpy ( fetched, &tmp, sizeof ( *fetched ) ); + + return ret; + } } /* Recurse into each child block in turn */ list_for_each_entry ( child, &settings->children, siblings ) { - if ( ( ret = fetch_setting_and_origin ( child, setting, origin, - data, len ) ) >= 0 ) + if ( ( ret = fetch_setting ( child, setting, origin, fetched, + data, len ) ) >= 0 ) return ret; } @@ -639,56 +707,95 @@ static int fetch_setting_and_origin ( struct settings *settings, } /** - * Fetch value of setting + * Fetch allocated copy of setting * * @v settings Settings block, or NULL to search all blocks * @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 + * @v origin Origin of setting to fill in, or NULL + * @v fetched Fetched setting to fill in, or NULL + * @v data Buffer to allocate and fill with setting data + * @v alloc Allocation function + * @ret len Length of setting, or negative error * - * The actual length of the setting will be returned even if - * the buffer was too small. + * The caller is responsible for eventually freeing the allocated + * buffer. */ -int fetch_setting ( struct settings *settings, struct setting *setting, - void *data, size_t len ) { - return fetch_setting_and_origin ( settings, setting, NULL, data, len ); +static int fetch_setting_alloc ( struct settings *settings, + const struct setting *setting, + struct settings **origin, + struct setting *fetched, + void **data, + void * ( * alloc ) ( size_t len ) ) { + struct settings *tmp_origin; + struct setting tmp_fetched; + int len; + int check_len; + + /* Use local buffers if necessary */ + if ( ! origin ) + origin = &tmp_origin; + if ( ! fetched ) + fetched = &tmp_fetched; + + /* Avoid returning uninitialised data on error */ + *data = NULL; + + /* Check existence, and fetch setting length */ + len = fetch_setting ( settings, setting, origin, fetched, NULL, 0 ); + if ( len < 0 ) + return len; + + /* Allocate buffer */ + *data = alloc ( len ); + if ( ! *data ) + return -ENOMEM; + + /* Fetch setting value */ + check_len = fetch_setting ( *origin, fetched, NULL, NULL, *data, len ); + assert ( check_len == len ); + return len; } /** - * Fetch origin of setting + * Fetch copy of setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch - * @ret origin Origin of setting, or NULL if not found + * @v origin Origin of setting to fill in, or NULL + * @v fetched Fetched setting to fill in, or NULL + * @v data Buffer to allocate and fill with setting data + * @ret len Length of setting, or negative error * - * This function can also be used as an existence check for the - * setting. + * The caller is responsible for eventually freeing the allocated + * buffer. */ -struct settings * fetch_setting_origin ( struct settings *settings, - struct setting *setting ) { - struct settings *origin; +int fetch_setting_copy ( struct settings *settings, + const struct setting *setting, + struct settings **origin, struct setting *fetched, + void **data ) { - fetch_setting_and_origin ( settings, setting, &origin, NULL, 0 ); - return origin; + return fetch_setting_alloc ( settings, setting, origin, fetched, + data, malloc ); } /** - * Fetch length of setting + * Fetch value of setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch - * @ret len Length of setting data, or negative error - * - * This function can also be used as an existence check for the - * setting. + * @v data Buffer to fill with setting string data + * @v len Length of buffer + * @ret len Length of setting, or negative error */ -int fetch_setting_len ( struct settings *settings, struct setting *setting ) { - return fetch_setting ( settings, setting, NULL, 0 ); +int fetch_raw_setting ( struct settings *settings, + const struct setting *setting, + void *data, size_t len ) { + + return fetch_setting ( settings, setting, NULL, NULL, data, len ); } /** - * Fetch copy of setting + * Fetch value of setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch @@ -697,34 +804,12 @@ int fetch_setting_len ( struct settings *settings, struct setting *setting ) { * * The caller is responsible for eventually freeing the allocated * buffer. - * - * To allow the caller to distinguish between a non-existent setting - * and an error in allocating memory for the copy, this function will - * return success (and a NULL buffer pointer) for a non-existent - * setting. */ -int fetch_setting_copy ( struct settings *settings, struct setting *setting, - void **data ) { - int len; - int check_len = 0; - - /* Avoid returning uninitialised data on error */ - *data = NULL; - - /* Fetch setting length, and return success if non-existent */ - len = fetch_setting_len ( settings, setting ); - if ( len < 0 ) - return 0; - - /* Allocate buffer */ - *data = malloc ( len ); - if ( ! *data ) - return -ENOMEM; +int fetch_raw_setting_copy ( struct settings *settings, + const struct setting *setting, + void **data ) { - /* Fetch setting */ - check_len = fetch_setting ( settings, setting, *data, len ); - assert ( check_len == len ); - return len; + return fetch_setting_copy ( settings, setting, NULL, NULL, data ); } /** @@ -740,11 +825,23 @@ int fetch_setting_copy ( struct settings *settings, struct setting *setting, * The returned length will be the length of the underlying setting * data. */ -int fetch_string_setting ( struct settings *settings, struct setting *setting, +int fetch_string_setting ( struct settings *settings, + const struct setting *setting, char *data, size_t len ) { + memset ( data, 0, len ); - return fetch_setting ( settings, setting, data, - ( ( len > 0 ) ? ( len - 1 ) : 0 ) ); + return fetch_raw_setting ( settings, setting, data, + ( ( len > 0 ) ? ( len - 1 ) : 0 ) ); +} + +/** + * Allocate memory for copy of string setting + * + * @v len Length of setting + * @ret ptr Allocated memory + */ +static void * fetch_string_setting_copy_alloc ( size_t len ) { + return zalloc ( len + 1 /* NUL */ ); } /** @@ -759,36 +856,13 @@ int fetch_string_setting ( struct settings *settings, struct setting *setting, * The returned length will be the length of the underlying setting * data. The caller is responsible for eventually freeing the * allocated buffer. - * - * To allow the caller to distinguish between a non-existent setting - * and an error in allocating memory for the copy, this function will - * return success (and a NULL buffer pointer) for a non-existent - * setting. */ int fetch_string_setting_copy ( struct settings *settings, - struct setting *setting, - char **data ) { - int len; - int check_len = 0; + const struct setting *setting, char **data ) { - /* Avoid returning uninitialised data on error */ - *data = NULL; - - /* Fetch setting length, and return success if non-existent */ - len = fetch_setting_len ( settings, setting ); - if ( len < 0 ) - return 0; - - /* Allocate string buffer */ - *data = malloc ( len + 1 ); - if ( ! *data ) - return -ENOMEM; - - /* Fetch setting */ - check_len = fetch_string_setting ( settings, setting, *data, - ( len + 1 ) ); - assert ( check_len == len ); - return len; + return fetch_setting_alloc ( settings, setting, NULL, NULL, + ( ( void ** ) data ), + fetch_string_setting_copy_alloc ); } /** @@ -801,12 +875,12 @@ int fetch_string_setting_copy ( struct settings *settings, * @ret len Length of setting, or negative error */ int fetch_ipv4_array_setting ( struct settings *settings, - struct setting *setting, + const struct setting *setting, struct in_addr *inp, unsigned int count ) { int len; - len = fetch_setting ( settings, setting, inp, - ( sizeof ( *inp ) * count ) ); + len = fetch_raw_setting ( settings, setting, inp, + ( sizeof ( *inp ) * count ) ); if ( len < 0 ) return len; if ( ( len % sizeof ( *inp ) ) != 0 ) @@ -822,96 +896,138 @@ int fetch_ipv4_array_setting ( struct settings *settings, * @v inp IPv4 address to fill in * @ret len Length of setting, or negative error */ -int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, +int fetch_ipv4_setting ( struct settings *settings, + const struct setting *setting, struct in_addr *inp ) { + return fetch_ipv4_array_setting ( settings, setting, inp, 1 ); } /** + * Fetch value of IPv6 address setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v inp IPv6 addresses to fill in + * @v count Maximum number of IPv6 addresses + * @ret len Length of setting, or negative error + */ +int fetch_ipv6_array_setting ( struct settings *settings, + const struct setting *setting, + struct in6_addr *inp, unsigned int count ) { + int len; + + len = fetch_raw_setting ( settings, setting, inp, + ( sizeof ( *inp ) * count ) ); + if ( len < 0 ) + return len; + if ( ( len % sizeof ( *inp ) ) != 0 ) + return -ERANGE; + return len; +} + +/** + * Fetch value of IPv6 address setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v inp IPv6 address to fill in + * @ret len Length of setting, or negative error + */ +int fetch_ipv6_setting ( struct settings *settings, + const struct setting *setting, + struct in6_addr *inp ) { + + return fetch_ipv6_array_setting ( settings, setting, inp, 1 ); +} + +/** * Extract numeric value of setting * + * @v is_signed Treat value as a signed integer * @v raw Raw setting data * @v len Length of raw setting data - * @ret signed_value Value, when interpreted as a signed integer - * @ret unsigned_value Value, when interpreted as an unsigned integer + * @ret value Numeric value * @ret len Length of setting, or negative error */ -static int numeric_setting_value ( const void *raw, size_t len, - signed long *signed_value, - unsigned long *unsigned_value ) { +static int numeric_setting_value ( int is_signed, const void *raw, size_t len, + unsigned long *value ) { const uint8_t *unsigned_bytes = raw; const int8_t *signed_bytes = raw; int is_negative; unsigned int i; + uint8_t pad; uint8_t byte; - /* Range check */ - if ( len > sizeof ( long ) ) - return -ERANGE; - /* Convert to host-ordered longs */ is_negative = ( len && ( signed_bytes[0] < 0 ) ); - *signed_value = ( is_negative ? -1L : 0 ); - *unsigned_value = 0; + *value = ( ( is_signed && is_negative ) ? -1L : 0 ); + pad = *value; for ( i = 0 ; i < len ; i++ ) { byte = unsigned_bytes[i]; - *signed_value = ( ( *signed_value << 8 ) | byte ); - *unsigned_value = ( ( *unsigned_value << 8 ) | byte ); + *value = ( ( *value << 8 ) | byte ); + if ( ( ( i + sizeof ( *value ) ) < len ) && ( byte != pad ) ) + return -ERANGE; } return len; } /** - * Fetch value of signed integer setting + * Fetch value of numeric setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch * @v value Integer value to fill in * @ret len Length of setting, or negative error */ -int fetch_int_setting ( struct settings *settings, struct setting *setting, - long *value ) { - unsigned long dummy; - long tmp; +int fetch_numeric_setting ( struct settings *settings, + const struct setting *setting, + unsigned long *value, int is_signed ) { + unsigned long tmp; int len; /* Avoid returning uninitialised data on error */ *value = 0; /* Fetch raw (network-ordered, variable-length) setting */ - len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) ); + len = fetch_raw_setting ( settings, setting, &tmp, sizeof ( tmp ) ); if ( len < 0 ) return len; /* Extract numeric value */ - return numeric_setting_value ( &tmp, len, value, &dummy ); + return numeric_setting_value ( is_signed, &tmp, len, value ); } /** - * Fetch value of unsigned integer setting + * Fetch value of signed integer setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch * @v value Integer value to fill in * @ret len Length of setting, or negative error */ -int fetch_uint_setting ( struct settings *settings, struct setting *setting, - unsigned long *value ) { - signed long dummy; - long tmp; - int len; +int fetch_int_setting ( struct settings *settings, + const struct setting *setting, + long *value ) { - /* Avoid returning uninitialised data on error */ - *value = 0; + return fetch_numeric_setting ( settings, setting, + ( ( unsigned long * ) value ), 1 ); +} - /* Fetch raw (network-ordered, variable-length) setting */ - len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) ); - if ( len < 0 ) - return len; +/** + * Fetch value of unsigned integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v value Integer value to fill in + * @ret len Length of setting, or negative error + */ +int fetch_uint_setting ( struct settings *settings, + const struct setting *setting, + unsigned long *value ) { - /* Extract numeric value */ - return numeric_setting_value ( &tmp, len, &dummy, value ); + return fetch_numeric_setting ( settings, setting, value, 0 ); } /** @@ -921,10 +1037,11 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, * @v setting Setting to fetch * @ret value Setting value, or zero */ -long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ - long value; +long fetch_intz_setting ( struct settings *settings, + const struct setting *setting ) { + unsigned long value; - fetch_int_setting ( settings, setting, &value ); + fetch_numeric_setting ( settings, setting, &value, 1 ); return value; } @@ -936,10 +1053,10 @@ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ * @ret value Setting value, or zero */ unsigned long fetch_uintz_setting ( struct settings *settings, - struct setting *setting ) { + const struct setting *setting ) { unsigned long value; - fetch_uint_setting ( settings, setting, &value ); + fetch_numeric_setting ( settings, setting, &value, 0 ); return value; } @@ -951,11 +1068,12 @@ unsigned long fetch_uintz_setting ( struct settings *settings, * @v uuid UUID to fill in * @ret len Length of setting, or negative error */ -int fetch_uuid_setting ( struct settings *settings, struct setting *setting, +int fetch_uuid_setting ( struct settings *settings, + const struct setting *setting, union uuid *uuid ) { int len; - len = fetch_setting ( settings, setting, uuid, sizeof ( *uuid ) ); + len = fetch_raw_setting ( settings, setting, uuid, sizeof ( *uuid ) ); if ( len < 0 ) return len; if ( len != sizeof ( *uuid ) ) @@ -969,6 +1087,11 @@ int fetch_uuid_setting ( struct settings *settings, struct setting *setting, * @v settings Settings block */ void clear_settings ( struct settings *settings ) { + + /* Find target settings block */ + settings = settings_target ( settings ); + + /* Clear settings, if applicable */ if ( settings->op->clear ) settings->op->clear ( settings ); } @@ -981,10 +1104,10 @@ void clear_settings ( struct settings *settings ) { * @ret 0 Settings are the same * @ret non-zero Settings are not the same */ -int setting_cmp ( struct setting *a, struct setting *b ) { +int setting_cmp ( const struct setting *a, const struct setting *b ) { /* If the settings have tags, compare them */ - if ( a->tag && ( a->tag == b->tag ) ) + if ( a->tag && ( a->tag == b->tag ) && ( a->scope == b->scope ) ) return 0; /* Otherwise, if the settings have names, compare them */ @@ -1003,39 +1126,173 @@ int setting_cmp ( struct setting *a, struct setting *b ) { */ /** - * Fetch and format value of setting + * Format setting value as a string + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +int setting_format ( const struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ) { + + /* Sanity check */ + if ( ! type->format ) + return -ENOTSUP; + + return type->format ( type, raw, raw_len, buf, len ); +} + +/** + * Parse formatted string to setting value + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ +int setting_parse ( const struct setting_type *type, const char *value, + void *buf, size_t len ) { + + /* Sanity check */ + if ( ! type->parse ) + return -ENOTSUP; + + return type->parse ( type, value, buf, len ); +} + +/** + * Convert setting value to number + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @ret value Numeric value + * @ret rc Return status code + */ +int setting_numerate ( const struct setting_type *type, const void *raw, + size_t raw_len, unsigned long *value ) { + + /* Sanity check */ + if ( ! type->numerate ) + return -ENOTSUP; + + return type->numerate ( type, raw, raw_len, value ); +} + +/** + * Convert number to setting value + * + * @v type Setting type + * @v value Numeric value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ +int setting_denumerate ( const struct setting_type *type, unsigned long value, + void *buf, size_t len ) { + + /* Sanity check */ + if ( ! type->denumerate ) + return -ENOTSUP; + + return type->denumerate ( type, value, buf, len ); +} + +/** + * Fetch formatted value of setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch - * @v type Settings type + * @v origin Origin of setting to fill in, or NULL + * @v fetched Fetched setting to fill in, or NULL * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -int fetchf_setting ( struct settings *settings, struct setting *setting, +int fetchf_setting ( struct settings *settings, const struct setting *setting, + struct settings **origin, struct setting *fetched, char *buf, size_t len ) { + struct setting tmp_fetched; + void *raw; int raw_len; - int check_len; - int rc; + int ret; + + /* Use local buffers if necessary */ + if ( ! fetched ) + fetched = &tmp_fetched; /* Fetch raw value */ - raw_len = fetch_setting_len ( settings, setting ); + raw_len = fetch_setting_copy ( settings, setting, origin, fetched, + &raw ); if ( raw_len < 0 ) { - rc = raw_len; - return rc; - } else { - uint8_t raw[raw_len]; + ret = raw_len; + goto err_fetch_copy; + } - /* Fetch raw value */ - check_len = fetch_setting ( settings, setting, raw, - sizeof ( raw ) ); - if ( check_len < 0 ) - return check_len; - assert ( check_len == raw_len ); + /* Sanity check */ + assert ( fetched->type != NULL ); - /* Format value */ - return setting->type->format ( raw, sizeof ( raw ), buf, len ); - } + /* Format setting */ + if ( ( ret = setting_format ( fetched->type, raw, raw_len, buf, + len ) ) < 0 ) + goto err_format; + + err_format: + free ( raw ); + err_fetch_copy: + return ret; +} + +/** + * Fetch copy of formatted value of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v origin Origin of setting to fill in, or NULL + * @v fetched Fetched setting to fill in, or NULL + * @v value Buffer to allocate and fill with formatted value + * @ret len Length of formatted value, or negative error + * + * The caller is responsible for eventually freeing the allocated + * buffer. + */ +int fetchf_setting_copy ( struct settings *settings, + const struct setting *setting, + struct settings **origin, struct setting *fetched, + char **value ) { + struct settings *tmp_origin; + struct setting tmp_fetched; + int len; + int check_len; + + /* Use local buffers if necessary */ + if ( ! origin ) + origin = &tmp_origin; + if ( ! fetched ) + fetched = &tmp_fetched; + + /* Avoid returning uninitialised data on error */ + *value = NULL; + + /* Check existence, and fetch formatted value length */ + len = fetchf_setting ( settings, setting, origin, fetched, NULL, 0 ); + if ( len < 0 ) + return len; + + /* Allocate buffer */ + *value = zalloc ( len + 1 /* NUL */ ); + if ( ! *value ) + return -ENOMEM; + + /* Fetch formatted value */ + check_len = fetchf_setting ( *origin, fetched, NULL, NULL, *value, + ( len + 1 /* NUL */ ) ); + assert ( check_len == len ); + return len; } /** @@ -1046,8 +1303,9 @@ int fetchf_setting ( struct settings *settings, struct setting *setting, * @v value Formatted setting data, or NULL * @ret rc Return status code */ -int storef_setting ( struct settings *settings, struct setting *setting, +int storef_setting ( struct settings *settings, const struct setting *setting, const char *value ) { + void *raw; int raw_len; int check_len; int rc; @@ -1056,21 +1314,127 @@ int storef_setting ( struct settings *settings, struct setting *setting, if ( ( ! value ) || ( ! value[0] ) ) return delete_setting ( settings, setting ); + /* Sanity check */ + assert ( setting->type != NULL ); + + /* Get raw value length */ + raw_len = setting_parse ( setting->type, value, NULL, 0 ); + if ( raw_len < 0 ) { + rc = raw_len; + goto err_raw_len; + } + + /* Allocate buffer for raw value */ + raw = malloc ( raw_len ); + if ( ! raw ) { + rc = -ENOMEM; + goto err_alloc_raw; + } + /* Parse formatted value */ - raw_len = setting->type->parse ( value, NULL, 0 ); + check_len = setting_parse ( setting->type, value, raw, raw_len ); + assert ( check_len == raw_len ); + + /* Store raw value */ + if ( ( rc = store_setting ( settings, setting, raw, raw_len ) ) != 0 ) + goto err_store; + + err_store: + free ( raw ); + err_alloc_raw: + err_raw_len: + return rc; +} + +/** + * Fetch numeric value of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v origin Origin of setting to fill in, or NULL + * @v fetched Fetched setting to fill in, or NULL + * @v value Numeric value to fill in + * @ret rc Return status code + */ +int fetchn_setting ( struct settings *settings, const struct setting *setting, + struct settings **origin, struct setting *fetched, + unsigned long *value ) { + struct setting tmp_fetched; + void *raw; + int raw_len; + int rc; + + /* Use local buffers if necessary */ + if ( ! fetched ) + fetched = &tmp_fetched; + + /* Fetch raw value */ + raw_len = fetch_setting_copy ( settings, setting, origin, fetched, + &raw ); if ( raw_len < 0 ) { rc = raw_len; - return rc; - } else { - uint8_t raw[raw_len]; + goto err_fetch_copy; + } - /* Parse formatted value */ - check_len = setting->type->parse ( value, raw, sizeof ( raw ) ); - assert ( check_len == raw_len ); + /* Sanity check */ + assert ( fetched->type != NULL ); - /* Store raw value */ - return store_setting ( settings, setting, raw, sizeof ( raw ) ); + /* Numerate setting */ + if ( ( rc = setting_numerate ( fetched->type, raw, raw_len, + value ) ) < 0 ) + goto err_numerate; + + err_numerate: + free ( raw ); + err_fetch_copy: + return rc; +} + +/** + * Store numeric value of setting + * + * @v settings Settings block + * @v setting Setting + * @v value Numeric value + * @ret rc Return status code + */ +int storen_setting ( struct settings *settings, const struct setting *setting, + unsigned long value ) { + void *raw; + int raw_len; + int check_len; + int rc; + + /* Sanity check */ + assert ( setting->type != NULL ); + + /* Get raw value length */ + raw_len = setting_denumerate ( setting->type, value, NULL, 0 ); + if ( raw_len < 0 ) { + rc = raw_len; + goto err_raw_len; } + + /* Allocate buffer for raw value */ + raw = malloc ( raw_len ); + if ( ! raw ) { + rc = -ENOMEM; + goto err_alloc_raw; + } + + /* Denumerate value */ + check_len = setting_denumerate ( setting->type, value, raw, raw_len ); + assert ( check_len == raw_len ); + + /* Store raw value */ + if ( ( rc = store_setting ( settings, setting, raw, raw_len ) ) != 0 ) + goto err_store; + + err_store: + free ( raw ); + err_alloc_raw: + err_raw_len: + return rc; } /****************************************************************************** @@ -1081,10 +1445,10 @@ int storef_setting ( struct settings *settings, struct setting *setting, */ /** - * Find named setting + * Find predefined setting * * @v name Name - * @ret setting Named setting, or NULL + * @ret setting Setting, or NULL */ struct setting * find_setting ( const char *name ) { struct setting *setting; @@ -1099,19 +1463,17 @@ struct setting * find_setting ( const char *name ) { /** * Parse setting name as tag number * - * @v settings Settings block * @v name Name * @ret tag Tag number, or 0 if not a valid number */ -static unsigned int parse_setting_tag ( struct settings *settings, - const char *name ) { +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 | settings->tag_magic ); + return tag; if ( *tmp != '.' ) return 0; tmp++; @@ -1124,8 +1486,8 @@ static unsigned int parse_setting_tag ( struct settings *settings, * @v name Name * @ret type Setting type, or NULL */ -static struct setting_type * find_setting_type ( const char *name ) { - struct setting_type *type; +static const struct setting_type * find_setting_type ( const char *name ) { + const struct setting_type *type; for_each_table_entry ( type, SETTING_TYPES ) { if ( strcmp ( name, type->name ) == 0 ) @@ -1141,42 +1503,34 @@ static struct setting_type * find_setting_type ( const char *name ) { * @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 default_type Default type to use, if none specified - * @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. + * Note that on success, this function will have modified the original + * setting @c name. */ -static int -parse_setting_name ( const char *name, - struct settings * ( * get_child ) ( struct settings *, - const char * ), - struct settings **settings, struct setting *setting, - struct setting_type *default_type, - char *tmp_name ) { +int parse_setting_name ( char *name, get_child_settings_t get_child, + struct settings **settings, struct setting *setting ) { char *settings_name; char *setting_name; char *type_name; - struct setting *named_setting; + struct setting *predefined; + int rc; /* Set defaults */ *settings = &settings_root; memset ( setting, 0, sizeof ( *setting ) ); setting->name = ""; - setting->type = default_type; /* Split name into "[settings_name/]setting_name[:type_name]" */ - strcpy ( tmp_name, name ); - if ( ( setting_name = strchr ( tmp_name, '/' ) ) != NULL ) { + if ( ( setting_name = strchr ( name, '/' ) ) != NULL ) { *(setting_name++) = 0; - settings_name = tmp_name; + settings_name = name; } else { - setting_name = tmp_name; + setting_name = name; settings_name = NULL; } if ( ( type_name = strchr ( setting_name, ':' ) ) != NULL ) @@ -1188,17 +1542,19 @@ parse_setting_name ( const char *name, if ( *settings == NULL ) { DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n", settings_name, name ); - return -ENODEV; + rc = -ENODEV; + goto err; } } /* Identify setting */ - setting->tag = parse_setting_tag ( *settings, setting_name ); + setting->tag = parse_setting_tag ( setting_name ); + setting->scope = (*settings)->default_scope; setting->name = setting_name; - for_each_table_entry ( named_setting, SETTINGS ) { - /* Matches a defined named setting; use that setting */ - if ( setting_cmp ( named_setting, setting ) == 0 ) { - memcpy ( setting, named_setting, sizeof ( *setting ) ); + for_each_table_entry ( predefined, SETTINGS ) { + /* Matches a predefined setting; use that setting */ + if ( setting_cmp ( predefined, setting ) == 0 ) { + memcpy ( setting, predefined, sizeof ( *setting ) ); break; } } @@ -1209,11 +1565,20 @@ parse_setting_name ( const char *name, if ( setting->type == NULL ) { DBG ( "Invalid setting type \"%s\" in \"%s\"\n", type_name, name ); - return -ENOTSUP; + rc = -ENOTSUP; + goto err; } } return 0; + + err: + /* Restore original name */ + if ( settings_name ) + *( setting_name - 1 ) = '/'; + if ( type_name ) + *( type_name - 1 ) = ':'; + return rc; } /** @@ -1225,152 +1590,16 @@ parse_setting_name ( const char *name, * @v len Length of buffer * @ret len Length of setting name, or negative error */ -int setting_name ( struct settings *settings, struct setting *setting, +int setting_name ( struct settings *settings, const struct setting *setting, char *buf, size_t len ) { const char *name; - if ( ! settings ) - settings = &settings_root; - + settings = settings_target ( settings ); name = settings_name ( settings ); return snprintf ( buf, len, "%s%s%s:%s", name, ( name[0] ? "/" : "" ), setting->name, setting->type->name ); } -/** - * Store value of named setting - * - * @v name Name of setting - * @v default_type Default type to use, if none specified - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code - */ -int store_named_setting ( const char *name, struct setting_type *default_type, - const void *data, size_t len ) { - struct settings *settings; - struct setting setting; - char tmp_name[ strlen ( name ) + 1 ]; - int rc; - - /* Parse setting name */ - if ( ( rc = parse_setting_name ( name, autovivify_child_settings, - &settings, &setting, default_type, - tmp_name ) ) != 0 ) - return rc; - - /* Store setting */ - if ( ( rc = store_setting ( settings, &setting, data, len ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Parse and store value of named setting - * - * @v name Name of setting - * @v default_type Default type to use, if none specified - * @v value Formatted setting data, or NULL - * @ret rc Return status code - */ -int storef_named_setting ( const char *name, struct setting_type *default_type, - const char *value ) { - struct settings *settings; - struct setting setting; - char tmp_name[ strlen ( name ) + 1 ]; - int rc; - - /* Parse setting name */ - if ( ( rc = parse_setting_name ( name, autovivify_child_settings, - &settings, &setting, default_type, - tmp_name ) ) != 0 ) - return rc; - - /* Store setting */ - if ( ( rc = storef_setting ( settings, &setting, value ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Fetch and format value of named setting - * - * @v name Name of setting - * @v name_buf Buffer to contain canonicalised name - * @v name_len Length of canonicalised name buffer - * @v value_buf Buffer to contain formatted value - * @v value_len Length of formatted value buffer - * @ret len Length of formatted value, or negative error - */ -int fetchf_named_setting ( const char *name, - char *name_buf, size_t name_len, - char *value_buf, size_t value_len ) { - struct settings *settings; - struct setting setting; - struct settings *origin; - char tmp_name[ strlen ( name ) + 1 ]; - int len; - int rc; - - /* Parse setting name */ - if ( ( rc = parse_setting_name ( name, find_child_settings, &settings, - &setting, NULL, tmp_name ) ) != 0 ) - return rc; - - /* Fetch setting */ - if ( ( len = fetchf_setting ( settings, &setting, value_buf, - value_len ) ) < 0 ) - return len; - - /* Construct setting name */ - origin = fetch_setting_origin ( settings, &setting ); - assert ( origin != NULL ); - setting_name ( origin, &setting, name_buf, name_len ); - - return len; -} - -/** - * Fetch and format copy of value of named setting - * - * @v name Name of setting - * @v data Buffer to allocate and fill with formatted value - * @ret len Length of formatted value, or negative error - * - * The caller is responsible for eventually freeing the allocated - * buffer. - * - * To allow the caller to distinguish between a non-existent setting - * and an error in allocating memory for the copy, this function will - * return success (and a NULL buffer pointer) for a non-existent - * setting. - */ -int fetchf_named_setting_copy ( const char *name, char **data ) { - int len; - int check_len; - - /* Avoid returning uninitialised data on error */ - *data = NULL; - - /* Fetch formatted value length, and return success if non-existent */ - len = fetchf_named_setting ( name, NULL, 0, NULL, 0 ); - if ( len < 0 ) - return 0; - - /* Allocate buffer */ - *data = malloc ( len + 1 /* NUL */ ); - if ( ! *data ) - return -ENOMEM; - - /* Fetch formatted value */ - check_len = fetchf_named_setting ( name, NULL, 0, *data, - ( len + 1 /* NUL */ ) ); - assert ( check_len == len ); - return len; -} - /****************************************************************************** * * Setting types @@ -1381,12 +1610,14 @@ int fetchf_named_setting_copy ( const char *name, char **data ) { /** * Parse string setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ -static int parse_string_setting ( const char *value, void *buf, size_t len ) { +static int parse_string_setting ( const struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { size_t raw_len = strlen ( value ); /* Exclude terminating NUL */ /* Copy string to buffer */ @@ -1400,13 +1631,15 @@ static int parse_string_setting ( const char *value, void *buf, size_t len ) { /** * Format string setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_string_setting ( const void *raw, size_t raw_len, char *buf, +static int format_string_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { /* Copy string to buffer, and terminate */ @@ -1419,135 +1652,199 @@ static int format_string_setting ( const void *raw, size_t raw_len, char *buf, } /** A string setting type */ -struct setting_type setting_type_string __setting_type = { +const struct setting_type setting_type_string __setting_type = { .name = "string", .parse = parse_string_setting, .format = format_string_setting, }; +/** A URI-encoded string setting type + * + * This setting type is obsolete; the name ":uristring" is retained to + * avoid breaking existing scripts. + */ +const struct setting_type setting_type_uristring __setting_type = { + .name = "uristring", + .parse = parse_string_setting, + .format = format_string_setting, +}; + /** - * Parse URI-encoded string setting value + * Parse IPv4 address setting value (when IPv4 support is not present) * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ -static int parse_uristring_setting ( const char *value, void *buf, - size_t len ) { - char tmp[ len + 1 /* NUL */ ]; - size_t raw_len; - - /* Decode to temporary buffer (including NUL) */ - raw_len = uri_decode ( value, tmp, sizeof ( tmp ) ); - - /* Copy to output buffer (excluding NUL) */ - if ( len > raw_len ) - len = raw_len; - memcpy ( buf, tmp, len ); - - return raw_len; +__weak int parse_ipv4_setting ( const struct setting_type *type __unused, + const char *value __unused, void *buf __unused, + size_t len __unused ) { + return -ENOTSUP; } /** - * Format URI-encoded string setting value + * Format IPv4 address setting value (when IPv4 support is not present) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_uristring_setting ( const void *raw, size_t raw_len, - char *buf, size_t len ) { - char tmp[ raw_len + 1 /* NUL */ ]; - - /* Copy to temporary buffer and terminate */ - memcpy ( tmp, raw, raw_len ); - tmp[raw_len] = '\0'; - - /* Encode directly into output buffer */ - return uri_encode ( tmp, buf, len, URI_FRAGMENT ); +__weak int format_ipv4_setting ( const struct setting_type *type __unused, + const void *raw __unused, + size_t raw_len __unused, char *buf __unused, + size_t len __unused ) { + return -ENOTSUP; } -/** A URI-encoded string setting type */ -struct setting_type setting_type_uristring __setting_type = { - .name = "uristring", - .parse = parse_uristring_setting, - .format = format_uristring_setting, +/** An IPv4 address setting type */ +const struct setting_type setting_type_ipv4 __setting_type = { + .name = "ipv4", + .parse = parse_ipv4_setting, + .format = format_ipv4_setting, }; /** - * Parse IPv4 address setting value + * Parse IPv6 address setting value (when IPv6 support is not present) * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ -static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) { - struct in_addr ipv4; - - /* Parse IPv4 address */ - if ( inet_aton ( value, &ipv4 ) == 0 ) - return -EINVAL; - - /* Copy to buffer */ - if ( len > sizeof ( ipv4 ) ) - len = sizeof ( ipv4 ); - memcpy ( buf, &ipv4, len ); - - return ( sizeof ( ipv4 ) ); +__weak int parse_ipv6_setting ( const struct setting_type *type __unused, + const char *value __unused, void *buf __unused, + size_t len __unused ) { + return -ENOTSUP; } /** - * Format IPv4 address setting value + * Format IPv6 address setting value (when IPv6 support is not present) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_ipv4_setting ( const void *raw, size_t raw_len, char *buf, - size_t len ) { - const struct in_addr *ipv4 = raw; - - if ( raw_len < sizeof ( *ipv4 ) ) - return -EINVAL; - return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) ); +__weak int format_ipv6_setting ( const struct setting_type *type __unused, + const void *raw __unused, + size_t raw_len __unused, char *buf __unused, + size_t len __unused ) { + return -ENOTSUP; } -/** An IPv4 address setting type */ -struct setting_type setting_type_ipv4 __setting_type = { - .name = "ipv4", - .parse = parse_ipv4_setting, - .format = format_ipv4_setting, +/** An IPv6 address setting type */ +const struct setting_type setting_type_ipv6 __setting_type = { + .name = "ipv6", + .parse = parse_ipv6_setting, + .format = format_ipv6_setting, }; +/** IPv6 settings scope */ +const struct settings_scope ipv6_scope; + /** - * Parse integer setting value + * Integer setting type indices * - * @v value Formatted setting value + * These indexes are defined such that (1<<index) gives the width of + * the integer, in bytes. + */ +enum setting_type_int_index { + SETTING_TYPE_INT8 = 0, + SETTING_TYPE_INT16 = 1, + SETTING_TYPE_INT32 = 2, +}; + +/** + * Integer setting type names + * + * These names exist as a static array in order to allow the type's + * integer size and signedness to be determined from the type's name. + * Note that there are no separate entries for the signed integer + * types: the name pointers simply point to the second character of + * the relevant string. + */ +static const char setting_type_int_name[][8] = { + [SETTING_TYPE_INT8] = "uint8", + [SETTING_TYPE_INT16] = "uint16", + [SETTING_TYPE_INT32] = "uint32", +}; + +/** + * Get unsigned integer setting type name + * + * @v index Integer setting type index + * @ret name Setting type name + */ +#define SETTING_TYPE_UINT_NAME( index ) setting_type_int_name[index] + +/** + * Get signed integer setting type name + * + * @v index Integer setting type index + * @ret name Setting type name + */ +#define SETTING_TYPE_INT_NAME( index ) ( setting_type_int_name[index] + 1 ) + +/** + * Get integer setting type index + * + * @v type Setting type + * @ret index Integer setting type index + */ +static unsigned int setting_type_int_index ( const struct setting_type *type ) { + + return ( ( type->name - setting_type_int_name[0] ) / + sizeof ( setting_type_int_name[0] ) ); +} + +/** + * Get integer setting type width + * + * @v type Setting type + * @ret index Integer setting type width + */ +static unsigned int setting_type_int_width ( const struct setting_type *type ) { + + return ( 1 << setting_type_int_index ( type ) ); +} + +/** + * Get integer setting type signedness + * + * @v type Setting type + * @ret is_signed Integer setting type is signed + */ +static int setting_type_int_is_signed ( const struct setting_type *type ) { + return ( ( type->name - setting_type_int_name[0] ) & 1 ); +} + +/** + * Convert number to setting value + * + * @v type Setting type + * @v value Numeric value * @v buf Buffer to contain raw value * @v len Length of buffer - * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_int_setting ( const char *value, void *buf, size_t len, - unsigned int size ) { +static int denumerate_int_setting ( const struct setting_type *type, + unsigned long value, void *buf, + size_t len ) { + unsigned int size = setting_type_int_width ( type ); union { uint32_t num; uint8_t bytes[4]; } u; - char *endp; - - /* Parse value */ - u.num = htonl ( strtoul ( value, &endp, 0 ) ); - if ( *endp ) - return -EINVAL; - /* Copy to buffer */ + u.num = htonl ( value ); if ( len > size ) len = size; memcpy ( buf, &u.bytes[ sizeof ( u ) - size ], len ); @@ -1556,64 +1853,70 @@ static int parse_int_setting ( const char *value, void *buf, size_t len, } /** - * Parse 8-bit integer setting value + * Convert setting value to number * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @v size Integer size, in bytes - * @ret len Length of raw value, or negative error + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v value Numeric value to fill in + * @ret rc Return status code */ -static int parse_int8_setting ( const char *value, void *buf, size_t len ) { - return parse_int_setting ( value, buf, len, sizeof ( uint8_t ) ); -} +static int numerate_int_setting ( const struct setting_type *type, + const void *raw, size_t raw_len, + unsigned long *value ) { + int is_signed = setting_type_int_is_signed ( type ); + int check_len; -/** - * Parse 16-bit integer setting value - * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @v size Integer size, in bytes - * @ret len Length of raw value, or negative error - */ -static int parse_int16_setting ( const char *value, void *buf, size_t len ) { - return parse_int_setting ( value, buf, len, sizeof ( uint16_t ) ); + /* Extract numeric value */ + check_len = numeric_setting_value ( is_signed, raw, raw_len, value ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == ( int ) raw_len ); + + return 0; } /** - * Parse 32-bit integer setting value + * Parse integer setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer - * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_int32_setting ( const char *value, void *buf, size_t len ) { - return parse_int_setting ( value, buf, len, sizeof ( uint32_t ) ); +static int parse_int_setting ( const struct setting_type *type, + const char *value, void *buf, size_t len ) { + char *endp; + unsigned long num_value; + + /* Parse value */ + num_value = strtoul ( value, &endp, 0 ); + if ( *endp ) + return -EINVAL; + + return type->denumerate ( type, num_value, buf, len ); } /** * Format signed integer setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_int_setting ( const void *raw, size_t raw_len, char *buf, - size_t len ) { - signed long value; - unsigned long dummy; - int check_len; +static int format_int_setting ( const struct setting_type *type, + const void *raw, size_t raw_len, + char *buf, size_t len ) { + unsigned long value; + int ret; /* Extract numeric value */ - check_len = numeric_setting_value ( raw, raw_len, &value, &dummy ); - if ( check_len < 0 ) - return check_len; - assert ( check_len == ( int ) raw_len ); + if ( ( ret = type->numerate ( type, raw, raw_len, &value ) ) < 0 ) + return ret; /* Format value */ return snprintf ( buf, len, "%ld", value ); @@ -1622,113 +1925,91 @@ static int format_int_setting ( const void *raw, size_t raw_len, char *buf, /** * Format unsigned integer setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_uint_setting ( const void *raw, size_t raw_len, char *buf, - size_t len ) { - signed long dummy; +static int format_uint_setting ( const struct setting_type *type, + const void *raw, size_t raw_len, + char *buf, size_t len ) { unsigned long value; - int check_len; + int ret; /* Extract numeric value */ - check_len = numeric_setting_value ( raw, raw_len, &dummy, &value ); - if ( check_len < 0 ) - return check_len; - assert ( check_len == ( int ) raw_len ); + if ( ( ret = type->numerate ( type, raw, raw_len, &value ) ) < 0 ) + return ret; /* Format value */ return snprintf ( buf, len, "%#lx", value ); } +/** + * Define a signed integer setting type + * + * @v index Integer setting type index + * @ret type Setting type + */ +#define SETTING_TYPE_INT( index ) { \ + .name = SETTING_TYPE_INT_NAME ( index ), \ + .parse = parse_int_setting, \ + .format = format_int_setting, \ + .denumerate = denumerate_int_setting, \ + .numerate = numerate_int_setting, \ +} + +/** + * Define an unsigned integer setting type + * + * @v index Integer setting type index + * @ret type Setting type + */ +#define SETTING_TYPE_UINT( index ) { \ + .name = SETTING_TYPE_UINT_NAME ( index ), \ + .parse = parse_int_setting, \ + .format = format_uint_setting, \ + .denumerate = denumerate_int_setting, \ + .numerate = numerate_int_setting, \ +} + /** A signed 8-bit integer setting type */ -struct setting_type setting_type_int8 __setting_type = { - .name = "int8", - .parse = parse_int8_setting, - .format = format_int_setting, -}; +const struct setting_type setting_type_int8 __setting_type = + SETTING_TYPE_INT ( SETTING_TYPE_INT8 ); /** A signed 16-bit integer setting type */ -struct setting_type setting_type_int16 __setting_type = { - .name = "int16", - .parse = parse_int16_setting, - .format = format_int_setting, -}; +const struct setting_type setting_type_int16 __setting_type = + SETTING_TYPE_INT ( SETTING_TYPE_INT16 ); /** A signed 32-bit integer setting type */ -struct setting_type setting_type_int32 __setting_type = { - .name = "int32", - .parse = parse_int32_setting, - .format = format_int_setting, -}; +const struct setting_type setting_type_int32 __setting_type = + SETTING_TYPE_INT ( SETTING_TYPE_INT32 ); /** An unsigned 8-bit integer setting type */ -struct setting_type setting_type_uint8 __setting_type = { - .name = "uint8", - .parse = parse_int8_setting, - .format = format_uint_setting, -}; +const struct setting_type setting_type_uint8 __setting_type = + SETTING_TYPE_UINT ( SETTING_TYPE_INT8 ); /** An unsigned 16-bit integer setting type */ -struct setting_type setting_type_uint16 __setting_type = { - .name = "uint16", - .parse = parse_int16_setting, - .format = format_uint_setting, -}; +const struct setting_type setting_type_uint16 __setting_type = + SETTING_TYPE_UINT ( SETTING_TYPE_INT16 ); /** An unsigned 32-bit integer setting type */ -struct setting_type setting_type_uint32 __setting_type = { - .name = "uint32", - .parse = parse_int32_setting, - .format = format_uint_setting, -}; - -/** - * Parse hex string setting value - * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @ret len Length of raw value, or negative error - */ -static int parse_hex_setting ( const char *value, void *buf, size_t len ) { - char *ptr = ( char * ) value; - uint8_t *bytes = buf; - unsigned int count = 0; - uint8_t byte; - - while ( 1 ) { - byte = strtoul ( ptr, &ptr, 16 ); - if ( count++ < len ) - *bytes++ = byte; - switch ( *ptr ) { - case '\0' : - return count; - case ':' : - case '-' : - ptr++; - break; - default : - return -EINVAL; - } - } -} +const struct setting_type setting_type_uint32 __setting_type = + SETTING_TYPE_UINT ( SETTING_TYPE_INT32 ); /** * Format hex string setting value * + * @v delimiter Byte delimiter * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer - * @v delimiter Byte delimiter * @ret len Length of formatted value, or negative error */ -static int format_hex_setting ( const void *raw, size_t raw_len, char *buf, - size_t len, const char *delimiter ) { +static int format_hex_setting ( const char *delimiter, const void *raw, + size_t raw_len, char *buf, size_t len ) { const uint8_t *bytes = raw; int used = 0; unsigned int i; @@ -1744,70 +2025,132 @@ static int format_hex_setting ( const void *raw, size_t raw_len, char *buf, } /** + * Parse hex string setting value (using colon delimiter) + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @v size Integer size, in bytes + * @ret len Length of raw value, or negative error + */ +static int parse_hex_setting ( const struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { + return hex_decode ( value, ':', buf, len ); +} + +/** * Format hex string setting value (using colon delimiter) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_hex_colon_setting ( const void *raw, size_t raw_len, +static int format_hex_colon_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { - return format_hex_setting ( raw, raw_len, buf, len, ":" ); + return format_hex_setting ( ":", raw, raw_len, buf, len ); +} + +/** + * Parse hex string setting value (using hyphen delimiter) + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @v size Integer size, in bytes + * @ret len Length of raw value, or negative error + */ +static int parse_hex_hyphen_setting ( const struct setting_type *type __unused, + const char *value, void *buf, + size_t len ) { + return hex_decode ( value, '-', buf, len ); } /** * Format hex string setting value (using hyphen delimiter) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_hex_hyphen_setting ( const void *raw, size_t raw_len, +static int format_hex_hyphen_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { - return format_hex_setting ( raw, raw_len, buf, len, "-" ); + return format_hex_setting ( "-", raw, raw_len, buf, len ); +} + +/** + * Parse hex string setting value (using no delimiter) + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @v size Integer size, in bytes + * @ret len Length of raw value, or negative error + */ +static int parse_hex_raw_setting ( const struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { + return hex_decode ( value, 0, buf, len ); +} + +/** + * Format hex string setting value (using no delimiter) + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int format_hex_raw_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, + char *buf, size_t len ) { + return format_hex_setting ( "", raw, raw_len, buf, len ); } /** A hex-string setting (colon-delimited) */ -struct setting_type setting_type_hex __setting_type = { +const struct setting_type setting_type_hex __setting_type = { .name = "hex", .parse = parse_hex_setting, .format = format_hex_colon_setting, }; /** A hex-string setting (hyphen-delimited) */ -struct setting_type setting_type_hexhyp __setting_type = { +const struct setting_type setting_type_hexhyp __setting_type = { .name = "hexhyp", - .parse = parse_hex_setting, + .parse = parse_hex_hyphen_setting, .format = format_hex_hyphen_setting, }; -/** - * Parse UUID setting value - * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @ret len Length of raw value, or negative error - */ -static int parse_uuid_setting ( const char *value __unused, - void *buf __unused, size_t len __unused ) { - return -ENOTSUP; -} +/** A hex-string setting (non-delimited) */ +const struct setting_type setting_type_hexraw __setting_type = { + .name = "hexraw", + .parse = parse_hex_raw_setting, + .format = format_hex_raw_setting, +}; /** * Format UUID setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf, +static int format_uuid_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { const union uuid *uuid = raw; @@ -1820,12 +2163,44 @@ static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf, } /** UUID setting type */ -struct setting_type setting_type_uuid __setting_type = { +const struct setting_type setting_type_uuid __setting_type = { .name = "uuid", - .parse = parse_uuid_setting, .format = format_uuid_setting, }; +/** + * Format PCI bus:dev.fn setting value + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int format_busdevfn_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, + size_t len ) { + unsigned long busdevfn; + int check_len; + + /* Extract numeric value */ + check_len = numeric_setting_value ( 0, raw, raw_len, &busdevfn ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == ( int ) raw_len ); + + /* Format value */ + return snprintf ( buf, len, "%02lx:%02lx.%lx", PCI_BUS ( busdevfn ), + PCI_SLOT ( busdevfn ), PCI_FUNC ( busdevfn ) ); +} + +/** PCI bus:dev.fn setting type */ +const struct setting_type setting_type_busdevfn __setting_type = { + .name = "busdevfn", + .format = format_busdevfn_setting, +}; + /****************************************************************************** * * Setting expansion @@ -1843,15 +2218,18 @@ struct setting_type setting_type_uuid __setting_type = { * eventually free() it. */ char * expand_settings ( const char *string ) { + struct settings *settings; + struct setting setting; char *expstr; char *start; char *end; char *head; char *name; char *tail; - int setting_len; - int new_len; + char *value; char *tmp; + int new_len; + int rc; /* Obtain temporary modifiable copy of string */ expstr = strdup ( string ); @@ -1881,27 +2259,28 @@ char * expand_settings ( const char *string ) { *end = '\0'; tail = ( end + 1 ); - /* Determine setting length */ - setting_len = fetchf_named_setting ( name, NULL, 0, NULL, 0 ); - if ( setting_len < 0 ) - setting_len = 0; /* Treat error as empty setting */ - - /* Read setting into temporary buffer */ - { - char setting_buf[ setting_len + 1 ]; - - setting_buf[0] = '\0'; - fetchf_named_setting ( name, NULL, 0, setting_buf, - sizeof ( setting_buf ) ); - - /* Construct expanded string and discard old string */ - tmp = expstr; - new_len = asprintf ( &expstr, "%s%s%s", - head, setting_buf, tail ); - free ( tmp ); - if ( new_len < 0 ) - return NULL; + /* Expand setting */ + if ( ( rc = parse_setting_name ( name, find_child_settings, + &settings, + &setting ) ) != 0 ) { + /* Treat invalid setting names as empty */ + value = NULL; + } else { + /* Fetch and format setting value. Ignore + * errors; treat non-existent settings as empty. + */ + fetchf_setting_copy ( settings, &setting, NULL, NULL, + &value ); } + + /* Construct expanded string and discard old string */ + tmp = expstr; + new_len = asprintf ( &expstr, "%s%s%s", + head, ( value ? value : "" ), tail ); + free ( value ); + free ( tmp ); + if ( new_len < 0 ) + return NULL; } return expstr; @@ -1915,7 +2294,7 @@ char * expand_settings ( const char *string ) { */ /** Hostname setting */ -struct setting hostname_setting __setting ( SETTING_HOST ) = { +const struct setting hostname_setting __setting ( SETTING_HOST, hostname ) = { .name = "hostname", .description = "Host name", .tag = DHCP_HOST_NAME, @@ -1923,7 +2302,7 @@ struct setting hostname_setting __setting ( SETTING_HOST ) = { }; /** Domain name setting */ -struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ) = { +const struct setting domain_setting __setting ( SETTING_IP_EXTRA, domain ) = { .name = "domain", .description = "DNS domain", .tag = DHCP_DOMAIN_NAME, @@ -1931,7 +2310,7 @@ struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ) = { }; /** TFTP server setting */ -struct setting next_server_setting __setting ( SETTING_BOOT ) = { +const struct setting next_server_setting __setting ( SETTING_BOOT,next-server)={ .name = "next-server", .description = "TFTP server", .tag = DHCP_EB_SIADDR, @@ -1939,7 +2318,7 @@ struct setting next_server_setting __setting ( SETTING_BOOT ) = { }; /** Filename setting */ -struct setting filename_setting __setting ( SETTING_BOOT ) = { +const struct setting filename_setting __setting ( SETTING_BOOT, filename ) = { .name = "filename", .description = "Boot filename", .tag = DHCP_BOOTFILE_NAME, @@ -1947,7 +2326,7 @@ struct setting filename_setting __setting ( SETTING_BOOT ) = { }; /** Root path setting */ -struct setting root_path_setting __setting ( SETTING_SANBOOT ) = { +const struct setting root_path_setting __setting ( SETTING_SANBOOT, root-path)={ .name = "root-path", .description = "SAN root path", .tag = DHCP_ROOT_PATH, @@ -1955,7 +2334,7 @@ struct setting root_path_setting __setting ( SETTING_SANBOOT ) = { }; /** Username setting */ -struct setting username_setting __setting ( SETTING_AUTH ) = { +const struct setting username_setting __setting ( SETTING_AUTH, username ) = { .name = "username", .description = "User name", .tag = DHCP_EB_USERNAME, @@ -1963,7 +2342,7 @@ struct setting username_setting __setting ( SETTING_AUTH ) = { }; /** Password setting */ -struct setting password_setting __setting ( SETTING_AUTH ) = { +const struct setting password_setting __setting ( SETTING_AUTH, password ) = { .name = "password", .description = "Password", .tag = DHCP_EB_PASSWORD, @@ -1971,13 +2350,22 @@ struct setting password_setting __setting ( SETTING_AUTH ) = { }; /** Priority setting */ -struct setting priority_setting __setting ( SETTING_MISC ) = { +const struct setting priority_setting __setting ( SETTING_MISC, priority ) = { .name = "priority", .description = "Settings priority", .tag = DHCP_EB_PRIORITY, .type = &setting_type_int8, }; +/** DHCP user class setting */ +const struct setting user_class_setting __setting ( SETTING_HOST_EXTRA, + user-class ) = { + .name = "user-class", + .description = "DHCP user class", + .tag = DHCP_USER_CLASS_ID, + .type = &setting_type_string, +}; + /****************************************************************************** * * Built-in settings block @@ -1985,68 +2373,142 @@ struct setting priority_setting __setting ( SETTING_MISC ) = { ****************************************************************************** */ -/** Built-in setting tag magic */ -#define BUILTIN_SETTING_TAG_MAGIC 0xb1 +/** Built-in setting scope */ +const struct settings_scope builtin_scope; /** - * Construct built-in setting tag + * Fetch error number setting * - * @v id Unique identifier - * @ret tag Setting tag + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error */ -#define BUILTIN_SETTING_TAG( id ) ( ( BUILTIN_SETTING_TAG_MAGIC << 24 ) | (id) ) +static int errno_fetch ( void *data, size_t len ) { + uint32_t content; -/** "errno" setting tag */ -#define BUILTIN_SETTING_TAG_ERRNO BUILTIN_SETTING_TAG ( 0x01 ) + /* Return current error */ + content = htonl ( errno ); + if ( len > sizeof ( content ) ) + len = sizeof ( content ); + memcpy ( data, &content, len ); + return sizeof ( content ); +} /** Error number setting */ -struct setting errno_setting __setting ( SETTING_MISC ) = { +const struct setting errno_setting __setting ( SETTING_MISC, errno ) = { .name = "errno", .description = "Last error", - .tag = BUILTIN_SETTING_TAG_ERRNO, .type = &setting_type_uint32, + .scope = &builtin_scope, +}; + +/** Error number built-in setting */ +struct builtin_setting errno_builtin_setting __builtin_setting = { + .setting = &errno_setting, + .fetch = errno_fetch, }; /** - * Fetch error number setting + * Fetch build architecture setting * - * @v settings Settings block - * @v setting Setting to fetch - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error */ -static int errno_fetch ( struct settings *settings __unused, - struct setting *setting __unused, - void *data, size_t len ) { - uint32_t content; +static int buildarch_fetch ( void *data, size_t len ) { + static const char buildarch[] = _S2 ( ARCH ); - /* Return current error */ - content = htonl ( errno ); - if ( len > sizeof ( content ) ) - len = sizeof ( content ); - memcpy ( data, &content, len ); - return sizeof ( content ); + strncpy ( data, buildarch, len ); + return ( sizeof ( buildarch ) - 1 /* NUL */ ); +} + +/** Build architecture setting */ +const struct setting buildarch_setting __setting ( SETTING_MISC, buildarch ) = { + .name = "buildarch", + .description = "Build architecture", + .type = &setting_type_string, + .scope = &builtin_scope, +}; + +/** Build architecture built-in setting */ +struct builtin_setting buildarch_builtin_setting __builtin_setting = { + .setting = &buildarch_setting, + .fetch = buildarch_fetch, +}; + +/** + * Fetch platform setting + * + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int platform_fetch ( void *data, size_t len ) { + static const char platform[] = _S2 ( PLATFORM ); + + strncpy ( data, platform, len ); + return ( sizeof ( platform ) - 1 /* NUL */ ); +} + +/** Platform setting */ +const struct setting platform_setting __setting ( SETTING_MISC, platform ) = { + .name = "platform", + .description = "Platform", + .type = &setting_type_string, + .scope = &builtin_scope, +}; + +/** Platform built-in setting */ +struct builtin_setting platform_builtin_setting __builtin_setting = { + .setting = &platform_setting, + .fetch = platform_fetch, +}; + +/** + * Fetch version setting + * + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int version_fetch ( void *data, size_t len ) { + strncpy ( data, product_version, len ); + return ( strlen ( product_version ) ); } +/** Version setting */ +const struct setting version_setting __setting ( SETTING_MISC, version ) = { + .name = "version", + .description = "Version", + .type = &setting_type_string, + .scope = &builtin_scope, +}; + +/** Version built-in setting */ +struct builtin_setting version_builtin_setting __builtin_setting = { + .setting = &version_setting, + .fetch = version_fetch, +}; + /** * Fetch built-in setting * * @v settings Settings block * @v setting Setting to fetch - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error */ static int builtin_fetch ( struct settings *settings __unused, struct setting *setting, void *data, size_t len ) { + struct builtin_setting *builtin; - if ( setting_cmp ( setting, &errno_setting ) == 0 ) { - return errno_fetch ( settings, setting, data, len ); - } else { - return -ENOENT; + for_each_table_entry ( builtin, BUILTIN_SETTINGS ) { + if ( setting_cmp ( setting, builtin->setting ) == 0 ) + return builtin->fetch ( data, len ); } + return -ENOENT; } /** @@ -2057,12 +2519,9 @@ static int builtin_fetch ( struct settings *settings __unused, * @ret applies Setting applies within this settings block */ static int builtin_applies ( struct settings *settings __unused, - struct setting *setting ) { - unsigned int tag_magic; + const struct setting *setting ) { - /* Check tag magic */ - tag_magic = ( setting->tag >> 24 ); - return ( tag_magic == BUILTIN_SETTING_TAG_MAGIC ); + return ( setting->scope == &builtin_scope ); } /** Built-in settings operations */ @@ -2074,7 +2533,6 @@ static struct settings_operations builtin_settings_operations = { /** Built-in settings */ static struct settings builtin_settings = { .refcnt = NULL, - .tag_magic = BUILTIN_SETTING_TAG ( 0 ), .siblings = LIST_HEAD_INIT ( builtin_settings.siblings ), .children = LIST_HEAD_INIT ( builtin_settings.children ), .op = &builtin_settings_operations, diff --git a/roms/ipxe/src/core/uri.c b/roms/ipxe/src/core/uri.c index e95268826..9ec21cee4 100644 --- a/roms/ipxe/src/core/uri.c +++ b/roms/ipxe/src/core/uri.c @@ -31,34 +31,199 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <libgen.h> #include <ctype.h> #include <ipxe/vsprintf.h> +#include <ipxe/params.h> #include <ipxe/uri.h> /** + * Decode URI field (in place) + * + * @v string String + * + * URI decoding can never increase the length of a string; we can + * therefore safely decode in place. + */ +static void uri_decode ( char *string ) { + char *dest = string; + char hexbuf[3]; + char *hexbuf_end; + char c; + char decoded; + unsigned int skip; + + /* Copy string, decoding escaped characters as necessary */ + do { + c = *(string++); + if ( c == '%' ) { + snprintf ( hexbuf, sizeof ( hexbuf ), "%s", string ); + decoded = strtoul ( hexbuf, &hexbuf_end, 16 ); + skip = ( hexbuf_end - hexbuf ); + string += skip; + if ( skip ) + c = decoded; + } + *(dest++) = c; + } while ( c ); +} + +/** + * Check if character should be escaped within a URI field + * + * @v c Character + * @v field URI field index + * @ret escaped Character should be escaped + */ +static int uri_character_escaped ( char c, unsigned int field ) { + + /* Non-printing characters and whitespace should always be + * escaped, since they cannot sensibly be displayed as part of + * a coherent URL string. (This test also catches control + * characters such as CR and LF, which could affect the + * operation of line-based protocols such as HTTP.) + * + * We should also escape characters which would alter the + * interpretation of the URL if not escaped, i.e. characters + * which have significance to the URL parser. We should not + * blindly escape all such characters, because this would lead + * to some very strange-looking URLs (e.g. if we were to + * always escape '/' as "%2F" even within the URI path). + * + * We do not need to be perfect. Our primary role is as a + * consumer of URIs rather than a producer; the main situation + * in which we produce a URI string is for display to a human + * user, who can probably tolerate some variance from the + * formal specification. The only situation in which we + * currently produce a URI string to be consumed by a computer + * is when constructing an HTTP request URI, which contains + * only the path and query fields. + * + * We can therefore sacrifice some correctness for the sake of + * code size. For example, colons within the URI host should + * be escaped unless they form part of an IPv6 literal + * address; doing this correctly would require the URI + * formatter to be aware of whether or not the URI host + * contained an IPv4 address, an IPv6 address, or a host name. + * We choose to simplify and never escape colons within the + * URI host field: in the event of a pathological hostname + * containing colons, this could potentially produce a URI + * string which could not be reparsed. + * + * After excluding non-printing characters, whitespace, and + * '%', the full set of characters with significance to the + * URL parser is "/#:@?". We choose for each URI field which + * of these require escaping in our use cases. + */ + static const char *escaped[URI_FIELDS] = { + /* Scheme: escape everything */ + [URI_SCHEME] = "/#:@?", + /* Opaque part: escape characters which would affect + * the reparsing of the URI, allowing everything else + * (e.g. ':', which will appear in iSCSI URIs). + */ + [URI_OPAQUE] = "/#", + /* User name: escape everything */ + [URI_USER] = "/#:@?", + /* Password: escape everything */ + [URI_PASSWORD] = "/#:@?", + /* Host name: escape everything except ':', which may + * appear as part of an IPv6 literal address. + */ + [URI_HOST] = "/#@?", + /* Port number: escape everything */ + [URI_PORT] = "/#:@?", + /* Path: escape everything except '/', which usually + * appears within paths. + */ + [URI_PATH] = "#:@?", + /* Query: escape everything except '/', which + * sometimes appears within queries. + */ + [URI_QUERY] = "#:@?", + /* Fragment: escape everything */ + [URI_FRAGMENT] = "/#:@?", + }; + + return ( /* Always escape non-printing characters and whitespace */ + ( ! isprint ( c ) ) || ( c == ' ' ) || + /* Always escape '%' */ + ( c == '%' ) || + /* Escape field-specific characters */ + strchr ( escaped[field], c ) ); +} + +/** + * Encode URI field + * + * @v uri URI + * @v field URI field index + * @v buf Buffer to contain encoded string + * @v len Length of buffer + * @ret len Length of encoded string (excluding NUL) + */ +size_t uri_encode ( const char *string, unsigned int field, + char *buf, ssize_t len ) { + ssize_t remaining = len; + size_t used; + char c; + + /* Ensure encoded string is NUL-terminated even if empty */ + if ( len > 0 ) + buf[0] = '\0'; + + /* Copy string, escaping as necessary */ + while ( ( c = *(string++) ) ) { + if ( uri_character_escaped ( c, field ) ) { + used = ssnprintf ( buf, remaining, "%%%02X", c ); + } else { + used = ssnprintf ( buf, remaining, "%c", c ); + } + buf += used; + remaining -= used; + } + + return ( len - remaining ); +} + +/** * Dump URI for debugging * * @v uri URI */ -static void dump_uri ( struct uri *uri ) { +static void uri_dump ( const struct uri *uri ) { + if ( ! uri ) return; if ( uri->scheme ) - DBG ( " scheme \"%s\"", uri->scheme ); + DBGC ( uri, " scheme \"%s\"", uri->scheme ); if ( uri->opaque ) - DBG ( " opaque \"%s\"", uri->opaque ); + DBGC ( uri, " opaque \"%s\"", uri->opaque ); if ( uri->user ) - DBG ( " user \"%s\"", uri->user ); + DBGC ( uri, " user \"%s\"", uri->user ); if ( uri->password ) - DBG ( " password \"%s\"", uri->password ); + DBGC ( uri, " password \"%s\"", uri->password ); if ( uri->host ) - DBG ( " host \"%s\"", uri->host ); + DBGC ( uri, " host \"%s\"", uri->host ); if ( uri->port ) - DBG ( " port \"%s\"", uri->port ); + DBGC ( uri, " port \"%s\"", uri->port ); if ( uri->path ) - DBG ( " path \"%s\"", uri->path ); + DBGC ( uri, " path \"%s\"", uri->path ); if ( uri->query ) - DBG ( " query \"%s\"", uri->query ); + DBGC ( uri, " query \"%s\"", uri->query ); if ( uri->fragment ) - DBG ( " fragment \"%s\"", uri->fragment ); + DBGC ( uri, " fragment \"%s\"", uri->fragment ); + if ( uri->params ) + DBGC ( uri, " params \"%s\"", uri->params->name ); +} + +/** + * Free URI + * + * @v refcnt Reference count + */ +static void uri_free ( struct refcnt *refcnt ) { + struct uri *uri = container_of ( refcnt, struct uri, refcnt ); + + params_put ( uri->params ); + free ( uri ); } /** @@ -73,35 +238,45 @@ static void dump_uri ( struct uri *uri ) { */ struct uri * parse_uri ( const char *uri_string ) { struct uri *uri; + struct parameters *params; char *raw; char *tmp; char *path; char *authority; - int i; size_t raw_len; + unsigned int field; /* Allocate space for URI struct and a copy of the string */ raw_len = ( strlen ( uri_string ) + 1 /* NUL */ ); uri = zalloc ( sizeof ( *uri ) + raw_len ); if ( ! uri ) return NULL; - raw = ( ( ( char * ) uri ) + sizeof ( *uri ) ); + ref_init ( &uri->refcnt, uri_free ); + raw = ( ( ( void * ) uri ) + sizeof ( *uri ) ); /* Copy in the raw string */ memcpy ( raw, uri_string, raw_len ); - /* Start by chopping off the fragment, if it exists */ + /* Identify the parameter list, if present */ + if ( ( tmp = strstr ( raw, "##params" ) ) ) { + *tmp = '\0'; + tmp += 8 /* "##params" */; + params = find_parameters ( *tmp ? ( tmp + 1 ) : NULL ); + if ( params ) { + uri->params = claim_parameters ( params ); + } else { + /* Ignore non-existent submission blocks */ + } + } + + /* Chop off the fragment, if it exists */ if ( ( tmp = strchr ( raw, '#' ) ) ) { *(tmp++) = '\0'; uri->fragment = tmp; } - /* Identify absolute/relative URI. We ignore schemes that are - * apparently only a single character long, since otherwise we - * misinterpret a DOS-style path name ("C:\path\to\file") as a - * URI with scheme="C",opaque="\path\to\file". - */ - if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) { + /* Identify absolute/relative URI */ + if ( ( tmp = strchr ( raw, ':' ) ) ) { /* Absolute URI: identify hierarchical/opaque */ uri->scheme = raw; *(tmp++) = '\0'; @@ -130,6 +305,12 @@ struct uri * parse_uri ( const char *uri_string ) { uri->query = tmp; } + /* If we have no path remaining, then we're already finished + * processing. + */ + if ( ! path[0] ) + goto done; + /* Identify net/absolute/relative path */ if ( strncmp ( path, "//", 2 ) == 0 ) { /* Net path. If this is terminated by the first '/' @@ -176,23 +357,22 @@ struct uri * parse_uri ( const char *uri_string ) { } /* Split host into host[:port] */ - if ( ( tmp = strchr ( uri->host, ':' ) ) ) { + if ( ( uri->host[ strlen ( uri->host ) - 1 ] != ']' ) && + ( tmp = strrchr ( uri->host, ':' ) ) ) { *(tmp++) = '\0'; 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 */ ); + /* Decode fields in-place */ + for ( field = 0 ; field < URI_FIELDS ; field++ ) { + if ( uri_field ( uri, field ) ) + uri_decode ( ( char * ) uri_field ( uri, field ) ); } done: - DBG ( "URI \"%s\" split into", uri_string ); - dump_uri ( uri ); - DBG ( "\n" ); + DBGC ( uri, "URI parsed \"%s\" to", uri_string ); + uri_dump ( uri ); + DBGC ( uri, "\n" ); return uri; } @@ -204,83 +384,138 @@ struct uri * parse_uri ( const char *uri_string ) { * @v default_port Default port to use if none specified in URI * @ret port Port */ -unsigned int uri_port ( struct uri *uri, unsigned int default_port ) { +unsigned int uri_port ( const struct uri *uri, unsigned int default_port ) { + if ( ( ! uri ) || ( ! uri->port ) ) return default_port; + return ( strtoul ( uri->port, NULL, 0 ) ); } /** - * Unparse URI + * Format URI * + * @v uri URI * @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, - 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" ); +size_t format_uri ( const struct uri *uri, char *buf, size_t len ) { + static const char prefixes[URI_FIELDS] = { + [URI_OPAQUE] = ':', + [URI_PASSWORD] = ':', + [URI_PORT] = ':', + [URI_PATH] = '/', + [URI_QUERY] = '?', + [URI_FRAGMENT] = '#', + }; + char prefix; + size_t used = 0; + unsigned int field; /* Ensure buffer is NUL-terminated */ - if ( size ) + if ( len ) buf[0] = '\0'; /* Special-case NULL URI */ if ( ! uri ) return 0; - /* 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; - } + /* Generate fields */ + for ( field = 0 ; field < URI_FIELDS ; field++ ) { + + /* Skip non-existent fields */ + if ( ! uri_field ( uri, field ) ) + continue; + + /* Prefix this field, if applicable */ + prefix = prefixes[field]; + if ( ( field == URI_HOST ) && ( uri->user != NULL ) ) + prefix = '@'; + if ( ( field == URI_PATH ) && ( uri->path[0] == '/' ) ) + prefix = '\0'; + if ( prefix ) { + used += ssnprintf ( ( buf + used ), ( len - used ), + "%c", prefix ); + } + + /* Encode this field */ + used += uri_encode ( uri_field ( uri, field ), field, + ( buf + used ), ( len - used ) ); - /* 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 ); + /* Suffix this field, if applicable */ + if ( ( field == URI_SCHEME ) && ( ! uri->opaque ) ) { + used += ssnprintf ( ( buf + used ), ( len - used ), + "://" ); } } + if ( len ) { + DBGC ( uri, "URI formatted" ); + uri_dump ( uri ); + DBGC ( uri, " to \"%s%s\"\n", buf, + ( ( used > len ) ? "<TRUNCATED>" : "" ) ); + } + return used; } /** + * Format URI + * + * @v uri URI + * @ret string URI string, or NULL on failure + * + * The caller is responsible for eventually freeing the allocated + * memory. + */ +char * format_uri_alloc ( const struct uri *uri ) { + size_t len; + char *string; + + len = ( format_uri ( uri, NULL, 0 ) + 1 /* NUL */ ); + string = malloc ( len ); + if ( string ) + format_uri ( uri, string, len ); + return string; +} + +/** + * Copy URI fields + * + * @v src Source URI + * @v dest Destination URI, or NULL to calculate length + * @ret len Length of raw URI + */ +static size_t uri_copy_fields ( const struct uri *src, struct uri *dest ) { + size_t len = sizeof ( *dest ); + char *out = ( ( void * ) dest + len ); + unsigned int field; + size_t field_len; + + /* Copy existent fields */ + for ( field = 0 ; field < URI_FIELDS ; field++ ) { + + /* Skip non-existent fields */ + if ( ! uri_field ( src, field ) ) + continue; + + /* Calculate field length */ + field_len = ( strlen ( uri_field ( src, field ) ) + + 1 /* NUL */ ); + len += field_len; + + /* Copy field, if applicable */ + if ( dest ) { + memcpy ( out, uri_field ( src, field ), field_len ); + uri_field ( dest, field ) = out; + out += field_len; + } + } + return len; +} + +/** * Duplicate URI * * @v uri URI @@ -288,12 +523,28 @@ 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, URI_ALL ) + 1 ); - char buf[len]; +struct uri * uri_dup ( const struct uri *uri ) { + struct uri *dup; + size_t len; + + /* Allocate new URI */ + len = uri_copy_fields ( uri, NULL ); + dup = zalloc ( len ); + if ( ! dup ) + return NULL; + ref_init ( &dup->refcnt, uri_free ); + + /* Copy fields */ + uri_copy_fields ( uri, dup ); + + /* Copy parameters */ + dup->params = params_get ( uri->params ); + + DBGC ( uri, "URI duplicated" ); + uri_dump ( uri ); + DBGC ( uri, "\n" ); - unparse_uri ( buf, len, uri, URI_ALL ); - return parse_uri ( buf ); + return dup; } /** @@ -369,7 +620,7 @@ char * resolve_path ( const char *base_path, * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI * (e.g. "http://ipxe.org/initrds/initrd.gz"). */ -struct uri * resolve_uri ( struct uri *base_uri, +struct uri * resolve_uri ( const struct uri *base_uri, struct uri *relative_uri ) { struct uri tmp_uri; char *tmp_path = NULL; @@ -388,11 +639,16 @@ struct uri * resolve_uri ( struct uri *base_uri, tmp_uri.path = tmp_path; tmp_uri.query = relative_uri->query; tmp_uri.fragment = relative_uri->fragment; + tmp_uri.params = relative_uri->params; } else if ( relative_uri->query ) { tmp_uri.query = relative_uri->query; tmp_uri.fragment = relative_uri->fragment; + tmp_uri.params = relative_uri->params; } else if ( relative_uri->fragment ) { tmp_uri.fragment = relative_uri->fragment; + tmp_uri.params = relative_uri->params; + } else if ( relative_uri->params ) { + tmp_uri.params = relative_uri->params; } /* Create demangled URI */ @@ -402,100 +658,23 @@ struct uri * resolve_uri ( struct uri *base_uri, } /** - * Test for unreserved URI characters + * Construct TFTP URI from next-server and filename * - * @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, 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 - */ - 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; -} - -/** - * URI-encode string + * @v next_server Next-server address + * @v filename Filename + * @ret uri URI, or NULL on failure * - * @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) + * TFTP filenames specified via the DHCP next-server field often + * contain characters such as ':' or '#' which would confuse the + * generic URI parser. We provide a mechanism for directly + * constructing a TFTP URI from the next-server and filename. */ -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 > 0 ) - buf[0] = '\0'; - - while ( ( c = *(raw_string++) ) ) { - if ( is_unreserved_uri_char ( c, field ) ) { - used = ssnprintf ( buf, remaining, "%c", c ); - } else { - used = ssnprintf ( buf, remaining, "%%%02X", c ); - } - buf += used; - remaining -= used; - } - - return ( len - remaining ); -} - -/** - * Decode URI-encoded string - * - * @v encoded_string URI-encoded string - * @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, ssize_t len ) { - ssize_t remaining; - char hexbuf[3]; - char *hexbuf_end; - unsigned char c; - - for ( remaining = len; *encoded_string; remaining-- ) { - if ( *encoded_string == '%' ) { - encoded_string++; - snprintf ( hexbuf, sizeof ( hexbuf ), "%s", - encoded_string ); - c = strtoul ( hexbuf, &hexbuf_end, 16 ); - encoded_string += ( hexbuf_end - hexbuf ); - } else { - c = *(encoded_string++); - } - if ( remaining > 1 ) - *buf++ = c; - } - - if ( len ) - *buf = 0; - - return ( len - remaining ); +struct uri * tftp_uri ( struct in_addr next_server, const char *filename ) { + struct uri uri; + + memset ( &uri, 0, sizeof ( uri ) ); + uri.scheme = "tftp"; + uri.host = inet_ntoa ( next_server ); + uri.path = filename; + return uri_dup ( &uri ); } diff --git a/roms/ipxe/src/core/vsprintf.c b/roms/ipxe/src/core/vsprintf.c index 5cc723108..54811b11b 100644 --- a/roms/ipxe/src/core/vsprintf.c +++ b/roms/ipxe/src/core/vsprintf.c @@ -167,7 +167,7 @@ static char * format_decimal ( char *end, signed long num, int width, * Call's the printf_context::handler() method and increments * printf_context::len. */ -static inline void cputchar ( struct printf_context *ctx, unsigned int c ) { +static inline void cputchar ( struct printf_context *ctx, unsigned char c ) { ctx->handler ( ctx, c ); ++ctx->len; } diff --git a/roms/ipxe/src/crypto/certstore.c b/roms/ipxe/src/crypto/certstore.c new file mode 100644 index 000000000..77cf6ebb6 --- /dev/null +++ b/roms/ipxe/src/crypto/certstore.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <stdlib.h> +#include <ipxe/init.h> +#include <ipxe/dhcp.h> +#include <ipxe/settings.h> +#include <ipxe/malloc.h> +#include <ipxe/crypto.h> +#include <ipxe/asn1.h> +#include <ipxe/x509.h> +#include <ipxe/certstore.h> + +/** @file + * + * Certificate store + * + */ + +/** Raw certificate data for all permanent stored certificates */ +#undef CERT +#define CERT( _index, _path ) \ + extern char stored_cert_ ## _index ## _data[]; \ + extern char stored_cert_ ## _index ## _len[]; \ + __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" \ + "\nstored_cert_" #_index "_data:\n\t" \ + ".incbin \"" _path "\"\n\t" \ + "\nstored_cert_" #_index "_end:\n\t" \ + ".equ stored_cert_" #_index "_len, " \ + "( stored_cert_" #_index "_end - " \ + " stored_cert_" #_index "_data )\n\t" \ + ".previous\n\t" ); +CERT_ALL + +/** Raw certificate cursors for all permanent stored certificates */ +#undef CERT +#define CERT( _index, _path ) { \ + .data = stored_cert_ ## _index ## _data, \ + .len = ( size_t ) stored_cert_ ## _index ## _len, \ +}, +static struct asn1_cursor certstore_raw[] = { + CERT_ALL +}; + +/** X.509 certificate structures for all permanent stored certificates */ +static struct x509_certificate certstore_certs[ sizeof ( certstore_raw ) / + sizeof ( certstore_raw[0] ) ]; + +/** Certificate store */ +struct x509_chain certstore = { + .refcnt = REF_INIT ( ref_no_free ), + .links = LIST_HEAD_INIT ( certstore.links ), +}; + +/** + * Mark stored certificate as most recently used + * + * @v cert X.509 certificate + * @ret cert X.509 certificate + */ +static struct x509_certificate * +certstore_found ( struct x509_certificate *cert ) { + + /* Mark as most recently used */ + list_del ( &cert->store.list ); + list_add ( &cert->store.list, &certstore.links ); + DBGC2 ( &certstore, "CERTSTORE found certificate %s\n", + x509_name ( cert ) ); + + return cert; +} + +/** + * Find certificate in store + * + * @v raw Raw certificate data + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) { + struct x509_certificate *cert; + + /* Search for certificate within store */ + list_for_each_entry ( cert, &certstore.links, store.list ) { + if ( asn1_compare ( raw, &cert->raw ) == 0 ) + return certstore_found ( cert ); + } + return NULL; +} + +/** + * Find certificate in store corresponding to a private key + * + * @v key Private key + * @ret cert X.509 certificate, or NULL if not found + */ +struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ) { + struct x509_certificate *cert; + + /* Search for certificate within store */ + list_for_each_entry ( cert, &certstore.links, store.list ) { + if ( pubkey_match ( cert->signature_algorithm->pubkey, + key->data, key->len, + cert->subject.public_key.raw.data, + cert->subject.public_key.raw.len ) == 0 ) + return certstore_found ( cert ); + } + return NULL; +} + +/** + * Add certificate to store + * + * @v cert X.509 certificate + */ +void certstore_add ( struct x509_certificate *cert ) { + + /* Add certificate to store */ + cert->store.cert = cert; + x509_get ( cert ); + list_add ( &cert->store.list, &certstore.links ); + DBGC ( &certstore, "CERTSTORE added certificate %s\n", + x509_name ( cert ) ); +} + +/** + * Discard a stored certificate + * + * @ret discarded Number of cached items discarded + */ +static unsigned int certstore_discard ( void ) { + struct x509_certificate *cert; + + /* Discard the least recently used certificate for which the + * only reference is held by the store itself. + */ + list_for_each_entry_reverse ( cert, &certstore.links, store.list ) { + if ( cert->refcnt.count == 0 ) { + DBGC ( &certstore, "CERTSTORE discarded certificate " + "%s\n", x509_name ( cert ) ); + list_del ( &cert->store.list ); + x509_put ( cert ); + return 1; + } + } + return 0; +} + +/** Certificate store cache discarder */ +struct cache_discarder certstore_discarder __cache_discarder ( CACHE_NORMAL ) ={ + .discard = certstore_discard, +}; + +/** + * Construct permanent certificate store + * + */ +static void certstore_init ( void ) { + struct asn1_cursor *raw; + struct x509_certificate *cert; + int i; + int rc; + + /* Skip if we have no permanent stored certificates */ + if ( ! sizeof ( certstore_raw ) ) + return; + + /* Add certificates */ + for ( i = 0 ; i < ( int ) ( sizeof ( certstore_raw ) / + sizeof ( certstore_raw[0] ) ) ; i++ ) { + + /* Skip if certificate already present in store */ + raw = &certstore_raw[i]; + if ( ( cert = certstore_find ( raw ) ) != NULL ) { + DBGC ( &certstore, "CERTSTORE permanent certificate %d " + "is a duplicate of %s\n", i, x509_name ( cert )); + continue; + } + + /* Parse certificate */ + cert = &certstore_certs[i]; + ref_init ( &cert->refcnt, ref_no_free ); + if ( ( rc = x509_parse ( cert, raw ) ) != 0 ) { + DBGC ( &certstore, "CERTSTORE could not parse " + "permanent certificate %d: %s\n", + i, strerror ( rc ) ); + continue; + } + + /* Add certificate to store. Certificate will never + * be discarded from the store, since we retain a + * permanent reference to it. + */ + certstore_add ( cert ); + DBGC ( &certstore, "CERTSTORE permanent certificate %d is %s\n", + i, x509_name ( cert ) ); + } +} + +/** Certificate store initialisation function */ +struct init_fn certstore_init_fn __init_fn ( INIT_LATE ) = { + .initialise = certstore_init, +}; + +/** Additional certificate setting */ +static struct setting cert_setting __setting ( SETTING_CRYPTO, cert ) = { + .name = "cert", + .description = "Certificate", + .tag = DHCP_EB_CERT, + .type = &setting_type_hex, +}; + +/** + * Apply certificate store configuration settings + * + * @ret rc Return status code + */ +static int certstore_apply_settings ( void ) { + static struct x509_certificate *cert = NULL; + struct x509_certificate *old_cert; + void *cert_data; + int len; + int rc; + + /* Record any existing additional certificate */ + old_cert = cert; + cert = NULL; + + /* Add additional certificate, if any */ + if ( ( len = fetch_raw_setting_copy ( NULL, &cert_setting, + &cert_data ) ) >= 0 ) { + if ( ( rc = x509_certificate ( cert_data, len, &cert ) ) == 0 ){ + DBGC ( &certstore, "CERTSTORE added additional " + "certificate %s\n", x509_name ( cert ) ); + } else { + DBGC ( &certstore, "CERTSTORE could not parse " + "additional certificate: %s\n", + strerror ( rc ) ); + /* Do not fail; leave as an unusable certificate */ + } + free ( cert_data ); + } + + /* Free old additional certificiate. Do this after reparsing + * the additional certificate; in the common case that the + * certificate has not changed, this will allow the stored + * certificate to be reused. + */ + x509_put ( old_cert ); + + return 0; +} + +/** Certificate store settings applicator */ +struct settings_applicator certstore_applicator __settings_applicator = { + .apply = certstore_apply_settings, +}; diff --git a/roms/ipxe/src/crypto/clientcert.c b/roms/ipxe/src/crypto/clientcert.c deleted file mode 100644 index 5ce1f6c1a..000000000 --- a/roms/ipxe/src/crypto/clientcert.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <ipxe/dhcp.h> -#include <ipxe/settings.h> -#include <ipxe/clientcert.h> - -/** @file - * - * Client certificate store - * - * Life would in theory be easier if we could use a single file to - * hold both the certificate and corresponding private key. - * Unfortunately, the only common format which supports this is - * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my - * codebase. See, for reference and amusement: - * - * http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html - * - */ - -/* Sanity checks */ -#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY) -#warning "Attempting to embed certificate with no corresponding private key" -#endif -#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE) -#warning "Attempting to embed private key with no corresponding certificate" -#endif - -/* Allow client certificates to be overridden if not explicitly specified */ -#ifdef CERTIFICATE -#define ALLOW_CERT_OVERRIDE 0 -#else -#define ALLOW_CERT_OVERRIDE 1 -#endif - -/* Raw client certificate data */ -extern char client_certificate_data[]; -extern char client_certificate_len[]; -__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" - "\nclient_certificate_data:\n\t" -#ifdef CERTIFICATE - ".incbin \"" CERTIFICATE "\"\n\t" -#endif /* CERTIFICATE */ - ".size client_certificate_data, ( . - client_certificate_data )\n\t" - ".equ client_certificate_len, ( . - client_certificate_data )\n\t" - ".previous\n\t" ); - -/* Raw client private key data */ -extern char client_private_key_data[]; -extern char client_private_key_len[]; -__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" - "\nclient_private_key_data:\n\t" -#ifdef PRIVATE_KEY - ".incbin \"" PRIVATE_KEY "\"\n\t" -#endif /* PRIVATE_KEY */ - ".size client_private_key_data, ( . - client_private_key_data )\n\t" - ".equ client_private_key_len, ( . - client_private_key_data )\n\t" - ".previous\n\t" ); - -/** Client certificate */ -struct client_certificate client_certificate = { - .data = client_certificate_data, - .len = ( ( size_t ) client_certificate_len ), -}; - -/** Client private key */ -struct client_private_key client_private_key = { - .data = client_private_key_data, - .len = ( ( size_t ) client_private_key_len ), -}; - -/** Client certificate setting */ -static struct setting cert_setting __setting ( SETTING_CRYPTO ) = { - .name = "cert", - .description = "Client certificate", - .tag = DHCP_EB_CERT, - .type = &setting_type_hex, -}; - -/** Client private key setting */ -static struct setting privkey_setting __setting ( SETTING_CRYPTO ) = { - .name = "privkey", - .description = "Client private key", - .tag = DHCP_EB_KEY, - .type = &setting_type_hex, -}; - -/** - * Apply client certificate store configuration settings - * - * @ret rc Return status code - */ -static int clientcert_apply_settings ( void ) { - static void *cert = NULL; - static void *key = NULL; - int len; - int rc; - - /* Allow client certificate to be overridden only if - * not explicitly specified at build time. - */ - if ( ALLOW_CERT_OVERRIDE ) { - - /* Restore default client certificate */ - client_certificate.data = client_certificate_data; - client_certificate.len = ( ( size_t ) client_certificate_len ); - - /* Fetch new client certificate, if any */ - free ( cert ); - len = fetch_setting_copy ( NULL, &cert_setting, &cert ); - if ( len < 0 ) { - rc = len; - DBGC ( &client_certificate, "CLIENTCERT cannot fetch " - "client certificate: %s\n", strerror ( rc ) ); - return rc; - } - if ( cert ) { - client_certificate.data = cert; - client_certificate.len = len; - } - - /* Restore default client private key */ - client_private_key.data = client_private_key_data; - client_private_key.len = ( ( size_t ) client_private_key_len ); - - /* Fetch new client private key, if any */ - free ( key ); - len = fetch_setting_copy ( NULL, &privkey_setting, &key ); - if ( len < 0 ) { - rc = len; - DBGC ( &client_certificate, "CLIENTCERT cannot fetch " - "client private key: %s\n", strerror ( rc ) ); - return rc; - } - if ( key ) { - client_private_key.data = key; - client_private_key.len = len; - } - } - - /* Debug */ - if ( have_client_certificate() ) { - DBGC ( &client_certificate, "CLIENTCERT using %s " - "certificate:\n", ( cert ? "external" : "built-in" ) ); - DBGC_HDA ( &client_certificate, 0, client_certificate.data, - client_certificate.len ); - DBGC ( &client_certificate, "CLIENTCERT using %s private " - "key:\n", ( key ? "external" : "built-in" ) ); - DBGC_HDA ( &client_certificate, 0, client_private_key.data, - client_private_key.len ); - } else { - DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" ); - } - - return 0; -} - -/** Client certificate store settings applicator */ -struct settings_applicator clientcert_applicator __settings_applicator = { - .apply = clientcert_apply_settings, -}; diff --git a/roms/ipxe/src/crypto/cms.c b/roms/ipxe/src/crypto/cms.c index c0c8d144f..b4a41de6c 100644 --- a/roms/ipxe/src/crypto/cms.c +++ b/roms/ipxe/src/crypto/cms.c @@ -130,7 +130,7 @@ static int cms_parse_certificates ( struct cms_signature *sig, } cert = x509_last ( sig->certificates ); DBGC ( sig, "CMS %p found certificate %s\n", - sig, cert->subject.name ); + sig, x509_name ( cert ) ); /* Move to next certificate */ asn1_skip_any ( &cursor ); @@ -617,18 +617,21 @@ static int cms_verify_digest ( struct cms_signature *sig, * @v data Signed data * @v len Length of signed data * @v time Time at which to validate certificates - * @v root Root certificate store, or NULL to use default + * @v store Certificate store, or NULL to use default + * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ static int cms_verify_signer_info ( struct cms_signature *sig, struct cms_signer_info *info, userptr_t data, size_t len, - time_t time, struct x509_root *root ) { + time_t time, struct x509_chain *store, + struct x509_root *root ) { struct x509_certificate *cert; int rc; /* Validate certificate chain */ - if ( ( rc = x509_validate_chain ( info->chain, time, root ) ) != 0 ) { + if ( ( rc = x509_validate_chain ( info->chain, time, store, + root ) ) != 0 ) { DBGC ( sig, "CMS %p/%p could not validate chain: %s\n", sig, info, strerror ( rc ) ); return rc; @@ -667,11 +670,13 @@ static int cms_verify_signer_info ( struct cms_signature *sig, * @v len Length of signed data * @v name Required common name, or NULL to check all signatures * @v time Time at which to validate certificates - * @v root Root certificate store, or NULL to use default + * @v store Certificate store, or NULL to use default + * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, - const char *name, time_t time, struct x509_root *root ) { + const char *name, time_t time, struct x509_chain *store, + struct x509_root *root ) { struct cms_signer_info *info; struct x509_certificate *cert; int count = 0; @@ -680,11 +685,10 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, /* Verify using all signerInfos */ list_for_each_entry ( info, &sig->info, list ) { cert = x509_first ( info->chain ); - if ( name && ( ( cert->subject.name == NULL ) || - ( strcmp ( cert->subject.name, name ) != 0 ) ) ) + if ( name && ( x509_check_name ( cert, name ) != 0 ) ) continue; - if ( ( rc = cms_verify_signer_info ( sig, info, data, len, - time, root ) ) != 0 ) + if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time, + store, root ) ) != 0 ) return rc; count++; } diff --git a/roms/ipxe/src/crypto/deflate.c b/roms/ipxe/src/crypto/deflate.c new file mode 100644 index 000000000..91a489961 --- /dev/null +++ b/roms/ipxe/src/crypto/deflate.c @@ -0,0 +1,1045 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <strings.h> +#include <errno.h> +#include <assert.h> +#include <ctype.h> +#include <ipxe/uaccess.h> +#include <ipxe/deflate.h> + +/** @file + * + * DEFLATE decompression algorithm + * + * This file implements the decompression half of the DEFLATE + * algorithm specified in RFC 1951. + * + * Portions of this code are derived from wimboot's xca.c. + * + */ + +/** + * Byte reversal table + * + * For some insane reason, the DEFLATE format stores some values in + * bit-reversed order. + */ +static uint8_t deflate_reverse[256]; + +/** Literal/length base values + * + * We include entries only for literal/length codes 257-284. Code 285 + * does not fit the pattern (it represents a length of 258; following + * the pattern from the earlier codes would give a length of 259), and + * has no extra bits. Codes 286-287 are invalid, but can occur. We + * treat any code greater than 284 as meaning "length 285, no extra + * bits". + */ +static uint8_t deflate_litlen_base[28]; + +/** Distance base values + * + * We include entries for all possible codes 0-31, avoiding the need + * to check for undefined codes 30 and 31 before performing the + * lookup. Codes 30 and 31 are never initialised, and will therefore + * be treated as meaning "14 extra bits, base distance 0". + */ +static uint16_t deflate_distance_base[32]; + +/** Code length map */ +static uint8_t deflate_codelen_map[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +/** Static Huffman alphabet length patterns */ +static struct deflate_static_length_pattern deflate_static_length_patterns[] = { + /* Literal/length code lengths */ + { 0x88, ( ( ( 143 - 0 ) + 1 ) / 2 ) }, + { 0x99, ( ( ( 255 - 144 ) + 1 ) / 2 ) }, + { 0x77, ( ( ( 279 - 256 ) + 1 ) / 2 ) }, + { 0x88, ( ( ( 287 - 280 ) + 1 ) / 2 ) }, + /* Distance code lengths */ + { 0x55, ( ( ( 31 - 0 ) + 1 ) / 2 ) }, + /* End marker */ + { 0, 0 } +}; + +/** + * Transcribe binary value (for debugging) + * + * @v value Value + * @v bits Length of value (in bits) + * @ret string Transcribed value + */ +static const char * deflate_bin ( unsigned long value, unsigned int bits ) { + static char buf[ ( 8 * sizeof ( value ) ) + 1 /* NUL */ ]; + char *out = buf; + + /* Sanity check */ + assert ( bits < sizeof ( buf ) ); + + /* Transcribe value */ + while ( bits-- ) + *(out++) = ( ( value & ( 1 << bits ) ) ? '1' : '0' ); + *out = '\0'; + + return buf; +} + +/** + * Set Huffman symbol length + * + * @v deflate Decompressor + * @v index Index within lengths + * @v bits Symbol length (in bits) + */ +static void deflate_set_length ( struct deflate *deflate, unsigned int index, + unsigned int bits ) { + + deflate->lengths[ index / 2 ] |= ( bits << ( 4 * ( index % 2 ) ) ); +} + +/** + * Get Huffman symbol length + * + * @v deflate Decompressor + * @v index Index within lengths + * @ret bits Symbol length (in bits) + */ +static unsigned int deflate_length ( struct deflate *deflate, + unsigned int index ) { + + return ( ( deflate->lengths[ index / 2 ] >> ( 4 * ( index % 2 ) ) ) + & 0x0f ); +} + +/** + * Determine Huffman alphabet name (for debugging) + * + * @v deflate Decompressor + * @v alphabet Huffman alphabet + * @ret name Alphabet name + */ +static const char * deflate_alphabet_name ( struct deflate *deflate, + struct deflate_alphabet *alphabet ){ + + if ( alphabet == &deflate->litlen ) { + return "litlen"; + } else if ( alphabet == &deflate->distance_codelen ) { + return "distance/codelen"; + } else { + return "<UNKNOWN>"; + } +} + +/** + * Dump Huffman alphabet (for debugging) + * + * @v deflate Decompressor + * @v alphabet Huffman alphabet + */ +static void deflate_dump_alphabet ( struct deflate *deflate, + struct deflate_alphabet *alphabet ) { + struct deflate_huf_symbols *huf_sym; + unsigned int bits; + unsigned int huf; + unsigned int i; + + /* Do nothing unless debugging is enabled */ + if ( ! DBG_EXTRA ) + return; + + /* Dump symbol table for each utilised length */ + for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) / + sizeof ( alphabet->huf[0] ) ) ; bits++ ) { + huf_sym = &alphabet->huf[ bits - 1 ]; + if ( huf_sym->freq == 0 ) + continue; + huf = ( huf_sym->start >> huf_sym->shift ); + DBGC2 ( alphabet, "DEFLATE %p \"%s\" length %d start \"%s\" " + "freq %d:", deflate, + deflate_alphabet_name ( deflate, alphabet ), bits, + deflate_bin ( huf, huf_sym->bits ), huf_sym->freq ); + for ( i = 0 ; i < huf_sym->freq ; i++ ) { + DBGC2 ( alphabet, " %03x", + huf_sym->raw[ huf + i ] ); + } + DBGC2 ( alphabet, "\n" ); + } + + /* Dump quick lookup table */ + DBGC2 ( alphabet, "DEFLATE %p \"%s\" quick lookup:", deflate, + deflate_alphabet_name ( deflate, alphabet ) ); + for ( i = 0 ; i < ( sizeof ( alphabet->lookup ) / + sizeof ( alphabet->lookup[0] ) ) ; i++ ) { + DBGC2 ( alphabet, " %d", ( alphabet->lookup[i] + 1 ) ); + } + DBGC2 ( alphabet, "\n" ); +} + +/** + * Construct Huffman alphabet + * + * @v deflate Decompressor + * @v alphabet Huffman alphabet + * @v count Number of symbols + * @v offset Starting offset within length table + * @ret rc Return status code + */ +static int deflate_alphabet ( struct deflate *deflate, + struct deflate_alphabet *alphabet, + unsigned int count, unsigned int offset ) { + struct deflate_huf_symbols *huf_sym; + unsigned int huf; + unsigned int cum_freq; + unsigned int bits; + unsigned int raw; + unsigned int adjustment; + unsigned int prefix; + int complete; + + /* Clear symbol table */ + memset ( alphabet->huf, 0, sizeof ( alphabet->huf ) ); + + /* Count number of symbols with each Huffman-coded length */ + for ( raw = 0 ; raw < count ; raw++ ) { + bits = deflate_length ( deflate, ( raw + offset ) ); + if ( bits ) + alphabet->huf[ bits - 1 ].freq++; + } + + /* Populate Huffman-coded symbol table */ + huf = 0; + cum_freq = 0; + for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) / + sizeof ( alphabet->huf[0] ) ) ; bits++ ) { + huf_sym = &alphabet->huf[ bits - 1 ]; + huf_sym->bits = bits; + huf_sym->shift = ( 16 - bits ); + huf_sym->start = ( huf << huf_sym->shift ); + huf_sym->raw = &alphabet->raw[cum_freq]; + huf += huf_sym->freq; + if ( huf > ( 1U << bits ) ) { + DBGC ( alphabet, "DEFLATE %p \"%s\" has too many " + "symbols with lengths <=%d\n", deflate, + deflate_alphabet_name ( deflate, alphabet ), + bits ); + return -EINVAL; + } + huf <<= 1; + cum_freq += huf_sym->freq; + } + complete = ( huf == ( 1U << bits ) ); + + /* Populate raw symbol table */ + for ( raw = 0 ; raw < count ; raw++ ) { + bits = deflate_length ( deflate, ( raw + offset ) ); + if ( bits ) { + huf_sym = &alphabet->huf[ bits - 1 ]; + *(huf_sym->raw++) = raw; + } + } + + /* Adjust Huffman-coded symbol table raw pointers and populate + * quick lookup table. + */ + for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) / + sizeof ( alphabet->huf[0] ) ) ; bits++ ) { + huf_sym = &alphabet->huf[ bits - 1 ]; + + /* Adjust raw pointer */ + huf_sym->raw -= huf_sym->freq; /* Reset to first symbol */ + adjustment = ( huf_sym->start >> huf_sym->shift ); + huf_sym->raw -= adjustment; /* Adjust for quick indexing */ + + /* Populate quick lookup table */ + for ( prefix = ( huf_sym->start >> DEFLATE_HUFFMAN_QL_SHIFT ) ; + prefix < ( 1 << DEFLATE_HUFFMAN_QL_BITS ) ; prefix++ ) { + alphabet->lookup[prefix] = ( bits - 1 ); + } + } + + /* Dump alphabet (for debugging) */ + deflate_dump_alphabet ( deflate, alphabet ); + + /* Check that there are no invalid codes */ + if ( ! complete ) { + DBGC ( alphabet, "DEFLATE %p \"%s\" is incomplete\n", deflate, + deflate_alphabet_name ( deflate, alphabet ) ); + return -EINVAL; + } + + return 0; +} + +/** + * Attempt to accumulate bits from input stream + * + * @v deflate Decompressor + * @v in Compressed input data + * @v target Number of bits to accumulate + * @ret excess Number of excess bits accumulated (may be negative) + */ +static int deflate_accumulate ( struct deflate *deflate, + struct deflate_chunk *in, + unsigned int target ) { + uint8_t byte; + + while ( deflate->bits < target ) { + + /* Check for end of input */ + if ( in->offset >= in->len ) + break; + + /* Acquire byte from input */ + copy_from_user ( &byte, in->data, in->offset++, + sizeof ( byte ) ); + deflate->accumulator = ( deflate->accumulator | + ( byte << deflate->bits ) ); + deflate->rotalumucca = ( deflate->rotalumucca | + ( deflate_reverse[byte] << + ( 24 - deflate->bits ) ) ); + deflate->bits += 8; + + /* Sanity check */ + assert ( deflate->bits <= + ( 8 * sizeof ( deflate->accumulator ) ) ); + } + + return ( deflate->bits - target ); +} + +/** + * Consume accumulated bits from the input stream + * + * @v deflate Decompressor + * @v count Number of accumulated bits to consume + * @ret data Consumed bits + */ +static int deflate_consume ( struct deflate *deflate, unsigned int count ) { + int data; + + /* Sanity check */ + assert ( count <= deflate->bits ); + + /* Extract data and consume bits */ + data = ( deflate->accumulator & ( ( 1 << count ) - 1 ) ); + deflate->accumulator >>= count; + deflate->rotalumucca <<= count; + deflate->bits -= count; + + return data; +} + +/** + * Attempt to extract a fixed number of bits from input stream + * + * @v deflate Decompressor + * @v in Compressed input data + * @v target Number of bits to extract + * @ret data Extracted bits (or negative if not yet accumulated) + */ +static int deflate_extract ( struct deflate *deflate, struct deflate_chunk *in, + unsigned int target ) { + int excess; + int data; + + /* Return immediately if we are attempting to extract zero bits */ + if ( target == 0 ) + return 0; + + /* Attempt to accumulate bits */ + excess = deflate_accumulate ( deflate, in, target ); + if ( excess < 0 ) + return excess; + + /* Extract data and consume bits */ + data = deflate_consume ( deflate, target ); + DBGCP ( deflate, "DEFLATE %p extracted %s = %#x = %d\n", deflate, + deflate_bin ( data, target ), data, data ); + + return data; +} + +/** + * Attempt to decode a Huffman-coded symbol from input stream + * + * @v deflate Decompressor + * @v in Compressed input data + * @v alphabet Huffman alphabet + * @ret code Raw code (or negative if not yet accumulated) + */ +static int deflate_decode ( struct deflate *deflate, + struct deflate_chunk *in, + struct deflate_alphabet *alphabet ) { + struct deflate_huf_symbols *huf_sym; + uint16_t huf; + unsigned int lookup_index; + int excess; + unsigned int raw; + + /* Attempt to accumulate maximum required number of bits. + * There may be fewer bits than this remaining in the stream, + * even if the stream still contains some complete + * Huffman-coded symbols. + */ + deflate_accumulate ( deflate, in, DEFLATE_HUFFMAN_BITS ); + + /* Normalise the bit-reversed accumulated value to 16 bits */ + huf = ( deflate->rotalumucca >> 16 ); + + /* Find symbol set for this length */ + lookup_index = ( huf >> DEFLATE_HUFFMAN_QL_SHIFT ); + huf_sym = &alphabet->huf[ alphabet->lookup[ lookup_index ] ]; + while ( huf < huf_sym->start ) + huf_sym--; + + /* Calculate number of excess bits, and return if not yet complete */ + excess = ( deflate->bits - huf_sym->bits ); + if ( excess < 0 ) + return excess; + + /* Consume bits */ + deflate_consume ( deflate, huf_sym->bits ); + + /* Look up raw symbol */ + raw = huf_sym->raw[ huf >> huf_sym->shift ]; + DBGCP ( deflate, "DEFLATE %p decoded %s = %#x = %d\n", deflate, + deflate_bin ( ( huf >> huf_sym->shift ), huf_sym->bits ), + raw, raw ); + + return raw; +} + +/** + * Discard bits up to the next byte boundary + * + * @v deflate Decompressor + */ +static void deflate_discard_to_byte ( struct deflate *deflate ) { + + deflate_consume ( deflate, ( deflate->bits & 7 ) ); +} + +/** + * Copy data to output buffer (if available) + * + * @v out Output data buffer + * @v start Source data + * @v offset Starting offset within source data + * @v len Length to copy + */ +static void deflate_copy ( struct deflate_chunk *out, + userptr_t start, size_t offset, size_t len ) { + size_t out_offset = out->offset; + size_t copy_len; + + /* Copy data one byte at a time, to allow for overlap */ + if ( out_offset < out->len ) { + copy_len = ( out->len - out_offset ); + if ( copy_len > len ) + copy_len = len; + while ( copy_len-- ) { + memcpy_user ( out->data, out_offset++, + start, offset++, 1 ); + } + } + out->offset += len; +} + +/** + * Inflate compressed data + * + * @v deflate Decompressor + * @v in Compressed input data + * @v out Output data buffer + * @ret rc Return status code + * + * The caller can use deflate_finished() to determine whether a + * successful return indicates that the decompressor is merely waiting + * for more input. + * + * Data will not be written beyond the specified end of the output + * data buffer, but the offset within the output data buffer will be + * updated to reflect the amount that should have been written. The + * caller can use this to find the length of the decompressed data + * before allocating the output data buffer. + */ +int deflate_inflate ( struct deflate *deflate, + struct deflate_chunk *in, + struct deflate_chunk *out ) { + + /* This could be implemented more neatly if gcc offered a + * means for enforcing tail recursion. + */ + if ( deflate->resume ) { + goto *(deflate->resume); + } else switch ( deflate->format ) { + case DEFLATE_RAW: goto block_header; + case DEFLATE_ZLIB: goto zlib_header; + default: assert ( 0 ); + } + + zlib_header: { + int header; + int cm; + + /* Extract header */ + header = deflate_extract ( deflate, in, ZLIB_HEADER_BITS ); + if ( header < 0 ) { + deflate->resume = &&zlib_header; + return 0; + } + + /* Parse header */ + cm = ( ( header >> ZLIB_HEADER_CM_LSB ) & ZLIB_HEADER_CM_MASK ); + if ( cm != ZLIB_HEADER_CM_DEFLATE ) { + DBGC ( deflate, "DEFLATE %p unsupported ZLIB " + "compression method %d\n", deflate, cm ); + return -ENOTSUP; + } + if ( header & ( 1 << ZLIB_HEADER_FDICT_BIT ) ) { + DBGC ( deflate, "DEFLATE %p unsupported ZLIB preset " + "dictionary\n", deflate ); + return -ENOTSUP; + } + + /* Process first block header */ + goto block_header; + } + + block_header: { + int header; + int bfinal; + int btype; + + /* Extract block header */ + header = deflate_extract ( deflate, in, DEFLATE_HEADER_BITS ); + if ( header < 0 ) { + deflate->resume = &&block_header; + return 0; + } + + /* Parse header */ + deflate->header = header; + bfinal = ( header & ( 1 << DEFLATE_HEADER_BFINAL_BIT ) ); + btype = ( header >> DEFLATE_HEADER_BTYPE_LSB ); + DBGC ( deflate, "DEFLATE %p found %sblock type %#x\n", + deflate, ( bfinal ? "final " : "" ), btype ); + switch ( btype ) { + case DEFLATE_HEADER_BTYPE_LITERAL: + goto literal_block; + case DEFLATE_HEADER_BTYPE_STATIC: + goto static_block; + case DEFLATE_HEADER_BTYPE_DYNAMIC: + goto dynamic_block; + default: + DBGC ( deflate, "DEFLATE %p unsupported block type " + "%#x\n", deflate, btype ); + return -ENOTSUP; + } + } + + literal_block: { + + /* Discard any bits up to the next byte boundary */ + deflate_discard_to_byte ( deflate ); + } + + literal_len: { + int len; + + /* Extract LEN field */ + len = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS ); + if ( len < 0 ) { + deflate->resume = &&literal_len; + return 0; + } + + /* Record length of literal data */ + deflate->remaining = len; + DBGC2 ( deflate, "DEFLATE %p literal block length %#04zx\n", + deflate, deflate->remaining ); + } + + literal_nlen: { + int nlen; + + /* Extract NLEN field */ + nlen = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS); + if ( nlen < 0 ) { + deflate->resume = &&literal_nlen; + return 0; + } + + /* Verify NLEN */ + if ( ( ( deflate->remaining ^ ~nlen ) & + ( ( 1 << DEFLATE_LITERAL_LEN_BITS ) - 1 ) ) != 0 ) { + DBGC ( deflate, "DEFLATE %p invalid len/nlen " + "%#04zx/%#04x\n", deflate, + deflate->remaining, nlen ); + return -EINVAL; + } + } + + literal_data: { + size_t in_remaining; + size_t len; + + /* Calculate available amount of literal data */ + in_remaining = ( in->len - in->offset ); + len = deflate->remaining; + if ( len > in_remaining ) + len = in_remaining; + + /* Copy data to output buffer */ + deflate_copy ( out, in->data, in->offset, len ); + + /* Consume data from input buffer */ + in->offset += len; + deflate->remaining -= len; + + /* Finish processing if we are blocked */ + if ( deflate->remaining ) { + deflate->resume = &&literal_data; + return 0; + } + + /* Otherwise, finish block */ + goto block_done; + } + + static_block: { + struct deflate_static_length_pattern *pattern; + uint8_t *lengths = deflate->lengths; + + /* Construct static Huffman lengths as per RFC 1950 */ + for ( pattern = deflate_static_length_patterns ; + pattern->count ; pattern++ ) { + memset ( lengths, pattern->fill, pattern->count ); + lengths += pattern->count; + } + deflate->litlen_count = 288; + deflate->distance_count = 32; + goto construct_alphabets; + } + + dynamic_block: + + dynamic_header: { + int header; + unsigned int hlit; + unsigned int hdist; + unsigned int hclen; + + /* Extract block header */ + header = deflate_extract ( deflate, in, DEFLATE_DYNAMIC_BITS ); + if ( header < 0 ) { + deflate->resume = &&dynamic_header; + return 0; + } + + /* Parse header */ + hlit = ( ( header >> DEFLATE_DYNAMIC_HLIT_LSB ) & + DEFLATE_DYNAMIC_HLIT_MASK ); + hdist = ( ( header >> DEFLATE_DYNAMIC_HDIST_LSB ) & + DEFLATE_DYNAMIC_HDIST_MASK ); + hclen = ( ( header >> DEFLATE_DYNAMIC_HCLEN_LSB ) & + DEFLATE_DYNAMIC_HCLEN_MASK ); + deflate->litlen_count = ( hlit + 257 ); + deflate->distance_count = ( hdist + 1 ); + deflate->length_index = 0; + deflate->length_target = ( hclen + 4 ); + DBGC2 ( deflate, "DEFLATE %p dynamic block %d codelen, %d " + "litlen, %d distance\n", deflate, + deflate->length_target, deflate->litlen_count, + deflate->distance_count ); + + /* Prepare for decoding code length code lengths */ + memset ( &deflate->lengths, 0, sizeof ( deflate->lengths ) ); + } + + dynamic_codelen: { + int len; + unsigned int index; + int rc; + + /* Extract all code lengths */ + while ( deflate->length_index < deflate->length_target ) { + + /* Extract code length length */ + len = deflate_extract ( deflate, in, + DEFLATE_CODELEN_BITS ); + if ( len < 0 ) { + deflate->resume = &&dynamic_codelen; + return 0; + } + + /* Store code length */ + index = deflate_codelen_map[deflate->length_index++]; + deflate_set_length ( deflate, index, len ); + DBGCP ( deflate, "DEFLATE %p codelen for %d is %d\n", + deflate, index, len ); + } + + /* Generate code length alphabet */ + if ( ( rc = deflate_alphabet ( deflate, + &deflate->distance_codelen, + ( DEFLATE_CODELEN_MAX_CODE + 1 ), + 0 ) ) != 0 ) + return rc; + + /* Prepare for decoding literal/length/distance code lengths */ + memset ( &deflate->lengths, 0, sizeof ( deflate->lengths ) ); + deflate->length_index = 0; + deflate->length_target = ( deflate->litlen_count + + deflate->distance_count ); + deflate->length = 0; + } + + dynamic_litlen_distance: { + int len; + int index; + + /* Decode literal/length/distance code length */ + len = deflate_decode ( deflate, in, &deflate->distance_codelen); + if ( len < 0 ) { + deflate->resume = &&dynamic_litlen_distance; + return 0; + } + + /* Prepare for extra bits */ + if ( len < 16 ) { + deflate->length = len; + deflate->extra_bits = 0; + deflate->dup_len = 1; + } else { + static const uint8_t dup_len[3] = { 3, 3, 11 }; + static const uint8_t extra_bits[3] = { 2, 3, 7 }; + index = ( len - 16 ); + deflate->dup_len = dup_len[index]; + deflate->extra_bits = extra_bits[index]; + if ( index ) + deflate->length = 0; + } + } + + dynamic_litlen_distance_extra: { + int extra; + unsigned int dup_len; + + /* Extract extra bits */ + extra = deflate_extract ( deflate, in, deflate->extra_bits ); + if ( extra < 0 ) { + deflate->resume = &&dynamic_litlen_distance_extra; + return 0; + } + + /* Store code lengths */ + dup_len = ( deflate->dup_len + extra ); + while ( ( deflate->length_index < deflate->length_target ) && + dup_len-- ) { + deflate_set_length ( deflate, deflate->length_index++, + deflate->length ); + } + + /* Process next literal/length or distance code + * length, if more are required. + */ + if ( deflate->length_index < deflate->length_target ) + goto dynamic_litlen_distance; + + /* Construct alphabets */ + goto construct_alphabets; + } + + construct_alphabets: { + unsigned int distance_offset = deflate->litlen_count; + unsigned int distance_count = deflate->distance_count; + int rc; + + /* Generate literal/length alphabet */ + if ( ( rc = deflate_alphabet ( deflate, &deflate->litlen, + deflate->litlen_count, 0 ) ) !=0) + return rc; + + /* Handle degenerate case of a single distance code + * (for which it is impossible to construct a valid, + * complete Huffman alphabet). RFC 1951 states: + * + * If only one distance code is used, it is encoded + * using one bit, not zero bits; in this case there + * is a single code length of one, with one unused + * code. One distance code of zero bits means that + * there are no distance codes used at all (the data + * is all literals). + * + * If we have only a single distance code, then we + * instead use two distance codes both with length 1. + * This results in a valid Huffman alphabet. The code + * "0" will mean distance code 0 (which is either + * correct or irrelevant), and the code "1" will mean + * distance code 1 (which is always irrelevant). + */ + if ( deflate->distance_count == 1 ) { + + deflate->lengths[0] = 0x11; + distance_offset = 0; + distance_count = 2; + } + + /* Generate distance alphabet */ + if ( ( rc = deflate_alphabet ( deflate, + &deflate->distance_codelen, + distance_count, + distance_offset ) ) != 0 ) + return rc; + } + + lzhuf_litlen: { + int code; + uint8_t byte; + unsigned int extra; + unsigned int bits; + + /* Decode Huffman codes */ + while ( 1 ) { + + /* Decode Huffman code */ + code = deflate_decode ( deflate, in, &deflate->litlen ); + if ( code < 0 ) { + deflate->resume = &&lzhuf_litlen; + return 0; + } + + /* Handle according to code type */ + if ( code < DEFLATE_LITLEN_END ) { + + /* Literal value: copy to output buffer */ + byte = code; + DBGCP ( deflate, "DEFLATE %p literal %#02x " + "('%c')\n", deflate, byte, + ( isprint ( byte ) ? byte : '.' ) ); + deflate_copy ( out, virt_to_user ( &byte ), 0, + sizeof ( byte ) ); + + } else if ( code == DEFLATE_LITLEN_END ) { + + /* End of block */ + goto block_done; + + } else { + + /* Length code: process extra bits */ + extra = ( code - DEFLATE_LITLEN_END - 1 ); + if ( extra < 28 ) { + bits = ( extra / 4 ); + if ( bits ) + bits--; + deflate->extra_bits = bits; + deflate->dup_len = + deflate_litlen_base[extra]; + } else { + deflate->extra_bits = 0; + deflate->dup_len = 258; + } + goto lzhuf_litlen_extra; + } + } + } + + lzhuf_litlen_extra: { + int extra; + + /* Extract extra bits */ + extra = deflate_extract ( deflate, in, deflate->extra_bits ); + if ( extra < 0 ) { + deflate->resume = &&lzhuf_litlen_extra; + return 0; + } + + /* Update duplicate length */ + deflate->dup_len += extra; + } + + lzhuf_distance: { + int code; + unsigned int extra; + unsigned int bits; + + /* Decode Huffman code */ + code = deflate_decode ( deflate, in, + &deflate->distance_codelen ); + if ( code < 0 ) { + deflate->resume = &&lzhuf_distance; + return 0; + } + + /* Process extra bits */ + extra = code; + bits = ( extra / 2 ); + if ( bits ) + bits--; + deflate->extra_bits = bits; + deflate->dup_distance = deflate_distance_base[extra]; + } + + lzhuf_distance_extra: { + int extra; + size_t dup_len; + size_t dup_distance; + + /* Extract extra bits */ + extra = deflate_extract ( deflate, in, deflate->extra_bits ); + if ( extra < 0 ) { + deflate->resume = &&lzhuf_distance_extra; + return 0; + } + + /* Update duplicate distance */ + dup_distance = ( deflate->dup_distance + extra ); + dup_len = deflate->dup_len; + DBGCP ( deflate, "DEFLATE %p duplicate length %zd distance " + "%zd\n", deflate, dup_len, dup_distance ); + + /* Sanity check */ + if ( dup_distance > out->offset ) { + DBGC ( deflate, "DEFLATE %p bad distance %zd (max " + "%zd)\n", deflate, dup_distance, out->offset ); + return -EINVAL; + } + + /* Copy data, allowing for overlap */ + deflate_copy ( out, out->data, ( out->offset - dup_distance ), + dup_len ); + + /* Process next literal/length symbol */ + goto lzhuf_litlen; + } + + block_done: { + + DBGCP ( deflate, "DEFLATE %p end of block\n", deflate ); + + /* If this was not the final block, process next block header */ + if ( ! ( deflate->header & ( 1 << DEFLATE_HEADER_BFINAL_BIT ) )) + goto block_header; + + /* Otherwise, process footer (if any) */ + switch ( deflate->format ) { + case DEFLATE_RAW: goto finished; + case DEFLATE_ZLIB: goto zlib_footer; + default: assert ( 0 ); + } + } + + zlib_footer: { + + /* Discard any bits up to the next byte boundary */ + deflate_discard_to_byte ( deflate ); + } + + zlib_adler32: { + int excess; + + /* Accumulate the 32 bits of checksum. We don't check + * the value, stop processing immediately afterwards, + * and so don't have to worry about the nasty corner + * cases involved in calling deflate_extract() to + * obtain a full 32 bits. + */ + excess = deflate_accumulate ( deflate, in, ZLIB_ADLER32_BITS ); + if ( excess < 0 ) { + deflate->resume = &&zlib_adler32; + return 0; + } + + /* Finish processing */ + goto finished; + } + + finished: { + /* Mark as finished and terminate */ + DBGCP ( deflate, "DEFLATE %p finished\n", deflate ); + deflate->resume = NULL; + return 0; + } +} + +/** + * Initialise decompressor + * + * @v deflate Decompressor + * @v format Compression format code + */ +void deflate_init ( struct deflate *deflate, enum deflate_format format ) { + static int global_init_done; + uint8_t i; + uint8_t bit; + uint8_t byte; + unsigned int base; + unsigned int bits; + + /* Perform global initialisation if required */ + if ( ! global_init_done ) { + + /* Initialise byte reversal table */ + for ( i = 255 ; i ; i-- ) { + for ( bit = 1, byte = 0 ; bit ; bit <<= 1 ) { + byte <<= 1; + if ( i & bit ) + byte |= 1; + } + deflate_reverse[i] = byte; + } + + /* Initialise literal/length extra bits table */ + base = 3; + for ( i = 0 ; i < 28 ; i++ ) { + bits = ( i / 4 ); + if ( bits ) + bits--; + deflate_litlen_base[i] = base; + base += ( 1 << bits ); + } + assert ( base == 259 ); /* sic */ + + /* Initialise distance extra bits table */ + base = 1; + for ( i = 0 ; i < 30 ; i++ ) { + bits = ( i / 2 ); + if ( bits ) + bits--; + deflate_distance_base[i] = base; + base += ( 1 << bits ); + } + assert ( base == 32769 ); + + /* Record global initialisation as complete */ + global_init_done = 1; + } + + /* Initialise structure */ + memset ( deflate, 0, sizeof ( *deflate ) ); + deflate->format = format; +} diff --git a/roms/ipxe/src/crypto/ocsp.c b/roms/ipxe/src/crypto/ocsp.c index ab75dea35..d4815a1b5 100644 --- a/roms/ipxe/src/crypto/ocsp.c +++ b/roms/ipxe/src/crypto/ocsp.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/base64.h> #include <ipxe/uri.h> #include <ipxe/ocsp.h> +#include <config/crypto.h> /** @file * @@ -58,6 +59,21 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define EINFO_EACCES_STALE \ __einfo_uniqify ( EINFO_EACCES, 0x04, \ "Stale (or premature) OCSP repsonse" ) +#define EACCES_NO_RESPONDER \ + __einfo_error ( EINFO_EACCES_NO_RESPONDER ) +#define EINFO_EACCES_NO_RESPONDER \ + __einfo_uniqify ( EINFO_EACCES, 0x05, \ + "Missing OCSP responder certificate" ) +#define ENOTSUP_RESPONSE_TYPE \ + __einfo_error ( EINFO_ENOTSUP_RESPONSE_TYPE ) +#define EINFO_ENOTSUP_RESPONSE_TYPE \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x01, \ + "Unsupported OCSP response type" ) +#define ENOTSUP_RESPONDER_ID \ + __einfo_error ( EINFO_ENOTSUP_RESPONDER_ID ) +#define EINFO_ENOTSUP_RESPONDER_ID \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x02, \ + "Unsupported OCSP responder ID" ) #define EPROTO_MALFORMED_REQUEST \ __einfo_error ( EINFO_EPROTO_MALFORMED_REQUEST ) #define EINFO_EPROTO_MALFORMED_REQUEST \ @@ -84,7 +100,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_UNAUTHORIZED, \ "Request unauthorized" ) #define EPROTO_STATUS( status ) \ - EUNIQ ( EPROTO, (status), EPROTO_MALFORMED_REQUEST, \ + EUNIQ ( EINFO_EPROTO, (status), EPROTO_MALFORMED_REQUEST, \ EPROTO_INTERNAL_ERROR, EPROTO_TRY_LATER, \ EPROTO_SIG_REQUIRED, EPROTO_UNAUTHORIZED ) @@ -162,11 +178,11 @@ static int ocsp_request ( struct ocsp_check *ocsp ) { asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC2_HDA ( ocsp, 0, builder->data, builder->len ); /* Parse certificate ID for comparison with response */ @@ -177,7 +193,7 @@ static int ocsp_request ( struct ocsp_check *ocsp ) { asn1_enter ( cert_id, ASN1_SEQUENCE ), asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } @@ -191,60 +207,63 @@ static int ocsp_request ( struct ocsp_check *ocsp ) { * @ret rc Return status code */ static int ocsp_uri_string ( struct ocsp_check *ocsp ) { - char *base_uri_string; - char *base64_request; - size_t base64_request_len; - size_t uri_string_len; - size_t prefix_len; + struct x509_ocsp_responder *responder = + &ocsp->cert->extensions.auth_info.ocsp; + struct uri path_uri; + char *path_base64_string; + char *path_uri_string; + size_t path_len; + size_t len; int rc; /* Sanity check */ - base_uri_string = ocsp->cert->extensions.auth_info.ocsp.uri; - if ( ! base_uri_string ) { + if ( ! responder->uri.len ) { DBGC ( ocsp, "OCSP %p \"%s\" has no OCSP URI\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); rc = -ENOTTY; goto err_no_uri; } - /* Base64-encode the request */ - base64_request_len = ( base64_encoded_len ( ocsp->request.builder.len ) - + 1 /* NUL */ ); - base64_request = malloc ( base64_request_len ); - if ( ! base64_request ) { + /* Base64-encode the request as the URI path */ + path_len = ( base64_encoded_len ( ocsp->request.builder.len ) + + 1 /* NUL */ ); + path_base64_string = malloc ( path_len ); + if ( ! path_base64_string ) { rc = -ENOMEM; - goto err_alloc_base64; + goto err_path_base64; } base64_encode ( ocsp->request.builder.data, ocsp->request.builder.len, - base64_request ); + path_base64_string ); - /* Allocate URI string */ - uri_string_len = ( strlen ( base_uri_string ) + 1 /* "/" */ + - uri_encode ( base64_request, NULL, 0, URI_FRAGMENT ) - + 1 /* NUL */ ); - ocsp->uri_string = malloc ( uri_string_len ); - if ( ! ocsp->uri_string ) { + /* URI-encode the Base64-encoded request */ + memset ( &path_uri, 0, sizeof ( path_uri ) ); + path_uri.path = path_base64_string; + path_uri_string = format_uri_alloc ( &path_uri ); + if ( ! path_uri_string ) { rc = -ENOMEM; - goto err_alloc_uri; + goto err_path_uri; } /* Construct URI string */ - prefix_len = snprintf ( ocsp->uri_string, uri_string_len, - "%s/", base_uri_string ); - uri_encode ( base64_request, ( ocsp->uri_string + prefix_len ), - ( uri_string_len - prefix_len ), URI_FRAGMENT ); + len = ( responder->uri.len + strlen ( path_uri_string ) + 1 /* NUL */ ); + ocsp->uri_string = zalloc ( len ); + if ( ! ocsp->uri_string ) { + rc = -ENOMEM; + goto err_ocsp_uri; + } + memcpy ( ocsp->uri_string, responder->uri.data, responder->uri.len ); + strcpy ( &ocsp->uri_string[responder->uri.len], path_uri_string ); DBGC2 ( ocsp, "OCSP %p \"%s\" URI is %s\n", - ocsp, ocsp->cert->subject.name, ocsp->uri_string ); - - /* Free base64-encoded request */ - free ( base64_request ); - base64_request = NULL; + ocsp, x509_name ( ocsp->cert ), ocsp->uri_string ); - return 0; + /* Success */ + rc = 0; - err_alloc_uri: - free ( base64_request ); - err_alloc_base64: + err_ocsp_uri: + free ( path_uri_string ); + err_path_uri: + free ( path_base64_string ); + err_path_base64: err_no_uri: return rc; } @@ -312,14 +331,14 @@ static int ocsp_parse_response_status ( struct ocsp_check *ocsp, memcpy ( &cursor, raw, sizeof ( cursor ) ); if ( ( rc = asn1_enter ( &cursor, ASN1_ENUMERATED ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate responseStatus: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; } /* Extract response status */ if ( cursor.len != sizeof ( status ) ) { DBGC ( ocsp, "OCSP %p \"%s\" invalid status:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EINVAL; } @@ -328,7 +347,7 @@ static int ocsp_parse_response_status ( struct ocsp_check *ocsp, /* Check response status */ if ( status != OCSP_STATUS_SUCCESSFUL ) { DBGC ( ocsp, "OCSP %p \"%s\" response status %d\n", - ocsp, ocsp->cert->subject.name, status ); + ocsp, x509_name ( ocsp->cert ), status ); return EPROTO_STATUS ( status ); } @@ -353,15 +372,97 @@ static int ocsp_parse_response_type ( struct ocsp_check *ocsp, /* Check responseType is "basic" */ if ( asn1_compare ( &oid_basic_response_type_cursor, &cursor ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); - return -ENOTSUP; + return -ENOTSUP_RESPONSE_TYPE; } return 0; } /** + * Compare responder's certificate name + * + * @v ocsp OCSP check + * @v cert Certificate + * @ret difference Difference as returned by memcmp() + */ +static int ocsp_compare_responder_name ( struct ocsp_check *ocsp, + struct x509_certificate *cert ) { + struct ocsp_responder *responder = &ocsp->response.responder; + + /* Compare responder ID with certificate's subject */ + return asn1_compare ( &responder->id, &cert->subject.raw ); +} + +/** + * Compare responder's certificate public key hash + * + * @v ocsp OCSP check + * @v cert Certificate + * @ret difference Difference as returned by memcmp() + */ +static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp, + struct x509_certificate *cert ) { + struct ocsp_responder *responder = &ocsp->response.responder; + uint8_t ctx[SHA1_CTX_SIZE]; + uint8_t digest[SHA1_DIGEST_SIZE]; + int difference; + + /* Sanity check */ + difference = ( sizeof ( digest ) - responder->id.len ); + if ( difference ) + return difference; + + /* Generate SHA1 hash of certificate's public key */ + digest_init ( &sha1_algorithm, ctx ); + digest_update ( &sha1_algorithm, ctx, + cert->subject.public_key.raw_bits.data, + cert->subject.public_key.raw_bits.len ); + digest_final ( &sha1_algorithm, ctx, digest ); + + /* Compare responder ID with SHA1 hash of certificate's public key */ + return memcmp ( digest, responder->id.data, sizeof ( digest ) ); +} + +/** + * Parse OCSP responder ID + * + * @v ocsp OCSP check + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int ocsp_parse_responder_id ( struct ocsp_check *ocsp, + const struct asn1_cursor *raw ) { + struct ocsp_responder *responder = &ocsp->response.responder; + struct asn1_cursor *responder_id = &responder->id; + unsigned int type; + + /* Enter responder ID */ + memcpy ( responder_id, raw, sizeof ( *responder_id ) ); + type = asn1_type ( responder_id ); + asn1_enter_any ( responder_id ); + + /* Identify responder ID type */ + switch ( type ) { + case ASN1_EXPLICIT_TAG ( 1 ) : + DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by name\n", + ocsp, x509_name ( ocsp->cert ) ); + responder->compare = ocsp_compare_responder_name; + return 0; + case ASN1_EXPLICIT_TAG ( 2 ) : + DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by key " + "hash\n", ocsp, x509_name ( ocsp->cert ) ); + responder->compare = ocsp_compare_responder_key_hash; + return 0; + default: + DBGC ( ocsp, "OCSP %p \"%s\" unsupported responder ID type " + "%d\n", ocsp, x509_name ( ocsp->cert ), type ); + return -ENOTSUP_RESPONDER_ID; + } +} + +/** * Parse OCSP certificate ID * * @v ocsp OCSP check @@ -377,7 +478,7 @@ static int ocsp_parse_cert_id ( struct ocsp_check *ocsp, asn1_shrink_any ( &cursor ); if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data, ocsp->request.cert_id.len ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); @@ -415,7 +516,7 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, /* Check certStatus */ if ( asn1_type ( &cursor ) != ASN1_IMPLICIT_TAG ( 0 ) ) { DBGC ( ocsp, "OCSP %p \"%s\" non-good certStatus:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EACCES_CERT_STATUS; } @@ -425,11 +526,11 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, if ( ( rc = asn1_generalized_time ( &cursor, &response->this_update ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse thisUpdate: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" this update was at time %lld\n", - ocsp, ocsp->cert->subject.name, response->this_update ); + ocsp, x509_name ( ocsp->cert ), response->this_update ); asn1_skip_any ( &cursor ); /* Parse nextUpdate, if present */ @@ -439,11 +540,11 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, &response->next_update ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse " "nextUpdate: %s\n", ocsp, - ocsp->cert->subject.name, strerror ( rc ) ); + x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" next update is at time %lld\n", - ocsp, ocsp->cert->subject.name, response->next_update ); + ocsp, x509_name ( ocsp->cert ), response->next_update ); } else { /* If no nextUpdate is present, this indicates that * "newer revocation information is available all the @@ -453,7 +554,7 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, * time and it would still be valid. */ DBGC ( ocsp, "OCSP %p \"%s\" responder is a moron\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); response->next_update = time ( NULL ); } @@ -484,7 +585,9 @@ static int ocsp_parse_tbs_response_data ( struct ocsp_check *ocsp, /* Skip version, if present */ asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); - /* Skip responderID */ + /* Parse responderID */ + if ( ( rc = ocsp_parse_responder_id ( ocsp, &cursor ) ) != 0 ) + return rc; asn1_skip_any ( &cursor ); /* Skip producedAt */ @@ -508,6 +611,7 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp, const struct asn1_cursor *raw ) { struct ocsp_response *response = &ocsp->response; struct asn1_cursor cursor; + struct x509_certificate *cert; int rc; /* Enter certs */ @@ -519,20 +623,40 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp, * multiple certificates, but the protocol requires that the * OCSP signing certificate must either be the issuer itself, * or must be directly issued by the issuer (see RFC2560 - * section 4.2.2.2 "Authorized Responders"). + * section 4.2.2.2 "Authorized Responders"). We therefore + * need to identify only the single certificate matching the + * Responder ID. */ - if ( ( cursor.len != 0 ) && - ( ( rc = x509_certificate ( cursor.data, cursor.len, - &response->signer ) ) != 0 ) ) { - DBGC ( ocsp, "OCSP %p \"%s\" could not parse certificate: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); - DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); - return rc; + while ( cursor.len ) { + + /* Parse certificate */ + if ( ( rc = x509_certificate ( cursor.data, cursor.len, + &cert ) ) != 0 ) { + DBGC ( ocsp, "OCSP %p \"%s\" could not parse " + "certificate: %s\n", ocsp, + x509_name ( ocsp->cert ), strerror ( rc ) ); + DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); + return rc; + } + + /* Use if this certificate matches the responder ID */ + if ( response->responder.compare ( ocsp, cert ) == 0 ) { + response->signer = cert; + DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC2 ( ocsp, "\"%s\"\n", + x509_name ( response->signer ) ); + return 0; + } + + /* Otherwise, discard this certificate */ + x509_put ( cert ); + asn1_skip_any ( &cursor ); } - DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by \"%s\"\n", ocsp, - ocsp->cert->subject.name, response->signer->subject.name ); - return 0; + DBGC ( ocsp, "OCSP %p \"%s\" missing responder certificate\n", + ocsp, x509_name ( ocsp->cert ) ); + return -EACCES_NO_RESPONDER; } /** @@ -563,17 +687,17 @@ static int ocsp_parse_basic_response ( struct ocsp_check *ocsp, if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature " "algorithm: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature algorithm is %s\n", - ocsp, ocsp->cert->subject.name, (*algorithm)->name ); + ocsp, x509_name ( ocsp->cert ), (*algorithm)->name ); asn1_skip_any ( &cursor ); /* Parse signature */ if ( ( rc = asn1_integral_bit_string ( &cursor, signature ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } asn1_skip_any ( &cursor ); @@ -717,7 +841,7 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, public_key->raw.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_init; } @@ -726,12 +850,12 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, response->signature.data, response->signature.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_verify; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); err_verify: pubkey_final ( pubkey, pubkey_ctx ); @@ -748,12 +872,17 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, */ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { struct ocsp_response *response = &ocsp->response; - struct x509_certificate *signer = response->signer; + struct x509_certificate *signer; int rc; /* Sanity checks */ assert ( response->data != NULL ); - assert ( signer != NULL ); + + /* The response may include a signer certificate; if this is + * not present then the response must have been signed + * directly by the issuer. + */ + signer = ( response->signer ? response->signer : ocsp->issuer ); /* Validate signer, if applicable. If the signer is not the * issuer, then it must be signed directly by the issuer. @@ -768,10 +897,10 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { x509_invalidate ( signer ); if ( ( rc = x509_validate ( signer, ocsp->issuer, time, &ocsp_root ) ) != 0 ) { - DBGC ( ocsp, "OCSP %p \"%s\" could not validate " - "signer \"%s\": %s\n", ocsp, - ocsp->cert->subject.name, signer->subject.name, - strerror ( rc ) ); + DBGC ( ocsp, "OCSP %p \"%s\" could not validate ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC ( ocsp, "signer \"%s\": %s\n", + x509_name ( signer ), strerror ( rc ) ); return rc; } @@ -780,9 +909,10 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { */ if ( ! ( signer->extensions.ext_usage.bits & X509_OCSP_SIGNING ) ) { - DBGC ( ocsp, "OCSP %p \"%s\" signer \"%s\" is " - "not an OCSP-signing certificate\n", ocsp, - ocsp->cert->subject.name, signer->subject.name ); + DBGC ( ocsp, "OCSP %p \"%s\" ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC ( ocsp, "signer \"%s\" is not an OCSP-signing " + "certificate\n", x509_name ( signer ) ); return -EACCES_NON_OCSP_SIGNING; } } @@ -794,18 +924,18 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { /* Check OCSP response is valid at the specified time * (allowing for some margin of error). */ - if ( response->this_update > ( time + X509_ERROR_MARGIN_TIME ) ) { + if ( response->this_update > ( time + TIMESTAMP_ERROR_MARGIN ) ) { DBGC ( ocsp, "OCSP %p \"%s\" response is not yet valid (at " - "time %lld)\n", ocsp, ocsp->cert->subject.name, time ); + "time %lld)\n", ocsp, x509_name ( ocsp->cert ), time ); return -EACCES_STALE; } - if ( response->next_update < ( time - X509_ERROR_MARGIN_TIME ) ) { + if ( response->next_update < ( time - TIMESTAMP_ERROR_MARGIN ) ) { DBGC ( ocsp, "OCSP %p \"%s\" response is stale (at time " - "%lld)\n", ocsp, ocsp->cert->subject.name, time ); + "%lld)\n", ocsp, x509_name ( ocsp->cert ), time ); return -EACCES_STALE; } DBGC2 ( ocsp, "OCSP %p \"%s\" response is valid (at time %lld)\n", - ocsp, ocsp->cert->subject.name, time ); + ocsp, x509_name ( ocsp->cert ), time ); /* Mark certificate as passing OCSP verification */ ocsp->cert->extensions.auth_info.ocsp.good = 1; @@ -814,11 +944,12 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time, &ocsp_root ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; } - DBGC ( ocsp, "OCSP %p \"%s\" successfully validated using \"%s\"\n", - ocsp, ocsp->cert->subject.name, signer->subject.name ); + DBGC ( ocsp, "OCSP %p \"%s\" successfully validated ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC ( ocsp, "using \"%s\"\n", x509_name ( signer ) ); return 0; } diff --git a/roms/ipxe/src/crypto/privkey.c b/roms/ipxe/src/crypto/privkey.c new file mode 100644 index 000000000..e010649c0 --- /dev/null +++ b/roms/ipxe/src/crypto/privkey.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <ipxe/dhcp.h> +#include <ipxe/settings.h> +#include <ipxe/x509.h> +#include <ipxe/privkey.h> + +/** @file + * + * Private key + * + * Life would in theory be easier if we could use a single file to + * hold both the certificate and corresponding private key. + * Unfortunately, the only common format which supports this is + * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my + * codebase. See, for reference and amusement: + * + * http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html + */ + +/* Allow private key to be overridden if not explicitly specified */ +#ifdef PRIVATE_KEY +#define ALLOW_KEY_OVERRIDE 0 +#else +#define ALLOW_KEY_OVERRIDE 1 +#endif + +/* Raw private key data */ +extern char private_key_data[]; +extern char private_key_len[]; +__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" + "\nprivate_key_data:\n\t" +#ifdef PRIVATE_KEY + ".incbin \"" PRIVATE_KEY "\"\n\t" +#endif /* PRIVATE_KEY */ + ".size private_key_data, ( . - private_key_data )\n\t" + ".equ private_key_len, ( . - private_key_data )\n\t" + ".previous\n\t" ); + +/** Private key */ +struct asn1_cursor private_key = { + .data = private_key_data, + .len = ( ( size_t ) private_key_len ), +}; + +/** Private key setting */ +static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = { + .name = "privkey", + .description = "Private key", + .tag = DHCP_EB_KEY, + .type = &setting_type_hex, +}; + +/** + * Apply private key configuration settings + * + * @ret rc Return status code + */ +static int privkey_apply_settings ( void ) { + static void *key_data = NULL; + int len; + + /* Allow private key to be overridden only if not explicitly + * specified at build time. + */ + if ( ALLOW_KEY_OVERRIDE ) { + + /* Restore default private key */ + private_key.data = private_key_data; + private_key.len = ( ( size_t ) private_key_len ); + + /* Fetch new private key, if any */ + free ( key_data ); + if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting, + &key_data ) ) >= 0 ) { + private_key.data = key_data; + private_key.len = len; + } + } + + /* Debug */ + if ( private_key.len ) { + DBGC ( &private_key, "PRIVKEY using %s private key:\n", + ( key_data ? "external" : "built-in" ) ); + DBGC_HDA ( &private_key, 0, private_key.data, private_key.len ); + } else { + DBGC ( &private_key, "PRIVKEY has no private key\n" ); + } + + return 0; +} + +/** Private key settings applicator */ +struct settings_applicator privkey_applicator __settings_applicator = { + .apply = privkey_apply_settings, +}; diff --git a/roms/ipxe/src/crypto/rootcert.c b/roms/ipxe/src/crypto/rootcert.c index 30ca170f5..ae28905ac 100644 --- a/roms/ipxe/src/crypto/rootcert.c +++ b/roms/ipxe/src/crypto/rootcert.c @@ -58,7 +58,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); static const uint8_t fingerprints[] = { TRUSTED }; /** Root certificate fingerprint setting */ -static struct setting trust_setting __setting ( SETTING_CRYPTO ) = { +static struct setting trust_setting __setting ( SETTING_CRYPTO, trust ) = { .name = "trust", .description = "Trusted root certificate fingerprints", .tag = DHCP_EB_TRUST, @@ -91,7 +91,6 @@ struct x509_root root_certificates = { static void rootcert_init ( void ) { void *external = NULL; int len; - int rc; /* Allow trusted root certificates to be overridden only if * not explicitly specified at build time. @@ -101,21 +100,8 @@ static void rootcert_init ( void ) { /* Fetch copy of "trust" setting, if it exists. This * memory will never be freed. */ - len = fetch_setting_copy ( NULL, &trust_setting, &external ); - if ( len < 0 ) { - rc = len; - DBGC ( &root_certificates, "ROOTCERT cannot fetch " - "trusted root certificate fingerprints: %s\n", - strerror ( rc ) ); - /* No way to prevent startup; fail safe by - * trusting no certificates. - */ - root_certificates.count = 0; - return; - } - - /* Use certificates from "trust" setting, if present */ - if ( external ) { + if ( ( len = fetch_raw_setting_copy ( NULL, &trust_setting, + &external ) ) >= 0 ) { root_certificates.fingerprints = external; root_certificates.count = ( len / FINGERPRINT_LEN ); } diff --git a/roms/ipxe/src/crypto/rsa.c b/roms/ipxe/src/crypto/rsa.c index 1a5cf6cd5..0ab7b2ad3 100644 --- a/roms/ipxe/src/crypto/rsa.c +++ b/roms/ipxe/src/crypto/rsa.c @@ -202,13 +202,11 @@ static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, /** * Parse RSA integer * - * @v context RSA context * @v integer Integer to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int rsa_parse_integer ( struct rsa_context *context, - struct asn1_cursor *integer, +static int rsa_parse_integer ( struct asn1_cursor *integer, const struct asn1_cursor *raw ) { /* Enter integer */ @@ -223,44 +221,35 @@ static int rsa_parse_integer ( struct rsa_context *context, } /* Fail if cursor or integer are invalid */ - if ( ! integer->len ) { - DBGC ( context, "RSA %p invalid integer:\n", context ); - DBGC_HDA ( context, 0, raw->data, raw->len ); + if ( ! integer->len ) return -EINVAL; - } return 0; } /** - * Initialise RSA cipher + * Parse RSA modulus and exponent * - * @v ctx RSA context - * @v key Key - * @v key_len Length of key + * @v modulus Modulus to fill in + * @v exponent Exponent to fill in + * @v raw ASN.1 cursor * @ret rc Return status code */ -static int rsa_init ( void *ctx, const void *key, size_t key_len ) { - struct rsa_context *context = ctx; +static int rsa_parse_mod_exp ( struct asn1_cursor *modulus, + struct asn1_cursor *exponent, + const struct asn1_cursor *raw ) { struct asn1_bit_string bits; - struct asn1_cursor modulus; - struct asn1_cursor exponent; struct asn1_cursor cursor; int is_private; int rc; - /* Initialise context */ - memset ( context, 0, sizeof ( *context ) ); - - /* Initialise cursor */ - cursor.data = key; - cursor.len = key_len; - /* Enter subjectPublicKeyInfo/RSAPrivateKey */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Determine key format */ if ( asn1_type ( &cursor ) == ASN1_INTEGER ) { + /* Private key */ is_private = 1; @@ -268,6 +257,7 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { asn1_skip_any ( &cursor ); } else { + /* Public key */ is_private = 0; @@ -276,7 +266,7 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { /* Enter subjectPublicKey */ if ( ( rc = asn1_integral_bit_string ( &cursor, &bits ) ) != 0 ) - goto err_parse; + return rc; cursor.data = bits.data; cursor.len = bits.len; @@ -285,8 +275,8 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { } /* Extract modulus */ - if ( ( rc = rsa_parse_integer ( context, &modulus, &cursor ) ) != 0 ) - goto err_parse; + if ( ( rc = rsa_parse_integer ( modulus, &cursor ) ) != 0 ) + return rc; asn1_skip_any ( &cursor ); /* Skip public exponent, if applicable */ @@ -294,8 +284,40 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { asn1_skip ( &cursor, ASN1_INTEGER ); /* Extract publicExponent/privateExponent */ - if ( ( rc = rsa_parse_integer ( context, &exponent, &cursor ) ) != 0 ) + if ( ( rc = rsa_parse_integer ( exponent, &cursor ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Initialise RSA cipher + * + * @v ctx RSA context + * @v key Key + * @v key_len Length of key + * @ret rc Return status code + */ +static int rsa_init ( void *ctx, const void *key, size_t key_len ) { + struct rsa_context *context = ctx; + struct asn1_cursor modulus; + struct asn1_cursor exponent; + struct asn1_cursor cursor; + int rc; + + /* Initialise context */ + memset ( context, 0, sizeof ( *context ) ); + + /* Initialise cursor */ + cursor.data = key; + cursor.len = key_len; + + /* Parse modulus and exponent */ + if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, &cursor ) ) != 0 ){ + DBGC ( context, "RSA %p invalid modulus/exponent:\n", context ); + DBGC_HDA ( context, 0, cursor.data, cursor.len ); goto err_parse; + } DBGC ( context, "RSA %p modulus:\n", context ); DBGC_HDA ( context, 0, modulus.data, modulus.len ); @@ -628,6 +650,46 @@ static void rsa_final ( void *ctx ) { rsa_free ( context ); } +/** + * Check for matching RSA public/private key pair + * + * @v private_key Private key + * @v private_key_len Private key length + * @v public_key Public key + * @v public_key_len Public key length + * @ret rc Return status code + */ +static int rsa_match ( const void *private_key, size_t private_key_len, + const void *public_key, size_t public_key_len ) { + struct asn1_cursor private_modulus; + struct asn1_cursor private_exponent; + struct asn1_cursor private_cursor; + struct asn1_cursor public_modulus; + struct asn1_cursor public_exponent; + struct asn1_cursor public_cursor; + int rc; + + /* Initialise cursors */ + private_cursor.data = private_key; + private_cursor.len = private_key_len; + public_cursor.data = public_key; + public_cursor.len = public_key_len; + + /* Parse moduli and exponents */ + if ( ( rc = rsa_parse_mod_exp ( &private_modulus, &private_exponent, + &private_cursor ) ) != 0 ) + return rc; + if ( ( rc = rsa_parse_mod_exp ( &public_modulus, &public_exponent, + &public_cursor ) ) != 0 ) + return rc; + + /* Compare moduli */ + if ( asn1_compare ( &private_modulus, &public_modulus ) != 0 ) + return -ENOTTY; + + return 0; +} + /** RSA public-key algorithm */ struct pubkey_algorithm rsa_algorithm = { .name = "rsa", @@ -639,4 +701,5 @@ struct pubkey_algorithm rsa_algorithm = { .sign = rsa_sign, .verify = rsa_verify, .final = rsa_final, + .match = rsa_match, }; diff --git a/roms/ipxe/src/crypto/x509.c b/roms/ipxe/src/crypto/x509.c index df3c5c0de..0502efa28 100644 --- a/roms/ipxe/src/crypto/x509.c +++ b/roms/ipxe/src/crypto/x509.c @@ -24,7 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> #include <assert.h> #include <ipxe/list.h> -#include <ipxe/malloc.h> +#include <ipxe/base16.h> #include <ipxe/asn1.h> #include <ipxe/crypto.h> #include <ipxe/md5.h> @@ -32,7 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/sha256.h> #include <ipxe/rsa.h> #include <ipxe/rootcert.h> +#include <ipxe/certstore.h> #include <ipxe/x509.h> +#include <config/crypto.h> /** @file * @@ -103,51 +105,43 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EACCES_OCSP_REQUIRED ) #define EINFO_EACCES_OCSP_REQUIRED \ __einfo_uniqify ( EINFO_EACCES, 0x09, "OCSP check required" ) - -/** Certificate cache */ -static LIST_HEAD ( x509_cache ); - -/** - * Free X.509 certificate - * - * @v refcnt Reference count - */ -static void x509_free ( struct refcnt *refcnt ) { - struct x509_certificate *cert = - container_of ( refcnt, struct x509_certificate, refcnt ); - - DBGC2 ( cert, "X509 %p freed\n", cert ); - free ( cert->subject.name ); - free ( cert->extensions.auth_info.ocsp.uri ); - free ( cert ); -} +#define EACCES_WRONG_NAME \ + __einfo_error ( EINFO_EACCES_WRONG_NAME ) +#define EINFO_EACCES_WRONG_NAME \ + __einfo_uniqify ( EINFO_EACCES, 0x0a, "Incorrect certificate name" ) +#define EACCES_USELESS \ + __einfo_error ( EINFO_EACCES_USELESS ) +#define EINFO_EACCES_USELESS \ + __einfo_uniqify ( EINFO_EACCES, 0x0b, "No usable certificates" ) /** - * Discard a cached certificate + * Get X.509 certificate name (for debugging) * - * @ret discarded Number of cached items discarded + * @v cert X.509 certificate + * @ret name Name (for debugging) */ -static unsigned int x509_discard ( void ) { - struct x509_certificate *cert; +const char * x509_name ( struct x509_certificate *cert ) { + struct asn1_cursor *common_name = &cert->subject.common_name; + struct digest_algorithm *digest = &sha1_algorithm; + static char buf[64]; + uint8_t fingerprint[ digest->digestsize ]; + size_t len; - /* Discard the least recently used certificate for which the - * only reference is held by the cache itself. - */ - list_for_each_entry_reverse ( cert, &x509_cache, list ) { - if ( cert->refcnt.count == 0 ) { - list_del ( &cert->list ); - x509_put ( cert ); - return 1; - } + len = common_name->len; + if ( len ) { + /* Certificate has a commonName: use that */ + if ( len > ( sizeof ( buf ) - 1 /* NUL */ ) ) + len = ( sizeof ( buf ) - 1 /* NUL */ ); + memcpy ( buf, common_name->data, len ); + buf[len] = '\0'; + } else { + /* Certificate has no commonName: use SHA-1 fingerprint */ + x509_fingerprint ( cert, digest, fingerprint ); + base16_encode ( fingerprint, sizeof ( fingerprint ), buf ); } - return 0; + return buf; } -/** X.509 cache discarder */ -struct cache_discarder x509_discarder __cache_discarder ( CACHE_NORMAL ) = { - .discard = x509_discard, -}; - /** "commonName" object identifier */ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; @@ -292,11 +286,10 @@ static int x509_parse_validity ( struct x509_certificate *cert, * Parse X.509 certificate common name * * @v cert X.509 certificate - * @v name Common name to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int x509_parse_common_name ( struct x509_certificate *cert, char **name, +static int x509_parse_common_name ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_cursor oid_cursor; @@ -325,19 +318,9 @@ static int x509_parse_common_name ( struct x509_certificate *cert, char **name, return rc; } - /* Allocate and copy name */ - *name = zalloc ( name_cursor.len + 1 /* NUL */ ); - if ( ! *name ) - return -ENOMEM; - memcpy ( *name, name_cursor.data, name_cursor.len ); - - /* Check that name contains no NULs */ - if ( strlen ( *name ) != name_cursor.len ) { - DBGC ( cert, "X509 %p contains malicious commonName:\n", - cert ); - DBGC_HDA ( cert, 0, raw->data, raw->len ); - return rc; - } + /* Record common name */ + memcpy ( &cert->subject.common_name, &name_cursor, + sizeof ( cert->subject.common_name ) ); return 0; } @@ -357,7 +340,6 @@ static int x509_parse_common_name ( struct x509_certificate *cert, char **name, static int x509_parse_subject ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_subject *subject = &cert->subject; - char **name = &subject->name; int rc; /* Record raw subject */ @@ -367,9 +349,10 @@ static int x509_parse_subject ( struct x509_certificate *cert, DBGC2_HDA ( cert, 0, subject->raw.data, subject->raw.len ); /* Parse common name */ - if ( ( rc = x509_parse_common_name ( cert, name, raw ) ) != 0 ) + if ( ( rc = x509_parse_common_name ( cert, raw ) ) != 0 ) return rc; - DBGC2 ( cert, "X509 %p common name is \"%s\":\n", cert, *name ); + DBGC2 ( cert, "X509 %p common name is \"%s\":\n", cert, + x509_name ( cert ) ); return 0; } @@ -615,24 +598,19 @@ static int x509_parse_extended_key_usage ( struct x509_certificate *cert, static int x509_parse_ocsp ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_ocsp_responder *ocsp = &cert->extensions.auth_info.ocsp; - struct asn1_cursor cursor; + struct asn1_cursor *uri = &ocsp->uri; int rc; /* Enter accessLocation */ - memcpy ( &cursor, raw, sizeof ( cursor ) ); - if ( ( rc = asn1_enter ( &cursor, ASN1_IMPLICIT_TAG ( 6 ) ) ) != 0 ) { + memcpy ( uri, raw, sizeof ( *uri ) ); + if ( ( rc = asn1_enter ( uri, X509_GENERAL_NAME_URI ) ) != 0 ) { DBGC ( cert, "X509 %p OCSP does not contain " "uniformResourceIdentifier:\n", cert ); DBGC_HDA ( cert, 0, raw->data, raw->len ); return rc; } - - /* Record URI */ - ocsp->uri = zalloc ( cursor.len + 1 /* NUL */ ); - if ( ! ocsp->uri ) - return -ENOMEM; - memcpy ( ocsp->uri, cursor.data, cursor.len ); - DBGC2 ( cert, "X509 %p OCSP URI is %s:\n", cert, ocsp->uri ); + DBGC2 ( cert, "X509 %p OCSP URI is:\n", cert ); + DBGC2_HDA ( cert, 0, uri->data, uri->len ); return 0; } @@ -730,6 +708,33 @@ static int x509_parse_authority_info_access ( struct x509_certificate *cert, return 0; } +/** + * Parse X.509 certificate subject alternative name + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_subject_alt_name ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_subject_alt_name *alt_name = &cert->extensions.alt_name; + struct asn1_cursor *names = &alt_name->names; + int rc; + + /* Enter subjectAltName */ + memcpy ( names, raw, sizeof ( *names ) ); + if ( ( rc = asn1_enter ( names, ASN1_SEQUENCE ) ) != 0 ) { + DBGC ( cert, "X509 %p invalid subjectAltName: %s\n", + cert, strerror ( rc ) ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + DBGC2 ( cert, "X509 %p has subjectAltName:\n", cert ); + DBGC2_HDA ( cert, 0, names->data, names->len ); + + return 0; +} + /** "id-ce-basicConstraints" object identifier */ static uint8_t oid_ce_basic_constraints[] = { ASN1_OID_BASICCONSTRAINTS }; @@ -746,6 +751,10 @@ static uint8_t oid_ce_ext_key_usage[] = static uint8_t oid_pe_authority_info_access[] = { ASN1_OID_AUTHORITYINFOACCESS }; +/** "id-ce-subjectAltName" object identifier */ +static uint8_t oid_ce_subject_alt_name[] = + { ASN1_OID_SUBJECTALTNAME }; + /** Supported certificate extensions */ static struct x509_extension x509_extensions[] = { { @@ -768,6 +777,11 @@ static struct x509_extension x509_extensions[] = { .oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ), .parse = x509_parse_authority_info_access, }, + { + .name = "subjectAltName", + .oid = ASN1_OID_CURSOR ( oid_ce_subject_alt_name ), + .parse = x509_parse_subject_alt_name, + }, }; /** @@ -963,8 +977,8 @@ static int x509_parse_tbscertificate ( struct x509_certificate *cert, * @v raw ASN.1 cursor * @ret rc Return status code */ -static int x509_parse ( struct x509_certificate *cert, - const struct asn1_cursor *raw ) { +int x509_parse ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { struct x509_signature *signature = &cert->signature; struct asn1_algorithm **signature_algorithm = &signature->algorithm; struct asn1_bit_string *signature_value = &signature->value; @@ -1040,30 +1054,19 @@ int x509_certificate ( const void *data, size_t len, cursor.len = len; asn1_shrink_any ( &cursor ); - /* Search for certificate within cache */ - list_for_each_entry ( (*cert), &x509_cache, list ) { - if ( asn1_compare ( &cursor, &(*cert)->raw ) == 0 ) { - - DBGC2 ( *cert, "X509 %p \"%s\" cache hit\n", - *cert, (*cert)->subject.name ); - - /* Mark as most recently used */ - list_del ( &(*cert)->list ); - list_add ( &(*cert)->list, &x509_cache ); + /* Return stored certificate, if present */ + if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) { - /* Add caller's reference */ - x509_get ( *cert ); - - return 0; - } + /* Add caller's reference */ + x509_get ( *cert ); + return 0; } /* Allocate and initialise certificate */ *cert = zalloc ( sizeof ( **cert ) + cursor.len ); if ( ! *cert ) return -ENOMEM; - ref_init ( &(*cert)->refcnt, x509_free ); - INIT_LIST_HEAD ( &(*cert)->list ); + ref_init ( &(*cert)->refcnt, NULL ); raw = ( *cert + 1 ); /* Copy raw data */ @@ -1077,9 +1080,8 @@ int x509_certificate ( const void *data, size_t len, return rc; } - /* Add certificate to cache */ - x509_get ( *cert ); - list_add ( &(*cert)->list, &x509_cache ); + /* Add certificate to store */ + certstore_add ( *cert ); return 0; } @@ -1109,14 +1111,14 @@ static int x509_check_signature ( struct x509_certificate *cert, digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len ); digest_final ( digest, digest_ctx, digest_out ); - DBGC2 ( cert, "X509 %p \"%s\" digest:\n", cert, cert->subject.name ); + DBGC2 ( cert, "X509 %p \"%s\" digest:\n", cert, x509_name ( cert ) ); DBGC2_HDA ( cert, 0, digest_out, sizeof ( digest_out ) ); /* Check that signature public key algorithm matches signer */ if ( public_key->algorithm->pubkey != pubkey ) { DBGC ( cert, "X509 %p \"%s\" signature algorithm %s does not " "match signer's algorithm %s\n", - cert, cert->subject.name, algorithm->name, + cert, x509_name ( cert ), algorithm->name, public_key->algorithm->name ); rc = -EINVAL_ALGORITHM_MISMATCH; goto err_mismatch; @@ -1126,14 +1128,14 @@ static int x509_check_signature ( struct x509_certificate *cert, if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, public_key->raw.len ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: " - "%s\n", cert, cert->subject.name, strerror ( rc ) ); + "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_init; } if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, signature->value.data, signature->value.len ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" signature verification failed: " - "%s\n", cert, cert->subject.name, strerror ( rc ) ); + "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_verify; } @@ -1172,9 +1174,10 @@ int x509_check_issuer ( struct x509_certificate *cert, * for some enjoyable ranting on this subject. */ if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) { - DBGC ( cert, "X509 %p \"%s\" issuer does not match X509 %p " - "\"%s\" subject\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" issuer does not match ", + cert, x509_name ( cert ) ); + DBGC ( cert, "X509 %p \"%s\" subject\n", + issuer, x509_name ( issuer ) ); DBGC_HDA ( cert, 0, cert->issuer.raw.data, cert->issuer.raw.len ); DBGC_HDA ( issuer, 0, issuer->subject.raw.data, @@ -1184,16 +1187,18 @@ int x509_check_issuer ( struct x509_certificate *cert, /* Check that issuer is allowed to sign certificates */ if ( ! issuer->extensions.basic.ca ) { - DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": " - "not a CA certificate\n", issuer, issuer->subject.name, - cert, cert->subject.name ); + DBGC ( issuer, "X509 %p \"%s\" cannot sign ", + issuer, x509_name ( issuer ) ); + DBGC ( issuer, "X509 %p \"%s\": not a CA certificate\n", + cert, x509_name ( cert ) ); return -EACCES_NOT_CA; } if ( issuer->extensions.usage.present && ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) { - DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": " - "no keyCertSign usage\n", issuer, issuer->subject.name, - cert, cert->subject.name ); + DBGC ( issuer, "X509 %p \"%s\" cannot sign ", + issuer, x509_name ( issuer ) ); + DBGC ( issuer, "X509 %p \"%s\": no keyCertSign usage\n", + cert, x509_name ( cert ) ); return -EACCES_KEY_USAGE; } @@ -1226,7 +1231,7 @@ void x509_fingerprint ( struct x509_certificate *cert, * Check X.509 root certificate * * @v cert X.509 certificate - * @v root X.509 root certificate store + * @v root X.509 root certificate list * @ret rc Return status code */ int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) { @@ -1243,14 +1248,14 @@ int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) { if ( memcmp ( fingerprint, root_fingerprint, sizeof ( fingerprint ) ) == 0 ) { DBGC ( cert, "X509 %p \"%s\" is a root certificate\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return 0; } root_fingerprint += sizeof ( fingerprint ); } DBGC2 ( cert, "X509 %p \"%s\" is not a root certificate\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return -ENOENT; } @@ -1265,19 +1270,19 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) { struct x509_validity *validity = &cert->validity; /* Check validity period */ - if ( validity->not_before.time > ( time + X509_ERROR_MARGIN_TIME ) ) { + if ( validity->not_before.time > ( time + TIMESTAMP_ERROR_MARGIN ) ) { DBGC ( cert, "X509 %p \"%s\" is not yet valid (at time %lld)\n", - cert, cert->subject.name, time ); + cert, x509_name ( cert ), time ); return -EACCES_EXPIRED; } - if ( validity->not_after.time < ( time - X509_ERROR_MARGIN_TIME ) ) { + if ( validity->not_after.time < ( time - TIMESTAMP_ERROR_MARGIN ) ) { DBGC ( cert, "X509 %p \"%s\" has expired (at time %lld)\n", - cert, cert->subject.name, time ); + cert, x509_name ( cert ), time ); return -EACCES_EXPIRED; } DBGC2 ( cert, "X509 %p \"%s\" is valid (at time %lld)\n", - cert, cert->subject.name, time ); + cert, x509_name ( cert ), time ); return 0; } @@ -1287,7 +1292,7 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) { * @v cert X.509 certificate * @v issuer Issuing X.509 certificate (or NULL) * @v time Time at which to validate certificate - * @v root Root certificate store, or NULL to use default + * @v root Root certificate list, or NULL to use default * @ret rc Return status code * * The issuing certificate must have already been validated. @@ -1324,15 +1329,15 @@ int x509_validate ( struct x509_certificate *cert, /* Fail unless we have an issuer */ if ( ! issuer ) { DBGC2 ( cert, "X509 %p \"%s\" has no issuer\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return -EACCES_UNTRUSTED; } /* Fail unless issuer has already been validated */ if ( ! issuer->valid ) { - DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" has not yet " - "been validated\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) ); + DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n", + issuer, x509_name ( issuer ) ); return -EACCES_OUT_OF_ORDER; } @@ -1342,17 +1347,17 @@ int x509_validate ( struct x509_certificate *cert, /* Fail if path length constraint is violated */ if ( issuer->path_remaining == 0 ) { - DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" path length " - "exceeded\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) ); + DBGC ( cert, "issuer %p \"%s\" path length exceeded\n", + issuer, x509_name ( issuer ) ); return -EACCES_PATH_LEN; } /* Fail if OCSP is required */ - if ( cert->extensions.auth_info.ocsp.uri && + if ( cert->extensions.auth_info.ocsp.uri.len && ( ! cert->extensions.auth_info.ocsp.good ) ) { DBGC ( cert, "X509 %p \"%s\" requires an OCSP check\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return -EACCES_OCSP_REQUIRED; } @@ -1365,13 +1370,121 @@ int x509_validate ( struct x509_certificate *cert, /* Mark certificate as valid */ cert->valid = 1; - DBGC ( cert, "X509 %p \"%s\" successfully validated using issuer %p " - "\"%s\"\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" successfully validated using ", + cert, x509_name ( cert ) ); + DBGC ( cert, "issuer %p \"%s\"\n", issuer, x509_name ( issuer ) ); + return 0; +} + +/** + * Check X.509 certificate alternative dNSName + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @v name Name + * @ret rc Return status code + */ +static int x509_check_dnsname ( struct x509_certificate *cert, + const struct asn1_cursor *raw, + const char *name ) { + const char *fullname = name; + const char *dnsname = raw->data; + size_t len = raw->len; + + /* Check for wildcards */ + if ( ( len >= 2 ) && ( dnsname[0] == '*' ) && ( dnsname[1] == '.' ) ) { + + /* Skip initial "*." */ + dnsname += 2; + len -= 2; + + /* Skip initial portion of name to be tested */ + name = strchr ( name, '.' ); + if ( ! name ) + return -ENOENT; + name++; + } + + /* Compare names */ + if ( ! ( ( strlen ( name ) == len ) && + ( memcmp ( name, dnsname, len ) == 0 ) ) ) + return -ENOENT; + + if ( name != fullname ) { + DBGC2 ( cert, "X509 %p \"%s\" found wildcard match for " + "\"*.%s\"\n", cert, x509_name ( cert ), name ); + } return 0; } /** + * Check X.509 certificate alternative name + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @v name Name + * @ret rc Return status code + */ +static int x509_check_alt_name ( struct x509_certificate *cert, + const struct asn1_cursor *raw, + const char *name ) { + struct asn1_cursor alt_name; + unsigned int type; + + /* Enter generalName */ + memcpy ( &alt_name, raw, sizeof ( alt_name ) ); + type = asn1_type ( &alt_name ); + asn1_enter_any ( &alt_name ); + + /* Check this name */ + switch ( type ) { + case X509_GENERAL_NAME_DNS : + return x509_check_dnsname ( cert, &alt_name, name ); + default: + DBGC2 ( cert, "X509 %p \"%s\" unknown name of type %#02x:\n", + cert, x509_name ( cert ), type ); + DBGC2_HDA ( cert, 0, alt_name.data, alt_name.len ); + return -ENOTSUP; + } +} + +/** + * Check X.509 certificate name + * + * @v cert X.509 certificate + * @v name Name + * @ret rc Return status code + */ +int x509_check_name ( struct x509_certificate *cert, const char *name ) { + struct asn1_cursor *common_name = &cert->subject.common_name; + struct asn1_cursor alt_name; + int rc; + + /* Check commonName */ + if ( x509_check_dnsname ( cert, common_name, name ) == 0 ) { + DBGC2 ( cert, "X509 %p \"%s\" commonName matches \"%s\"\n", + cert, x509_name ( cert ), name ); + return 0; + } + + /* Check any subjectAlternativeNames */ + memcpy ( &alt_name, &cert->extensions.alt_name.names, + sizeof ( alt_name ) ); + for ( ; alt_name.len ; asn1_skip_any ( &alt_name ) ) { + if ( ( rc = x509_check_alt_name ( cert, &alt_name, + name ) ) == 0 ) { + DBGC2 ( cert, "X509 %p \"%s\" subjectAltName matches " + "\"%s\"\n", cert, x509_name ( cert ), name ); + return 0; + } + } + + DBGC ( cert, "X509 %p \"%s\" does not match name \"%s\"\n", + cert, x509_name ( cert ), name ); + return -EACCES_WRONG_NAME; +} + +/** * Free X.509 certificate chain * * @v refcnt Reference count @@ -1435,7 +1548,7 @@ int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) { link->cert = x509_get ( cert ); list_add_tail ( &link->list, &chain->links ); DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n", - chain, cert, cert->subject.name ); + chain, cert, x509_name ( cert ) ); return 0; } @@ -1516,7 +1629,7 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) { cert = x509_last ( chain ); if ( ! cert ) { DBGC ( chain, "X509 chain %p has no certificates\n", chain ); - return -EINVAL; + return -EACCES_EMPTY; } /* Append certificates, in order */ @@ -1543,20 +1656,23 @@ int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) { * * @v chain X.509 certificate chain * @v time Time at which to validate certificates - * @v root Root certificate store, or NULL to use default + * @v store Certificate store, or NULL to use default + * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ int x509_validate_chain ( struct x509_chain *chain, time_t time, - struct x509_root *root ) { + struct x509_chain *store, struct x509_root *root ) { struct x509_certificate *issuer = NULL; struct x509_link *link; int rc; - /* Sanity check */ - if ( list_empty ( &chain->links ) ) { - DBGC ( chain, "X509 chain %p is empty\n", chain ); - return -EACCES_EMPTY; - } + /* Use default certificate store if none specified */ + if ( ! store ) + store = &certstore; + + /* Append any applicable certificates from the certificate store */ + if ( ( rc = x509_auto_append ( chain, store ) ) != 0 ) + return rc; /* Find first certificate that can be validated as a * standalone (i.e. is already valid, or can be validated as @@ -1586,6 +1702,9 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time, return 0; } - DBGC ( chain, "X509 chain %p found no valid certificates\n", chain ); - return -EACCES_UNTRUSTED; + DBGC ( chain, "X509 chain %p found no usable certificates\n", chain ); + return -EACCES_USELESS; } + +/* Drag in certificate store */ +REQUIRE_OBJECT ( certstore ); diff --git a/roms/ipxe/src/drivers/block/ibft.c b/roms/ipxe/src/drivers/block/ibft.c index f16096377..0700f8c4f 100644 --- a/roms/ipxe/src/drivers/block/ibft.c +++ b/roms/ipxe/src/drivers/block/ibft.c @@ -37,6 +37,7 @@ FILE_LICENCE ( BSD2 ); #include <ipxe/in.h> #include <ipxe/netdevice.h> #include <ipxe/ethernet.h> +#include <ipxe/vlan.h> #include <ipxe/dhcp.h> #include <ipxe/iscsi.h> #include <ipxe/ibft.h> @@ -106,7 +107,7 @@ static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) { * @v count Maximum number of IP addresses */ static void ibft_set_ipaddr_setting ( struct ibft_ipaddr *ipaddr, - struct setting *setting, + const struct setting *setting, unsigned int count ) { struct in_addr in[count]; unsigned int i; @@ -182,11 +183,13 @@ static int ibft_set_string ( struct ibft_strings *strings, */ static int ibft_set_string_setting ( struct ibft_strings *strings, struct ibft_string *string, - struct setting *setting ) { + const struct setting *setting ) { + struct settings *origin; + struct setting fetched; int len; char *dest; - len = fetch_setting_len ( NULL, setting ); + len = fetch_setting ( NULL, setting, &origin, &fetched, NULL, 0 ); if ( len < 0 ) { string->offset = 0; string->len = 0; @@ -196,7 +199,7 @@ static int ibft_set_string_setting ( struct ibft_strings *strings, dest = ibft_alloc_string ( strings, string, len ); if ( ! dest ) return -ENOBUFS; - fetch_string_setting ( NULL, setting, dest, ( len + 1 ) ); + fetch_string_setting ( origin, &fetched, dest, ( len + 1 )); return 0; } @@ -264,6 +267,8 @@ 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 */ + nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) ); + DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) ); if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, nic->mac_address ) ) != 0 ) { DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) ); diff --git a/roms/ipxe/src/drivers/block/scsi.c b/roms/ipxe/src/drivers/block/scsi.c index b45ae6304..4245f019b 100644 --- a/roms/ipxe/src/drivers/block/scsi.c +++ b/roms/ipxe/src/drivers/block/scsi.c @@ -89,7 +89,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define EINFO_EIO_COMPLETED \ __einfo_uniqify ( EINFO_EIO, 0x0f, "Completed" ) #define EIO_SENSE( key ) \ - EUNIQ ( EIO, (key), EIO_NO_SENSE, EIO_RECOVERED_ERROR, \ + EUNIQ ( EINFO_EIO, (key), EIO_NO_SENSE, EIO_RECOVERED_ERROR, \ EIO_NOT_READY, EIO_MEDIUM_ERROR, EIO_HARDWARE_ERROR, \ EIO_ILLEGAL_REQUEST, EIO_UNIT_ATTENTION, \ EIO_DATA_PROTECT, EIO_BLANK_CHECK, EIO_VENDOR_SPECIFIC, \ diff --git a/roms/ipxe/src/drivers/block/srp.c b/roms/ipxe/src/drivers/block/srp.c index 098a973eb..70a97b2f9 100644 --- a/roms/ipxe/src/drivers/block/srp.c +++ b/roms/ipxe/src/drivers/block/srp.c @@ -93,7 +93,7 @@ FEATURE ( FEATURE_PROTOCOL, "SRP", DHCP_EB_FEATURE_SRP, 1 ); SRP_LOGIN_REJ_REASON_NO_MORE_CHANNELS, \ "RDMA channel limit reached for this initiator" ) #define EPERM_LOGIN_REJ( reason_nibble ) \ - EUNIQ ( EPERM, (reason_nibble), EPERM_UNKNOWN, \ + EUNIQ ( EINFO_EPERM, (reason_nibble), EPERM_UNKNOWN, \ EPERM_INSUFFICIENT_RESOURCES, EPERM_BAD_MAX_I_T_IU_LEN, \ EPERM_CANNOT_ASSOCIATE, EPERM_UNSUPPORTED_BUFFER_FORMAT, \ EPERM_NO_MULTIPLE_CHANNELS, EPERM_NO_MORE_CHANNELS ) diff --git a/roms/ipxe/src/drivers/bus/pci.c b/roms/ipxe/src/drivers/bus/pci.c index 7bd353d8b..4a8d00b54 100644 --- a/roms/ipxe/src/drivers/bus/pci.c +++ b/roms/ipxe/src/drivers/bus/pci.c @@ -171,8 +171,20 @@ void adjust_pci_device ( struct pci_device *pci ) { * @ret rc Return status code */ int pci_read_config ( struct pci_device *pci ) { + uint16_t busdevfn; + uint8_t hdrtype; uint32_t tmp; + /* Ignore all but the first function on non-multifunction devices */ + if ( PCI_FUNC ( pci->busdevfn ) != 0 ) { + busdevfn = pci->busdevfn; + pci->busdevfn = PCI_FIRST_FUNC ( pci->busdevfn ); + pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype ); + pci->busdevfn = busdevfn; + if ( ! ( hdrtype & 0x80 ) ) + return -ENODEV; + } + /* Check for physical device presence */ pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp ); if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) ) @@ -204,6 +216,32 @@ int pci_read_config ( struct pci_device *pci ) { } /** + * Find next device on PCI bus + * + * @v pci PCI device to fill in + * @v busdevfn Starting bus:dev.fn address + * @ret busdevfn Bus:dev.fn address of next PCI device, or negative error + */ +int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) { + static unsigned int end; + int rc; + + /* Determine number of PCI buses */ + if ( ! end ) + end = PCI_BUSDEVFN ( pci_num_bus(), 0, 0 ); + + /* Find next PCI device, if any */ + for ( ; busdevfn < end ; busdevfn++ ) { + memset ( pci, 0, sizeof ( *pci ) ); + pci_init ( pci, busdevfn ); + if ( ( rc = pci_read_config ( pci ) ) == 0 ) + return busdevfn; + } + + return -ENODEV; +} + +/** * Find driver for PCI device * * @v pci PCI device @@ -276,14 +314,10 @@ void pci_remove ( struct pci_device *pci ) { */ static int pcibus_probe ( struct root_device *rootdev ) { struct pci_device *pci = NULL; - unsigned int num_bus; - unsigned int busdevfn; - uint8_t hdrtype = 0; + int busdevfn = 0; int rc; - num_bus = pci_num_bus(); - for ( busdevfn = 0 ; busdevfn < PCI_BUSDEVFN ( num_bus, 0, 0 ) ; - busdevfn++ ) { + for ( busdevfn = 0 ; 1 ; busdevfn++ ) { /* Allocate struct pci_device */ if ( ! pci ) @@ -292,22 +326,11 @@ static int pcibus_probe ( struct root_device *rootdev ) { rc = -ENOMEM; goto err; } - memset ( pci, 0, sizeof ( *pci ) ); - pci_init ( pci, busdevfn ); - - /* Skip all but the first function on - * non-multifunction cards - */ - if ( PCI_FUNC ( busdevfn ) == 0 ) { - pci_read_config_byte ( pci, PCI_HEADER_TYPE, - &hdrtype ); - } else if ( ! ( hdrtype & 0x80 ) ) { - continue; - } - /* Read device configuration */ - if ( ( rc = pci_read_config ( pci ) ) != 0 ) - continue; + /* Find next PCI device, if any */ + busdevfn = pci_find_next ( pci, busdevfn ); + if ( busdevfn < 0 ) + break; /* Look for a driver */ if ( ( rc = pci_find_driver ( pci ) ) != 0 ) { diff --git a/roms/ipxe/src/drivers/bus/pci_settings.c b/roms/ipxe/src/drivers/bus/pci_settings.c new file mode 100644 index 000000000..db20452e0 --- /dev/null +++ b/roms/ipxe/src/drivers/bus/pci_settings.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <errno.h> +#include <ipxe/pci.h> +#include <ipxe/settings.h> +#include <ipxe/init.h> + +/** @file + * + * PCI device settings + * + */ + +/** PCI device settings scope */ +static const struct settings_scope pci_settings_scope; + +/** + * Check applicability of PCI device setting + * + * @v settings Settings block + * @v setting Setting + * @ret applies Setting applies within this settings block + */ +static int pci_settings_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &pci_settings_scope ); +} + +/** + * Fetch value of PCI device setting + * + * @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 + */ +static int pci_settings_fetch ( struct settings *settings __unused, + struct setting *setting, + void *data, size_t len ) { + struct pci_device pci; + unsigned int tag_busdevfn; + unsigned int tag_offset; + unsigned int tag_len; + unsigned int i; + + /* Extract busdevfn, offset, and length from tag */ + tag_busdevfn = ( ( setting->tag >> 16 ) & 0xffff ); + tag_offset = ( ( setting->tag >> 8 ) & 0xff ); + tag_len = ( ( setting->tag >> 0 ) & 0xff ); + + /* Locate PCI device */ + memset ( &pci, 0, sizeof ( pci ) ); + pci_init ( &pci, tag_busdevfn ); + DBG ( PCI_FMT " reading %#02x+%#x\n", PCI_ARGS ( &pci ), + tag_offset, tag_len ); + + /* Read data one byte at a time, in reverse order (since PCI + * is little-endian and iPXE settings are essentially + * big-endian). + */ + tag_offset += tag_len; + for ( i = 0 ; ( ( i < tag_len ) && ( i < len ) ); i++ ) { + pci_read_config_byte ( &pci, --tag_offset, data++ ); + } + + /* Set type to ":hexraw" if not already specified */ + if ( ! setting->type ) + setting->type = &setting_type_hexraw; + + return tag_len; +} + +/** PCI device settings operations */ +static struct settings_operations pci_settings_operations = { + .applies = pci_settings_applies, + .fetch = pci_settings_fetch, +}; + +/** PCI device settings */ +static struct settings pci_settings = { + .refcnt = NULL, + .siblings = LIST_HEAD_INIT ( pci_settings.siblings ), + .children = LIST_HEAD_INIT ( pci_settings.children ), + .op = &pci_settings_operations, + .default_scope = &pci_settings_scope, +}; + +/** Initialise PCI device settings */ +static void pci_settings_init ( void ) { + int rc; + + if ( ( rc = register_settings ( &pci_settings, NULL, "pci" ) ) != 0 ) { + DBG ( "PCI could not register settings: %s\n", + strerror ( rc ) ); + return; + } +} + +/** PCI device settings initialiser */ +struct init_fn pci_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = pci_settings_init, +}; diff --git a/roms/ipxe/src/drivers/linux/tap.c b/roms/ipxe/src/drivers/linux/tap.c index 53bb16a30..979436654 100644 --- a/roms/ipxe/src/drivers/linux/tap.c +++ b/roms/ipxe/src/drivers/linux/tap.c @@ -200,11 +200,6 @@ static int tap_probe(struct linux_device *device, struct linux_device_request *r netdev->dev = &device->dev; memset(nic, 0, sizeof(*nic)); - if ((rc = register_netdev(netdev)) != 0) - goto err_register; - - netdev_link_up(netdev); - /* Look for the mandatory if setting */ if_setting = linux_find_setting("if", &request->settings); @@ -216,11 +211,20 @@ static int tap_probe(struct linux_device *device, struct linux_device_request *r } nic->interface = if_setting->value; + snprintf ( device->dev.name, sizeof ( device->dev.name ), "%s", + nic->interface ); + device->dev.desc.bus_type = BUS_TYPE_TAP; if_setting->applied = 1; /* Apply rest of the settings */ linux_apply_settings(&request->settings, &netdev->settings.settings); + /* Register network device */ + if ((rc = register_netdev(netdev)) != 0) + goto err_register; + + netdev_link_up(netdev); + return 0; err_settings: diff --git a/roms/ipxe/src/drivers/net/3c515.c b/roms/ipxe/src/drivers/net/3c515.c index 0aa68b1aa..1591e0617 100644 --- a/roms/ipxe/src/drivers/net/3c515.c +++ b/roms/ipxe/src/drivers/net/3c515.c @@ -389,7 +389,7 @@ static void t515_reset(struct nic *nic) outb(PKT_BUF_SZ >> 8, nic->ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Tx ring. */ for (i = 0; i < TX_RING_SIZE; i++) - vp->tx_skbuff[i] = 0; + vp->tx_skbuff[i] = NULL; outl(0, nic->ioaddr + DownListPtr); } /* Set receiver mode: presumably accept b-case and phys addr only. */ diff --git a/roms/ipxe/src/drivers/net/3c595.c b/roms/ipxe/src/drivers/net/3c595.c index 1aa8ed641..2338c54b7 100644 --- a/roms/ipxe/src/drivers/net/3c595.c +++ b/roms/ipxe/src/drivers/net/3c595.c @@ -399,7 +399,7 @@ vxsetlink(void) i = vx_connector; /* default in EEPROM */ reason = "default"; - warning = 0; + warning = NULL; if ((vx_connectors & conn_tab[vx_connector].bit) == 0) { warning = "strange connector type in EEPROM."; @@ -407,7 +407,7 @@ vxsetlink(void) i = CONNECTOR_UTP; } - if (warning != 0) { + if (warning) { printf("warning: %s\n", warning); } printf("selected %s. (%s)\n", conn_tab[i].name, reason); diff --git a/roms/ipxe/src/drivers/net/3c90x.c b/roms/ipxe/src/drivers/net/3c90x.c index c19005746..853de2b52 100644 --- a/roms/ipxe/src/drivers/net/3c90x.c +++ b/roms/ipxe/src/drivers/net/3c90x.c @@ -346,11 +346,12 @@ static int a3c90x_transmit(struct net_device *netdev, tx_cur_desc->DnNextPtr = 0; /* FrameStartHeader differs in 90x and >= 90xB - * It contains length in 90x and a round up boundary and packet ID for - * 90xB and 90xC. We can leave this to 0 for 90xB and 90xC. + * It contains the packet length in 90x and a round up boundary and + * packet ID for 90xB and 90xC. Disable packet length round-up on the + * later revisions. */ tx_cur_desc->FrameStartHeader = - fshTxIndicate | (inf_3c90x->isBrev ? 0x00 : len); + fshTxIndicate | (inf_3c90x->isBrev ? fshRndupDefeat : len); tx_cur_desc->DataAddr = virt_to_bus(iob->data); tx_cur_desc->DataLength = len | downLastFrag; @@ -813,10 +814,18 @@ static int a3c90x_open(struct net_device *netdev) goto error; } + a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl, upStall); + /* send rx_ring address to NIC */ outl(virt_to_bus(inf_3c90x->rx_ring), inf_3c90x->IOAddr + regUpListPtr_l); + a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl, upUnStall); + + /* set maximum allowed receive packet length */ + a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3); + outl(RX_BUF_SIZE, inf_3c90x->IOAddr + regMaxPktSize_3_w); + /* enable packet transmission and reception */ a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0); a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0); diff --git a/roms/ipxe/src/drivers/net/3c90x.h b/roms/ipxe/src/drivers/net/3c90x.h index 53fc522bf..8bffa37f1 100644 --- a/roms/ipxe/src/drivers/net/3c90x.h +++ b/roms/ipxe/src/drivers/net/3c90x.h @@ -202,6 +202,7 @@ enum GlobalResetParams { enum FrameStartHeader { fshTxIndicate = 0x8000, fshDnComplete = 0x10000, + fshRndupDefeat = 0x10000000, }; enum UpDownDesc { diff --git a/roms/ipxe/src/drivers/net/ath/ath.h b/roms/ipxe/src/drivers/net/ath/ath.h index 5a19a19cd..42ad59f78 100644 --- a/roms/ipxe/src/drivers/net/ath/ath.h +++ b/roms/ipxe/src/drivers/net/ath/ath.h @@ -20,6 +20,8 @@ #ifndef ATH_H #define ATH_H +FILE_LICENCE ( BSD2 ); + #include <unistd.h> #include <ipxe/net80211.h> diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ani.h b/roms/ipxe/src/drivers/net/ath/ath9k/ani.h index 9a333b5f7..dbd4d4d5b 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ani.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ani.h @@ -20,6 +20,8 @@ #ifndef ANI_H #define ANI_H +FILE_LICENCE ( BSD2 ); + #define HAL_PROCESS_ANI 0x00000001 #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan) diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h index 479aed547..fcc155654 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +FILE_LICENCE ( BSD2 ); + static const u32 ar5416Modes[][6] = { {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h index 7dca47443..6c1ccd50e 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +FILE_LICENCE ( BSD2 ); + static const u32 ar5416Modes_9100[][6] = { {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h index dd121513b..d7a5ac09f 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +FILE_LICENCE ( BSD2 ); + static const u32 ar9280Modes_9280_2[][6] = { {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h index 453af6dc5..71d9162c9 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h @@ -16,6 +16,8 @@ #ifndef AR9002_PHY_H #define AR9002_PHY_H +FILE_LICENCE ( BSD2 ); + #define AR_PHY_TEST 0x9800 #define PHY_AGC_CLR 0x10000000 #define RFSILENT_BB 0x00002000 diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h index 393f2de52..f03879236 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h @@ -20,6 +20,8 @@ #ifndef AR9003_EEPROM_H #define AR9003_EEPROM_H +FILE_LICENCE ( BSD2 ); + #define AR9300_EEP_VER 0xD000 #define AR9300_EEP_VER_MINOR_MASK 0xFFF #define AR9300_EEP_MINOR_VER_1 0x1 diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h index d2dce9b7b..36dc97e99 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h @@ -20,6 +20,8 @@ #ifndef ATH9K_H #define ATH9K_H +FILE_LICENCE ( BSD2 ); + #include "common.h" /* diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c index cc4edece4..85d0c7de6 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +FILE_LICENCE ( BSD2 ); + #include "hw.h" #include "ar5008_initvals.h" #include "ar9001_initvals.h" diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c index 93fbe7733..03de7701a 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c +++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +FILE_LICENCE ( BSD2 ); + #include <ipxe/malloc.h> #include <ipxe/pci_io.h> #include <ipxe/pci.h> diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/calib.h b/roms/ipxe/src/drivers/net/ath/ath9k/calib.h index 5bf50f4a6..b811accf0 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/calib.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/calib.h @@ -20,6 +20,8 @@ #ifndef CALIB_H #define CALIB_H +FILE_LICENCE ( BSD2 ); + #include "hw.h" #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/common.h b/roms/ipxe/src/drivers/net/ath/ath9k/common.h index 009f8036d..0fe3b5be6 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/common.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/common.h @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +FILE_LICENCE ( BSD2 ); + #include "../ath.h" #include "hw.h" diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h b/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h index b451ebd70..8a48d6e5f 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h @@ -20,6 +20,8 @@ #ifndef EEPROM_H #define EEPROM_H +FILE_LICENCE ( BSD2 ); + #define AR_EEPROM_MODAL_SPURS 5 #include "../ath.h" diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h b/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h index 65cff3b08..51c7b08e4 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h @@ -17,6 +17,8 @@ #ifndef ATH9K_HW_OPS_H #define ATH9K_HW_OPS_H +FILE_LICENCE ( BSD2 ); + #include "hw.h" /* Hardware core and driver accessible callbacks */ diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/hw.h b/roms/ipxe/src/drivers/net/ath/ath9k/hw.h index c10df3883..051074691 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/hw.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/hw.h @@ -20,6 +20,8 @@ #ifndef HW_H #define HW_H +FILE_LICENCE ( BSD2 ); + #include <errno.h> #include "mac.h" diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/mac.h b/roms/ipxe/src/drivers/net/ath/ath9k/mac.h index 5899230e0..0c0a75948 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/mac.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/mac.h @@ -20,6 +20,8 @@ #ifndef MAC_H #define MAC_H +FILE_LICENCE ( BSD2 ); + #include <unistd.h> #define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ? \ diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/phy.h b/roms/ipxe/src/drivers/net/ath/ath9k/phy.h index 8b380305b..28f59ecd9 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/phy.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/phy.h @@ -17,6 +17,8 @@ #ifndef PHY_H #define PHY_H +FILE_LICENCE ( BSD2 ); + #define CHANSEL_DIV 15 #define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) #define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/reg.h b/roms/ipxe/src/drivers/net/ath/ath9k/reg.h index c18ee9921..67762b6d1 100644 --- a/roms/ipxe/src/drivers/net/ath/ath9k/reg.h +++ b/roms/ipxe/src/drivers/net/ath/ath9k/reg.h @@ -17,6 +17,8 @@ #ifndef REG_H #define REG_H +FILE_LICENCE ( BSD2 ); + #include "../reg.h" #define AR_CR 0x0008 diff --git a/roms/ipxe/src/drivers/net/ath/reg.h b/roms/ipxe/src/drivers/net/ath/reg.h index 484a8f1cb..7982f4344 100644 --- a/roms/ipxe/src/drivers/net/ath/reg.h +++ b/roms/ipxe/src/drivers/net/ath/reg.h @@ -20,6 +20,8 @@ #ifndef ATH_REGISTERS_H #define ATH_REGISTERS_H +FILE_LICENCE ( BSD2 ); + #define AR_MIBC 0x0040 #define AR_MIBC_COW 0x00000001 #define AR_MIBC_FMC 0x00000002 diff --git a/roms/ipxe/src/drivers/net/ath/regd.h b/roms/ipxe/src/drivers/net/ath/regd.h index 6954c5f36..fd09a0c8d 100644 --- a/roms/ipxe/src/drivers/net/ath/regd.h +++ b/roms/ipxe/src/drivers/net/ath/regd.h @@ -20,6 +20,8 @@ #ifndef REGD_H #define REGD_H +FILE_LICENCE ( BSD2 ); + #include "ath.h" enum ctl_group { diff --git a/roms/ipxe/src/drivers/net/bnx2.c b/roms/ipxe/src/drivers/net/bnx2.c index a986bdef7..4ebcc52a9 100644 --- a/roms/ipxe/src/drivers/net/bnx2.c +++ b/roms/ipxe/src/drivers/net/bnx2.c @@ -2617,9 +2617,6 @@ bnx2_probe(struct nic *nic, struct pci_device *pdev) struct bnx2 *bp = &bnx2; int i, rc; - if (pdev == 0) - return 0; - memset(bp, 0, sizeof(*bp)); rc = bnx2_init_board(pdev, nic); diff --git a/roms/ipxe/src/drivers/net/cs89x0.h b/roms/ipxe/src/drivers/net/cs89x0.h index 432fe94eb..aca790fdd 100644 --- a/roms/ipxe/src/drivers/net/cs89x0.h +++ b/roms/ipxe/src/drivers/net/cs89x0.h @@ -471,9 +471,6 @@ FILE_LICENCE ( GPL2_ONLY ); #define PNP_CNF_DMA 0x74 #define PNP_CNF_MEM 0x48 -#define BIT0 1 -#define BIT15 0x8000 - /* * Local variables: * c-basic-offset: 8 diff --git a/roms/ipxe/src/drivers/net/efi/snpnet.c b/roms/ipxe/src/drivers/net/efi/snpnet.c index 977908151..cd9e7e386 100644 --- a/roms/ipxe/src/drivers/net/efi/snpnet.c +++ b/roms/ipxe/src/drivers/net/efi/snpnet.c @@ -56,20 +56,21 @@ static int snpnet_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct snpnet_device *snpnetdev = netdev->priv; EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; - EFI_STATUS efirc; void *txbuf=NULL; size_t len = iob_len ( iobuf ); + EFI_STATUS efirc; + int rc; - efirc = snp->Transmit ( snp, 0, len, iobuf->data, NULL, NULL, NULL ); - if (efirc) { - return EFIRC_TO_RC ( efirc ); + if ( ( efirc = snp->Transmit ( snp, 0, len, iobuf->data, NULL, NULL, + NULL ) ) != 0 ) { + return -EEFI ( efirc ); } /* since GetStatus is so inconsistent, don't try more than one outstanding transmit at a time */ while ( txbuf == NULL ) { - efirc = snp->GetStatus ( snp, NULL, &txbuf ); - if ( efirc ) { + if ( ( efirc = snp->GetStatus ( snp, NULL, &txbuf ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not get status %s\n", snp, - efi_strerror ( efirc ) ); + strerror ( rc ) ); break; } @@ -86,9 +87,10 @@ static int snpnet_transmit ( struct net_device *netdev, static void snpnet_poll ( struct net_device *netdev ) { struct snpnet_device *snpnetdev = netdev->priv; EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; - EFI_STATUS efirc; struct io_buffer *iobuf = NULL; UINTN len; + EFI_STATUS efirc; + int rc; /* Process received packets */ while ( 1 ) { @@ -115,12 +117,13 @@ static void snpnet_poll ( struct net_device *netdev ) { } /* Other error? */ - if ( efirc ) { + if ( efirc != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p receive packet error: %s " "(len was %zd, is now %zd)\n", - snp, efi_strerror ( efirc ), iob_len(iobuf), + snp, strerror ( rc ), iob_len(iobuf), (size_t)len ); - netdev_rx_err ( netdev, iobuf, efirc ); + netdev_rx_err ( netdev, iobuf, rc ); break; } @@ -139,25 +142,27 @@ static void snpnet_poll ( struct net_device *netdev ) { static int snpnet_open ( struct net_device *netdev ) { struct snpnet_device *snpnetdev = netdev->priv; EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; - EFI_STATUS efirc; + EFI_MAC_ADDRESS *mac; UINT32 enableFlags, disableFlags; + EFI_STATUS efirc; + int rc; snpnetdev->close_state = snp->Mode->State; if ( snp->Mode->State != EfiSimpleNetworkInitialized ) { - efirc = snp->Initialize ( snp, 0, 0 ); - if ( efirc ) { + if ( ( efirc = snp->Initialize ( snp, 0, 0 ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not initialize: %s\n", - snp, efi_strerror ( efirc ) ); - return EFIRC_TO_RC ( efirc ); + snp, strerror ( rc ) ); + return rc; } } /* Use the default MAC address */ - efirc = snp->StationAddress ( snp, FALSE, - (EFI_MAC_ADDRESS *)netdev->ll_addr ); - if ( efirc ) { + mac = ( ( void * ) netdev->ll_addr ); + if ( ( efirc = snp->StationAddress ( snp, FALSE, mac ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not reset station address: %s\n", - snp, efi_strerror ( efirc ) ); + snp, strerror ( rc ) ); } /* Set up receive filters to receive unicast and broadcast packets @@ -179,11 +184,11 @@ static int snpnet_open ( struct net_device *netdev ) { enableFlags |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS; } disableFlags &= ~enableFlags; - efirc = snp->ReceiveFilters ( snp, enableFlags, disableFlags, - FALSE, 0, NULL ); - if ( efirc ) { + if ( ( efirc = snp->ReceiveFilters ( snp, enableFlags, disableFlags, + FALSE, 0, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not set receive filters: %s\n", - snp, efi_strerror ( efirc ) ); + snp, strerror ( rc ) ); } DBGC ( snp, "SNP %p opened\n", snp ); @@ -199,12 +204,13 @@ static void snpnet_close ( struct net_device *netdev ) { struct snpnet_device *snpnetdev = netdev->priv; EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp; EFI_STATUS efirc; + int rc; if ( snpnetdev->close_state != EfiSimpleNetworkInitialized ) { - efirc = snp->Shutdown ( snp ); - if ( efirc ) { + if ( ( efirc = snp->Shutdown ( snp ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not shut down: %s\n", - snp, efi_strerror ( efirc ) ); + snp, strerror ( rc ) ); } } } @@ -264,11 +270,10 @@ int snpnet_probe ( struct snp_device *snpdev ) { /* Start the interface */ if ( snp->Mode->State == EfiSimpleNetworkStopped ) { - efirc = snp->Start ( snp ); - if ( efirc ) { + if ( ( efirc = snp->Start ( snp ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not start: %s\n", snp, - efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + strerror ( rc ) ); goto err_start; } } @@ -310,25 +315,27 @@ err_start: */ void snpnet_remove ( struct snp_device *snpdev ) { EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpdev->snp; - EFI_STATUS efirc; struct net_device *netdev = snpdev->netdev; + EFI_STATUS efirc; + int rc; if ( snp->Mode->State == EfiSimpleNetworkInitialized && snpdev->removal_state != EfiSimpleNetworkInitialized ) { DBGC ( snp, "SNP %p shutting down\n", snp ); - efirc = snp->Shutdown ( snp ); - if ( efirc ) { + if ( ( efirc = snp->Shutdown ( snp ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snp, "SNP %p could not shut down: %s\n", - snp, efi_strerror ( efirc ) ); + snp, strerror ( rc ) ); } } if ( snp->Mode->State == EfiSimpleNetworkStarted && snpdev->removal_state == EfiSimpleNetworkStopped ) { DBGC ( snp, "SNP %p stopping\n", snp ); - efirc = snp->Stop ( snp ); - if ( efirc ) { - DBGC ( snp, "SNP %p could not be stopped\n", snp ); + if ( ( efirc = snp->Stop ( snp ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( snp, "SNP %p could not be stopped: %s\n", + snp, strerror ( rc ) ); } } diff --git a/roms/ipxe/src/drivers/net/etherfabric.c b/roms/ipxe/src/drivers/net/etherfabric.c index 6036d3216..5e0efb1e1 100644 --- a/roms/ipxe/src/drivers/net/etherfabric.c +++ b/roms/ipxe/src/drivers/net/etherfabric.c @@ -3798,7 +3798,8 @@ falcon_clear_interrupts ( struct efab_nic *efab ) } else { /* write to the INT_ACK register */ - falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 ); + EFAB_ZERO_DWORD ( reg ); + falcon_writel ( efab, ®, FCN_INT_ACK_KER_REG_A1 ); mb(); falcon_readl ( efab, ®, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 ); diff --git a/roms/ipxe/src/drivers/net/hfa384x.h b/roms/ipxe/src/drivers/net/hfa384x.h index 2e3ccf52c..d33704e63 100644 --- a/roms/ipxe/src/drivers/net/hfa384x.h +++ b/roms/ipxe/src/drivers/net/hfa384x.h @@ -39,7 +39,7 @@ * * -------------------------------------------------------------------- * -* Portions of the development of this software were funded by +* Portions of the development of this software were funded by * Intersil Corporation as part of PRISM(R) chipset product development. * * -------------------------------------------------------------------- @@ -65,18 +65,18 @@ FILE_LICENCE ( GPL2_ONLY ); /*------ Constants --------------------------------------------*/ /*--- Mins & Maxs -----------------------------------*/ -#define HFA384x_CMD_ALLOC_LEN_MIN ((UINT16)4) -#define HFA384x_CMD_ALLOC_LEN_MAX ((UINT16)2400) -#define HFA384x_BAP_DATALEN_MAX ((UINT16)4096) -#define HFA384x_BAP_OFFSET_MAX ((UINT16)4096) -#define HFA384x_PORTID_MAX ((UINT16)7) -#define HFA384x_NUMPORTS_MAX ((UINT16)(HFA384x_PORTID_MAX+1)) -#define HFA384x_PDR_LEN_MAX ((UINT16)512) /* in bytes, from EK */ -#define HFA384x_PDA_RECS_MAX ((UINT16)200) /* a guess */ -#define HFA384x_PDA_LEN_MAX ((UINT16)1024) /* in bytes, from EK */ -#define HFA384x_SCANRESULT_MAX ((UINT16)31) -#define HFA384x_HSCANRESULT_MAX ((UINT16)31) -#define HFA384x_CHINFORESULT_MAX ((UINT16)16) +#define HFA384x_CMD_ALLOC_LEN_MIN ((uint16_t)4) +#define HFA384x_CMD_ALLOC_LEN_MAX ((uint16_t)2400) +#define HFA384x_BAP_DATALEN_MAX ((uint16_t)4096) +#define HFA384x_BAP_OFFSET_MAX ((uint16_t)4096) +#define HFA384x_PORTID_MAX ((uint16_t)7) +#define HFA384x_NUMPORTS_MAX ((uint16_t)(HFA384x_PORTID_MAX+1)) +#define HFA384x_PDR_LEN_MAX ((uint16_t)512) /* in bytes, from EK */ +#define HFA384x_PDA_RECS_MAX ((uint16_t)200) /* a guess */ +#define HFA384x_PDA_LEN_MAX ((uint16_t)1024) /* in bytes, from EK */ +#define HFA384x_SCANRESULT_MAX ((uint16_t)31) +#define HFA384x_HSCANRESULT_MAX ((uint16_t)31) +#define HFA384x_CHINFORESULT_MAX ((uint16_t)16) #define HFA384x_DRVR_FIDSTACKLEN_MAX (10) #define HFA384x_DRVR_TXBUF_MAX (sizeof(hfa384x_tx_frame_t) + \ WLAN_DATA_MAXLEN - \ @@ -86,63 +86,63 @@ FILE_LICENCE ( GPL2_ONLY ); #define HFA384x_INFODATA_MAXLEN (sizeof(hfa384x_infodata_t)) #define HFA384x_INFOFRM_MAXLEN (sizeof(hfa384x_InfFrame_t)) #define HFA384x_RID_GUESSING_MAXLEN 2048 /* I'm not really sure */ -#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN +#define HFA384x_RIDDATA_MAXLEN HFA384x_RID_GUESSING_MAXLEN #define HFA384x_USB_RWMEM_MAXLEN 2048 /*--- Support Constants -----------------------------*/ -#define HFA384x_BAP_PROC ((UINT16)0) -#define HFA384x_BAP_INT ((UINT16)1) -#define HFA384x_PORTTYPE_IBSS ((UINT16)0) -#define HFA384x_PORTTYPE_BSS ((UINT16)1) -#define HFA384x_PORTTYPE_WDS ((UINT16)2) -#define HFA384x_PORTTYPE_PSUEDOIBSS ((UINT16)3) -#define HFA384x_PORTTYPE_HOSTAP ((UINT16)6) -#define HFA384x_WEPFLAGS_PRIVINVOKED ((UINT16)BIT0) -#define HFA384x_WEPFLAGS_EXCLUDE ((UINT16)BIT1) -#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT ((UINT16)BIT4) -#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT ((UINT16)BIT7) -#define HFA384x_WEPFLAGS_DISALLOW_MIXED ((UINT16)BIT11) -#define HFA384x_WEPFLAGS_IV_INTERVAL1 ((UINT16)0) -#define HFA384x_WEPFLAGS_IV_INTERVAL10 ((UINT16)BIT5) -#define HFA384x_WEPFLAGS_IV_INTERVAL50 ((UINT16)BIT6) -#define HFA384x_WEPFLAGS_IV_INTERVAL100 ((UINT16)(BIT5 | BIT6)) -#define HFA384x_WEPFLAGS_FIRMWARE_WPA ((UINT16)BIT8) -#define HFA384x_WEPFLAGS_HOST_MIC ((UINT16)BIT9) -#define HFA384x_ROAMMODE_FWSCAN_FWROAM ((UINT16)1) -#define HFA384x_ROAMMODE_FWSCAN_HOSTROAM ((UINT16)2) -#define HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM ((UINT16)3) -#define HFA384x_PORTSTATUS_DISABLED ((UINT16)1) -#define HFA384x_PORTSTATUS_INITSRCH ((UINT16)2) -#define HFA384x_PORTSTATUS_CONN_IBSS ((UINT16)3) -#define HFA384x_PORTSTATUS_CONN_ESS ((UINT16)4) -#define HFA384x_PORTSTATUS_OOR_ESS ((UINT16)5) -#define HFA384x_PORTSTATUS_CONN_WDS ((UINT16)6) -#define HFA384x_PORTSTATUS_HOSTAP ((UINT16)8) -#define HFA384x_RATEBIT_1 ((UINT16)1) -#define HFA384x_RATEBIT_2 ((UINT16)2) -#define HFA384x_RATEBIT_5dot5 ((UINT16)4) -#define HFA384x_RATEBIT_11 ((UINT16)8) +#define HFA384x_BAP_PROC ((uint16_t)0) +#define HFA384x_BAP_int ((uint16_t)1) +#define HFA384x_PORTTYPE_IBSS ((uint16_t)0) +#define HFA384x_PORTTYPE_BSS ((uint16_t)1) +#define HFA384x_PORTTYPE_WDS ((uint16_t)2) +#define HFA384x_PORTTYPE_PSUEDOIBSS ((uint16_t)3) +#define HFA384x_PORTTYPE_HOSTAP ((uint16_t)6) +#define HFA384x_WEPFLAGS_PRIVINVOKED ((uint16_t)BIT0) +#define HFA384x_WEPFLAGS_EXCLUDE ((uint16_t)BIT1) +#define HFA384x_WEPFLAGS_DISABLE_TXCRYPT ((uint16_t)BIT4) +#define HFA384x_WEPFLAGS_DISABLE_RXCRYPT ((uint16_t)BIT7) +#define HFA384x_WEPFLAGS_DISALLOW_MIXED ((uint16_t)BIT11) +#define HFA384x_WEPFLAGS_IV_INTERVAL1 ((uint16_t)0) +#define HFA384x_WEPFLAGS_IV_INTERVAL10 ((uint16_t)BIT5) +#define HFA384x_WEPFLAGS_IV_INTERVAL50 ((uint16_t)BIT6) +#define HFA384x_WEPFLAGS_IV_INTERVAL100 ((uint16_t)(BIT5 | BIT6)) +#define HFA384x_WEPFLAGS_FIRMWARE_WPA ((uint16_t)BIT8) +#define HFA384x_WEPFLAGS_HOST_MIC ((uint16_t)BIT9) +#define HFA384x_ROAMMODE_FWSCAN_FWROAM ((uint16_t)1) +#define HFA384x_ROAMMODE_FWSCAN_HOSTROAM ((uint16_t)2) +#define HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM ((uint16_t)3) +#define HFA384x_PORTSTATUS_DISABLED ((uint16_t)1) +#define HFA384x_PORTSTATUS_INITSRCH ((uint16_t)2) +#define HFA384x_PORTSTATUS_CONN_IBSS ((uint16_t)3) +#define HFA384x_PORTSTATUS_CONN_ESS ((uint16_t)4) +#define HFA384x_PORTSTATUS_OOR_ESS ((uint16_t)5) +#define HFA384x_PORTSTATUS_CONN_WDS ((uint16_t)6) +#define HFA384x_PORTSTATUS_HOSTAP ((uint16_t)8) +#define HFA384x_RATEBIT_1 ((uint16_t)1) +#define HFA384x_RATEBIT_2 ((uint16_t)2) +#define HFA384x_RATEBIT_5dot5 ((uint16_t)4) +#define HFA384x_RATEBIT_11 ((uint16_t)8) /*--- Just some symbolic names for legibility -------*/ -#define HFA384x_TXCMD_NORECL ((UINT16)0) -#define HFA384x_TXCMD_RECL ((UINT16)1) +#define HFA384x_TXCMD_NORECL ((uint16_t)0) +#define HFA384x_TXCMD_RECL ((uint16_t)1) /*--- MAC Internal memory constants and macros ------*/ /* masks and macros used to manipulate MAC internal memory addresses. */ -/* MAC internal memory addresses are 23 bit quantities. The MAC uses - * a paged address space where the upper 16 bits are the page number - * and the lower 7 bits are the offset. There are various Host API - * elements that require two 16-bit quantities to specify a MAC - * internal memory address. Unfortunately, some of the API's use a - * page/offset format where the offset value is JUST the lower seven - * bits and the page is the remaining 16 bits. Some of the API's - * assume that the 23 bit address has been split at the 16th bit. We - * refer to these two formats as AUX format and CMD format. The +/* MAC internal memory addresses are 23 bit quantities. The MAC uses + * a paged address space where the upper 16 bits are the page number + * and the lower 7 bits are the offset. There are various Host API + * elements that require two 16-bit quantities to specify a MAC + * internal memory address. Unfortunately, some of the API's use a + * page/offset format where the offset value is JUST the lower seven + * bits and the page is the remaining 16 bits. Some of the API's + * assume that the 23 bit address has been split at the 16th bit. We + * refer to these two formats as AUX format and CMD format. The * macros below help handle some of this. - */ + */ /* Handy constant */ -#define HFA384x_ADDR_AUX_OFF_MAX ((UINT16)0x007f) +#define HFA384x_ADDR_AUX_OFF_MAX ((uint16_t)0x007f) /* Mask bits for discarding unwanted pieces in a flat address */ #define HFA384x_ADDR_FLAT_AUX_PAGE_MASK (0x007fff80) @@ -160,25 +160,25 @@ FILE_LICENCE ( GPL2_ONLY ); /* Make a 32-bit flat address from AUX format 16-bit page and offset */ #define HFA384x_ADDR_AUX_MKFLAT(p,o) \ - (((UINT32)(((UINT16)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) <<7) | \ - ((UINT32)(((UINT16)(o))&HFA384x_ADDR_AUX_OFF_MASK)) + (((uint32_t)(((uint16_t)(p))&HFA384x_ADDR_AUX_PAGE_MASK)) <<7) | \ + ((uint32_t)(((uint16_t)(o))&HFA384x_ADDR_AUX_OFF_MASK)) /* Make a 32-bit flat address from CMD format 16-bit page and offset */ #define HFA384x_ADDR_CMD_MKFLAT(p,o) \ - (((UINT32)(((UINT16)(p))&HFA384x_ADDR_CMD_PAGE_MASK)) <<16) | \ - ((UINT32)(((UINT16)(o))&HFA384x_ADDR_CMD_OFF_MASK)) + (((uint32_t)(((uint16_t)(p))&HFA384x_ADDR_CMD_PAGE_MASK)) <<16) | \ + ((uint32_t)(((uint16_t)(o))&HFA384x_ADDR_CMD_OFF_MASK)) /* Make AUX format offset and page from a 32-bit flat address */ #define HFA384x_ADDR_AUX_MKPAGE(f) \ - ((UINT16)((((UINT32)(f))&HFA384x_ADDR_FLAT_AUX_PAGE_MASK)>>7)) + ((uint16_t)((((uint32_t)(f))&HFA384x_ADDR_FLAT_AUX_PAGE_MASK)>>7)) #define HFA384x_ADDR_AUX_MKOFF(f) \ - ((UINT16)(((UINT32)(f))&HFA384x_ADDR_FLAT_AUX_OFF_MASK)) + ((uint16_t)(((uint32_t)(f))&HFA384x_ADDR_FLAT_AUX_OFF_MASK)) /* Make CMD format offset and page from a 32-bit flat address */ #define HFA384x_ADDR_CMD_MKPAGE(f) \ - ((UINT16)((((UINT32)(f))&HFA384x_ADDR_FLAT_CMD_PAGE_MASK)>>16)) + ((uint16_t)((((uint32_t)(f))&HFA384x_ADDR_FLAT_CMD_PAGE_MASK)>>16)) #define HFA384x_ADDR_CMD_MKOFF(f) \ - ((UINT16)(((UINT32)(f))&HFA384x_ADDR_FLAT_CMD_OFF_MASK)) + ((uint16_t)(((uint32_t)(f))&HFA384x_ADDR_FLAT_CMD_OFF_MASK)) /*--- Aux register masks/tests ----------------------*/ /* Some of the upper bits of the AUX offset register are used to */ @@ -190,7 +190,7 @@ FILE_LICENCE ( GPL2_ONLY ); /* Make AUX register offset and page values from a flat address */ #define HFA384x_AUX_MKOFF(f, c) \ - (HFA384x_ADDR_AUX_MKOFF(f) | (((UINT16)(c))<<12)) + (HFA384x_ADDR_AUX_MKOFF(f) | (((uint16_t)(c))<<12)) #define HFA384x_AUX_MKPAGE(f) HFA384x_ADDR_AUX_MKPAGE(f) @@ -284,91 +284,91 @@ FILE_LICENCE ( GPL2_ONLY ); #endif /*--- Register Field Masks --------------------------*/ -#define HFA384x_CMD_BUSY ((UINT16)BIT15) -#define HFA384x_CMD_AINFO ((UINT16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) -#define HFA384x_CMD_MACPORT ((UINT16)(BIT10 | BIT9 | BIT8)) -#define HFA384x_CMD_RECL ((UINT16)BIT8) -#define HFA384x_CMD_WRITE ((UINT16)BIT8) -#define HFA384x_CMD_PROGMODE ((UINT16)(BIT9 | BIT8)) -#define HFA384x_CMD_CMDCODE ((UINT16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) - -#define HFA384x_STATUS_RESULT ((UINT16)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) -#define HFA384x_STATUS_CMDCODE ((UINT16)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) - -#define HFA384x_OFFSET_BUSY ((UINT16)BIT15) -#define HFA384x_OFFSET_ERR ((UINT16)BIT14) -#define HFA384x_OFFSET_DATAOFF ((UINT16)(BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1)) - -#define HFA384x_EVSTAT_TICK ((UINT16)BIT15) -#define HFA384x_EVSTAT_WTERR ((UINT16)BIT14) -#define HFA384x_EVSTAT_INFDROP ((UINT16)BIT13) -#define HFA384x_EVSTAT_INFO ((UINT16)BIT7) -#define HFA384x_EVSTAT_DTIM ((UINT16)BIT5) -#define HFA384x_EVSTAT_CMD ((UINT16)BIT4) -#define HFA384x_EVSTAT_ALLOC ((UINT16)BIT3) -#define HFA384x_EVSTAT_TXEXC ((UINT16)BIT2) -#define HFA384x_EVSTAT_TX ((UINT16)BIT1) -#define HFA384x_EVSTAT_RX ((UINT16)BIT0) +#define HFA384x_CMD_BUSY ((uint16_t)BIT15) +#define HFA384x_CMD_AINFO ((uint16_t)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) +#define HFA384x_CMD_MACPORT ((uint16_t)(BIT10 | BIT9 | BIT8)) +#define HFA384x_CMD_RECL ((uint16_t)BIT8) +#define HFA384x_CMD_WRITE ((uint16_t)BIT8) +#define HFA384x_CMD_PROGMODE ((uint16_t)(BIT9 | BIT8)) +#define HFA384x_CMD_CMDCODE ((uint16_t)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) + +#define HFA384x_STATUS_RESULT ((uint16_t)(BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)) +#define HFA384x_STATUS_CMDCODE ((uint16_t)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)) + +#define HFA384x_OFFSET_BUSY ((uint16_t)BIT15) +#define HFA384x_OFFSET_ERR ((uint16_t)BIT14) +#define HFA384x_OFFSET_DATAOFF ((uint16_t)(BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1)) + +#define HFA384x_EVSTAT_TICK ((uint16_t)BIT15) +#define HFA384x_EVSTAT_WTERR ((uint16_t)BIT14) +#define HFA384x_EVSTAT_INFDROP ((uint16_t)BIT13) +#define HFA384x_EVSTAT_INFO ((uint16_t)BIT7) +#define HFA384x_EVSTAT_DTIM ((uint16_t)BIT5) +#define HFA384x_EVSTAT_CMD ((uint16_t)BIT4) +#define HFA384x_EVSTAT_ALLOC ((uint16_t)BIT3) +#define HFA384x_EVSTAT_TXEXC ((uint16_t)BIT2) +#define HFA384x_EVSTAT_TX ((uint16_t)BIT1) +#define HFA384x_EVSTAT_RX ((uint16_t)BIT0) #define HFA384x_INT_BAP_OP (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC) #define HFA384x_INT_NORMAL (HFA384x_EVSTAT_INFO|HFA384x_EVSTAT_RX|HFA384x_EVSTAT_TX|HFA384x_EVSTAT_TXEXC|HFA384x_EVSTAT_INFDROP|HFA384x_EVSTAT_ALLOC|HFA384x_EVSTAT_DTIM) -#define HFA384x_INTEN_TICK ((UINT16)BIT15) -#define HFA384x_INTEN_WTERR ((UINT16)BIT14) -#define HFA384x_INTEN_INFDROP ((UINT16)BIT13) -#define HFA384x_INTEN_INFO ((UINT16)BIT7) -#define HFA384x_INTEN_DTIM ((UINT16)BIT5) -#define HFA384x_INTEN_CMD ((UINT16)BIT4) -#define HFA384x_INTEN_ALLOC ((UINT16)BIT3) -#define HFA384x_INTEN_TXEXC ((UINT16)BIT2) -#define HFA384x_INTEN_TX ((UINT16)BIT1) -#define HFA384x_INTEN_RX ((UINT16)BIT0) - -#define HFA384x_EVACK_TICK ((UINT16)BIT15) -#define HFA384x_EVACK_WTERR ((UINT16)BIT14) -#define HFA384x_EVACK_INFDROP ((UINT16)BIT13) -#define HFA384x_EVACK_INFO ((UINT16)BIT7) -#define HFA384x_EVACK_DTIM ((UINT16)BIT5) -#define HFA384x_EVACK_CMD ((UINT16)BIT4) -#define HFA384x_EVACK_ALLOC ((UINT16)BIT3) -#define HFA384x_EVACK_TXEXC ((UINT16)BIT2) -#define HFA384x_EVACK_TX ((UINT16)BIT1) -#define HFA384x_EVACK_RX ((UINT16)BIT0) - -#define HFA384x_CONTROL_AUXEN ((UINT16)(BIT15 | BIT14)) +#define HFA384x_INTEN_TICK ((uint16_t)BIT15) +#define HFA384x_INTEN_WTERR ((uint16_t)BIT14) +#define HFA384x_INTEN_INFDROP ((uint16_t)BIT13) +#define HFA384x_INTEN_INFO ((uint16_t)BIT7) +#define HFA384x_INTEN_DTIM ((uint16_t)BIT5) +#define HFA384x_INTEN_CMD ((uint16_t)BIT4) +#define HFA384x_INTEN_ALLOC ((uint16_t)BIT3) +#define HFA384x_INTEN_TXEXC ((uint16_t)BIT2) +#define HFA384x_INTEN_TX ((uint16_t)BIT1) +#define HFA384x_INTEN_RX ((uint16_t)BIT0) + +#define HFA384x_EVACK_TICK ((uint16_t)BIT15) +#define HFA384x_EVACK_WTERR ((uint16_t)BIT14) +#define HFA384x_EVACK_INFDROP ((uint16_t)BIT13) +#define HFA384x_EVACK_INFO ((uint16_t)BIT7) +#define HFA384x_EVACK_DTIM ((uint16_t)BIT5) +#define HFA384x_EVACK_CMD ((uint16_t)BIT4) +#define HFA384x_EVACK_ALLOC ((uint16_t)BIT3) +#define HFA384x_EVACK_TXEXC ((uint16_t)BIT2) +#define HFA384x_EVACK_TX ((uint16_t)BIT1) +#define HFA384x_EVACK_RX ((uint16_t)BIT0) + +#define HFA384x_CONTROL_AUXEN ((uint16_t)(BIT15 | BIT14)) /*--- Command Code Constants --------------------------*/ /*--- Controller Commands --------------------------*/ -#define HFA384x_CMDCODE_INIT ((UINT16)0x00) -#define HFA384x_CMDCODE_ENABLE ((UINT16)0x01) -#define HFA384x_CMDCODE_DISABLE ((UINT16)0x02) -#define HFA384x_CMDCODE_DIAG ((UINT16)0x03) +#define HFA384x_CMDCODE_INIT ((uint16_t)0x00) +#define HFA384x_CMDCODE_ENABLE ((uint16_t)0x01) +#define HFA384x_CMDCODE_DISABLE ((uint16_t)0x02) +#define HFA384x_CMDCODE_DIAG ((uint16_t)0x03) /*--- Buffer Mgmt Commands --------------------------*/ -#define HFA384x_CMDCODE_ALLOC ((UINT16)0x0A) -#define HFA384x_CMDCODE_TX ((UINT16)0x0B) -#define HFA384x_CMDCODE_CLRPRST ((UINT16)0x12) +#define HFA384x_CMDCODE_ALLOC ((uint16_t)0x0A) +#define HFA384x_CMDCODE_TX ((uint16_t)0x0B) +#define HFA384x_CMDCODE_CLRPRST ((uint16_t)0x12) /*--- Regulate Commands --------------------------*/ -#define HFA384x_CMDCODE_NOTIFY ((UINT16)0x10) -#define HFA384x_CMDCODE_INQ ((UINT16)0x11) +#define HFA384x_CMDCODE_NOTIFY ((uint16_t)0x10) +#define HFA384x_CMDCODE_INQ ((uint16_t)0x11) /*--- Configure Commands --------------------------*/ -#define HFA384x_CMDCODE_ACCESS ((UINT16)0x21) -#define HFA384x_CMDCODE_DOWNLD ((UINT16)0x22) +#define HFA384x_CMDCODE_ACCESS ((uint16_t)0x21) +#define HFA384x_CMDCODE_DOWNLD ((uint16_t)0x22) /*--- Debugging Commands -----------------------------*/ -#define HFA384x_CMDCODE_MONITOR ((UINT16)(0x38)) -#define HFA384x_MONITOR_ENABLE ((UINT16)(0x0b)) -#define HFA384x_MONITOR_DISABLE ((UINT16)(0x0f)) +#define HFA384x_CMDCODE_MONITOR ((uint16_t)(0x38)) +#define HFA384x_MONITOR_ENABLE ((uint16_t)(0x0b)) +#define HFA384x_MONITOR_DISABLE ((uint16_t)(0x0f)) /*--- Result Codes --------------------------*/ -#define HFA384x_SUCCESS ((UINT16)(0x00)) -#define HFA384x_CARD_FAIL ((UINT16)(0x01)) -#define HFA384x_NO_BUFF ((UINT16)(0x05)) -#define HFA384x_CMD_ERR ((UINT16)(0x7F)) +#define HFA384x_SUCCESS ((uint16_t)(0x00)) +#define HFA384x_CARD_FAIL ((uint16_t)(0x01)) +#define HFA384x_NO_BUFF ((uint16_t)(0x05)) +#define HFA384x_CMD_ERR ((uint16_t)(0x7F)) /*--- Programming Modes -------------------------- MODE 0: Disable programming @@ -376,408 +376,408 @@ FILE_LICENCE ( GPL2_ONLY ); MODE 2: Enable non-volatile memory programming MODE 3: Program non-volatile memory section --------------------------------------------------*/ -#define HFA384x_PROGMODE_DISABLE ((UINT16)0x00) -#define HFA384x_PROGMODE_RAM ((UINT16)0x01) -#define HFA384x_PROGMODE_NV ((UINT16)0x02) -#define HFA384x_PROGMODE_NVWRITE ((UINT16)0x03) +#define HFA384x_PROGMODE_DISABLE ((uint16_t)0x00) +#define HFA384x_PROGMODE_RAM ((uint16_t)0x01) +#define HFA384x_PROGMODE_NV ((uint16_t)0x02) +#define HFA384x_PROGMODE_NVWRITE ((uint16_t)0x03) /*--- AUX register enable --------------------------*/ -#define HFA384x_AUXPW0 ((UINT16)0xfe01) -#define HFA384x_AUXPW1 ((UINT16)0xdc23) -#define HFA384x_AUXPW2 ((UINT16)0xba45) +#define HFA384x_AUXPW0 ((uint16_t)0xfe01) +#define HFA384x_AUXPW1 ((uint16_t)0xdc23) +#define HFA384x_AUXPW2 ((uint16_t)0xba45) -#define HFA384x_CONTROL_AUX_ISDISABLED ((UINT16)0x0000) -#define HFA384x_CONTROL_AUX_ISENABLED ((UINT16)0xc000) -#define HFA384x_CONTROL_AUX_DOENABLE ((UINT16)0x8000) -#define HFA384x_CONTROL_AUX_DODISABLE ((UINT16)0x4000) +#define HFA384x_CONTROL_AUX_ISDISABLED ((uint16_t)0x0000) +#define HFA384x_CONTROL_AUX_ISENABLED ((uint16_t)0xc000) +#define HFA384x_CONTROL_AUX_DOENABLE ((uint16_t)0x8000) +#define HFA384x_CONTROL_AUX_DODISABLE ((uint16_t)0x4000) /*--- Record ID Constants --------------------------*/ /*-------------------------------------------------------------------- Configuration RIDs: Network Parameters, Static Configuration Entities --------------------------------------------------------------------*/ -#define HFA384x_RID_CNFPORTTYPE ((UINT16)0xFC00) -#define HFA384x_RID_CNFOWNMACADDR ((UINT16)0xFC01) -#define HFA384x_RID_CNFDESIREDSSID ((UINT16)0xFC02) -#define HFA384x_RID_CNFOWNCHANNEL ((UINT16)0xFC03) -#define HFA384x_RID_CNFOWNSSID ((UINT16)0xFC04) -#define HFA384x_RID_CNFOWNATIMWIN ((UINT16)0xFC05) -#define HFA384x_RID_CNFSYSSCALE ((UINT16)0xFC06) -#define HFA384x_RID_CNFMAXDATALEN ((UINT16)0xFC07) -#define HFA384x_RID_CNFWDSADDR ((UINT16)0xFC08) -#define HFA384x_RID_CNFPMENABLED ((UINT16)0xFC09) -#define HFA384x_RID_CNFPMEPS ((UINT16)0xFC0A) -#define HFA384x_RID_CNFMULTICASTRX ((UINT16)0xFC0B) -#define HFA384x_RID_CNFMAXSLEEPDUR ((UINT16)0xFC0C) -#define HFA384x_RID_CNFPMHOLDDUR ((UINT16)0xFC0D) -#define HFA384x_RID_CNFOWNNAME ((UINT16)0xFC0E) -#define HFA384x_RID_CNFOWNDTIMPER ((UINT16)0xFC10) -#define HFA384x_RID_CNFWDSADDR1 ((UINT16)0xFC11) -#define HFA384x_RID_CNFWDSADDR2 ((UINT16)0xFC12) -#define HFA384x_RID_CNFWDSADDR3 ((UINT16)0xFC13) -#define HFA384x_RID_CNFWDSADDR4 ((UINT16)0xFC14) -#define HFA384x_RID_CNFWDSADDR5 ((UINT16)0xFC15) -#define HFA384x_RID_CNFWDSADDR6 ((UINT16)0xFC16) -#define HFA384x_RID_CNFMCASTPMBUFF ((UINT16)0xFC17) +#define HFA384x_RID_CNFPORTTYPE ((uint16_t)0xFC00) +#define HFA384x_RID_CNFOWNMACADDR ((uint16_t)0xFC01) +#define HFA384x_RID_CNFDESIREDSSID ((uint16_t)0xFC02) +#define HFA384x_RID_CNFOWNCHANNEL ((uint16_t)0xFC03) +#define HFA384x_RID_CNFOWNSSID ((uint16_t)0xFC04) +#define HFA384x_RID_CNFOWNATIMWIN ((uint16_t)0xFC05) +#define HFA384x_RID_CNFSYSSCALE ((uint16_t)0xFC06) +#define HFA384x_RID_CNFMAXDATALEN ((uint16_t)0xFC07) +#define HFA384x_RID_CNFWDSADDR ((uint16_t)0xFC08) +#define HFA384x_RID_CNFPMENABLED ((uint16_t)0xFC09) +#define HFA384x_RID_CNFPMEPS ((uint16_t)0xFC0A) +#define HFA384x_RID_CNFMULTICASTRX ((uint16_t)0xFC0B) +#define HFA384x_RID_CNFMAXSLEEPDUR ((uint16_t)0xFC0C) +#define HFA384x_RID_CNFPMHOLDDUR ((uint16_t)0xFC0D) +#define HFA384x_RID_CNFOWNNAME ((uint16_t)0xFC0E) +#define HFA384x_RID_CNFOWNDTIMPER ((uint16_t)0xFC10) +#define HFA384x_RID_CNFWDSADDR1 ((uint16_t)0xFC11) +#define HFA384x_RID_CNFWDSADDR2 ((uint16_t)0xFC12) +#define HFA384x_RID_CNFWDSADDR3 ((uint16_t)0xFC13) +#define HFA384x_RID_CNFWDSADDR4 ((uint16_t)0xFC14) +#define HFA384x_RID_CNFWDSADDR5 ((uint16_t)0xFC15) +#define HFA384x_RID_CNFWDSADDR6 ((uint16_t)0xFC16) +#define HFA384x_RID_CNFMCASTPMBUFF ((uint16_t)0xFC17) /*-------------------------------------------------------------------- Configuration RID lengths: Network Params, Static Config Entities - This is the length of JUST the DATA part of the RID (does not + This is the length of JUST the DATA part of the RID (does not include the len or code fields) --------------------------------------------------------------------*/ /* TODO: fill in the rest of these */ -#define HFA384x_RID_CNFPORTTYPE_LEN ((UINT16)2) -#define HFA384x_RID_CNFOWNMACADDR_LEN ((UINT16)6) -#define HFA384x_RID_CNFDESIREDSSID_LEN ((UINT16)34) -#define HFA384x_RID_CNFOWNCHANNEL_LEN ((UINT16)2) -#define HFA384x_RID_CNFOWNSSID_LEN ((UINT16)34) -#define HFA384x_RID_CNFOWNATIMWIN_LEN ((UINT16)2) -#define HFA384x_RID_CNFSYSSCALE_LEN ((UINT16)0) -#define HFA384x_RID_CNFMAXDATALEN_LEN ((UINT16)0) -#define HFA384x_RID_CNFWDSADDR_LEN ((UINT16)6) -#define HFA384x_RID_CNFPMENABLED_LEN ((UINT16)0) -#define HFA384x_RID_CNFPMEPS_LEN ((UINT16)0) -#define HFA384x_RID_CNFMULTICASTRX_LEN ((UINT16)0) -#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((UINT16)0) -#define HFA384x_RID_CNFPMHOLDDUR_LEN ((UINT16)0) -#define HFA384x_RID_CNFOWNNAME_LEN ((UINT16)34) -#define HFA384x_RID_CNFOWNDTIMPER_LEN ((UINT16)0) -#define HFA384x_RID_CNFWDSADDR1_LEN ((UINT16)6) -#define HFA384x_RID_CNFWDSADDR2_LEN ((UINT16)6) -#define HFA384x_RID_CNFWDSADDR3_LEN ((UINT16)6) -#define HFA384x_RID_CNFWDSADDR4_LEN ((UINT16)6) -#define HFA384x_RID_CNFWDSADDR5_LEN ((UINT16)6) -#define HFA384x_RID_CNFWDSADDR6_LEN ((UINT16)6) -#define HFA384x_RID_CNFMCASTPMBUFF_LEN ((UINT16)0) -#define HFA384x_RID_CNFAUTHENTICATION_LEN ((UINT16)sizeof(UINT16)) -#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((UINT16)0) +#define HFA384x_RID_CNFPORTTYPE_LEN ((uint16_t)2) +#define HFA384x_RID_CNFOWNMACADDR_LEN ((uint16_t)6) +#define HFA384x_RID_CNFDESIREDSSID_LEN ((uint16_t)34) +#define HFA384x_RID_CNFOWNCHANNEL_LEN ((uint16_t)2) +#define HFA384x_RID_CNFOWNSSID_LEN ((uint16_t)34) +#define HFA384x_RID_CNFOWNATIMWIN_LEN ((uint16_t)2) +#define HFA384x_RID_CNFSYSSCALE_LEN ((uint16_t)0) +#define HFA384x_RID_CNFMAXDATALEN_LEN ((uint16_t)0) +#define HFA384x_RID_CNFWDSADDR_LEN ((uint16_t)6) +#define HFA384x_RID_CNFPMENABLED_LEN ((uint16_t)0) +#define HFA384x_RID_CNFPMEPS_LEN ((uint16_t)0) +#define HFA384x_RID_CNFMULTICASTRX_LEN ((uint16_t)0) +#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((uint16_t)0) +#define HFA384x_RID_CNFPMHOLDDUR_LEN ((uint16_t)0) +#define HFA384x_RID_CNFOWNNAME_LEN ((uint16_t)34) +#define HFA384x_RID_CNFOWNDTIMPER_LEN ((uint16_t)0) +#define HFA384x_RID_CNFWDSADDR1_LEN ((uint16_t)6) +#define HFA384x_RID_CNFWDSADDR2_LEN ((uint16_t)6) +#define HFA384x_RID_CNFWDSADDR3_LEN ((uint16_t)6) +#define HFA384x_RID_CNFWDSADDR4_LEN ((uint16_t)6) +#define HFA384x_RID_CNFWDSADDR5_LEN ((uint16_t)6) +#define HFA384x_RID_CNFWDSADDR6_LEN ((uint16_t)6) +#define HFA384x_RID_CNFMCASTPMBUFF_LEN ((uint16_t)0) +#define HFA384x_RID_CNFAUTHENTICATION_LEN ((uint16_t)sizeof(uint16_t)) +#define HFA384x_RID_CNFMAXSLEEPDUR_LEN ((uint16_t)0) /*-------------------------------------------------------------------- Configuration RIDs: Network Parameters, Dynamic Configuration Entities --------------------------------------------------------------------*/ -#define HFA384x_RID_GROUPADDR ((UINT16)0xFC80) -#define HFA384x_RID_CREATEIBSS ((UINT16)0xFC81) -#define HFA384x_RID_FRAGTHRESH ((UINT16)0xFC82) -#define HFA384x_RID_RTSTHRESH ((UINT16)0xFC83) -#define HFA384x_RID_TXRATECNTL ((UINT16)0xFC84) -#define HFA384x_RID_PROMISCMODE ((UINT16)0xFC85) -#define HFA384x_RID_FRAGTHRESH0 ((UINT16)0xFC90) -#define HFA384x_RID_FRAGTHRESH1 ((UINT16)0xFC91) -#define HFA384x_RID_FRAGTHRESH2 ((UINT16)0xFC92) -#define HFA384x_RID_FRAGTHRESH3 ((UINT16)0xFC93) -#define HFA384x_RID_FRAGTHRESH4 ((UINT16)0xFC94) -#define HFA384x_RID_FRAGTHRESH5 ((UINT16)0xFC95) -#define HFA384x_RID_FRAGTHRESH6 ((UINT16)0xFC96) -#define HFA384x_RID_RTSTHRESH0 ((UINT16)0xFC97) -#define HFA384x_RID_RTSTHRESH1 ((UINT16)0xFC98) -#define HFA384x_RID_RTSTHRESH2 ((UINT16)0xFC99) -#define HFA384x_RID_RTSTHRESH3 ((UINT16)0xFC9A) -#define HFA384x_RID_RTSTHRESH4 ((UINT16)0xFC9B) -#define HFA384x_RID_RTSTHRESH5 ((UINT16)0xFC9C) -#define HFA384x_RID_RTSTHRESH6 ((UINT16)0xFC9D) -#define HFA384x_RID_TXRATECNTL0 ((UINT16)0xFC9E) -#define HFA384x_RID_TXRATECNTL1 ((UINT16)0xFC9F) -#define HFA384x_RID_TXRATECNTL2 ((UINT16)0xFCA0) -#define HFA384x_RID_TXRATECNTL3 ((UINT16)0xFCA1) -#define HFA384x_RID_TXRATECNTL4 ((UINT16)0xFCA2) -#define HFA384x_RID_TXRATECNTL5 ((UINT16)0xFCA3) -#define HFA384x_RID_TXRATECNTL6 ((UINT16)0xFCA4) +#define HFA384x_RID_GROUPADDR ((uint16_t)0xFC80) +#define HFA384x_RID_CREATEIBSS ((uint16_t)0xFC81) +#define HFA384x_RID_FRAGTHRESH ((uint16_t)0xFC82) +#define HFA384x_RID_RTSTHRESH ((uint16_t)0xFC83) +#define HFA384x_RID_TXRATECNTL ((uint16_t)0xFC84) +#define HFA384x_RID_PROMISCMODE ((uint16_t)0xFC85) +#define HFA384x_RID_FRAGTHRESH0 ((uint16_t)0xFC90) +#define HFA384x_RID_FRAGTHRESH1 ((uint16_t)0xFC91) +#define HFA384x_RID_FRAGTHRESH2 ((uint16_t)0xFC92) +#define HFA384x_RID_FRAGTHRESH3 ((uint16_t)0xFC93) +#define HFA384x_RID_FRAGTHRESH4 ((uint16_t)0xFC94) +#define HFA384x_RID_FRAGTHRESH5 ((uint16_t)0xFC95) +#define HFA384x_RID_FRAGTHRESH6 ((uint16_t)0xFC96) +#define HFA384x_RID_RTSTHRESH0 ((uint16_t)0xFC97) +#define HFA384x_RID_RTSTHRESH1 ((uint16_t)0xFC98) +#define HFA384x_RID_RTSTHRESH2 ((uint16_t)0xFC99) +#define HFA384x_RID_RTSTHRESH3 ((uint16_t)0xFC9A) +#define HFA384x_RID_RTSTHRESH4 ((uint16_t)0xFC9B) +#define HFA384x_RID_RTSTHRESH5 ((uint16_t)0xFC9C) +#define HFA384x_RID_RTSTHRESH6 ((uint16_t)0xFC9D) +#define HFA384x_RID_TXRATECNTL0 ((uint16_t)0xFC9E) +#define HFA384x_RID_TXRATECNTL1 ((uint16_t)0xFC9F) +#define HFA384x_RID_TXRATECNTL2 ((uint16_t)0xFCA0) +#define HFA384x_RID_TXRATECNTL3 ((uint16_t)0xFCA1) +#define HFA384x_RID_TXRATECNTL4 ((uint16_t)0xFCA2) +#define HFA384x_RID_TXRATECNTL5 ((uint16_t)0xFCA3) +#define HFA384x_RID_TXRATECNTL6 ((uint16_t)0xFCA4) /*-------------------------------------------------------------------- Configuration RID Lengths: Network Param, Dynamic Config Entities - This is the length of JUST the DATA part of the RID (does not + This is the length of JUST the DATA part of the RID (does not include the len or code fields) --------------------------------------------------------------------*/ /* TODO: fill in the rest of these */ -#define HFA384x_RID_GROUPADDR_LEN ((UINT16)16 * WLAN_ADDR_LEN) -#define HFA384x_RID_CREATEIBSS_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL_LEN ((UINT16)4) -#define HFA384x_RID_PROMISCMODE_LEN ((UINT16)2) -#define HFA384x_RID_FRAGTHRESH0_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH1_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH2_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH3_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH4_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH5_LEN ((UINT16)0) -#define HFA384x_RID_FRAGTHRESH6_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH0_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH1_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH2_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH3_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH4_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH5_LEN ((UINT16)0) -#define HFA384x_RID_RTSTHRESH6_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL0_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL1_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL2_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL3_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL4_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL5_LEN ((UINT16)0) -#define HFA384x_RID_TXRATECNTL6_LEN ((UINT16)0) +#define HFA384x_RID_GROUPADDR_LEN ((uint16_t)16 * WLAN_ADDR_LEN) +#define HFA384x_RID_CREATEIBSS_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL_LEN ((uint16_t)4) +#define HFA384x_RID_PROMISCMODE_LEN ((uint16_t)2) +#define HFA384x_RID_FRAGTHRESH0_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH1_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH2_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH3_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH4_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH5_LEN ((uint16_t)0) +#define HFA384x_RID_FRAGTHRESH6_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH0_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH1_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH2_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH3_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH4_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH5_LEN ((uint16_t)0) +#define HFA384x_RID_RTSTHRESH6_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL0_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL1_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL2_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL3_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL4_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL5_LEN ((uint16_t)0) +#define HFA384x_RID_TXRATECNTL6_LEN ((uint16_t)0) /*-------------------------------------------------------------------- Configuration RIDs: Behavior Parameters --------------------------------------------------------------------*/ -#define HFA384x_RID_ITICKTIME ((UINT16)0xFCE0) +#define HFA384x_RID_ITICKTIME ((uint16_t)0xFCE0) /*-------------------------------------------------------------------- Configuration RID Lengths: Behavior Parameters - This is the length of JUST the DATA part of the RID (does not + This is the length of JUST the DATA part of the RID (does not include the len or code fields) --------------------------------------------------------------------*/ -#define HFA384x_RID_ITICKTIME_LEN ((UINT16)2) +#define HFA384x_RID_ITICKTIME_LEN ((uint16_t)2) /*---------------------------------------------------------------------- Information RIDs: NIC Information --------------------------------------------------------------------*/ -#define HFA384x_RID_MAXLOADTIME ((UINT16)0xFD00) -#define HFA384x_RID_DOWNLOADBUFFER ((UINT16)0xFD01) -#define HFA384x_RID_PRIIDENTITY ((UINT16)0xFD02) -#define HFA384x_RID_PRISUPRANGE ((UINT16)0xFD03) -#define HFA384x_RID_PRI_CFIACTRANGES ((UINT16)0xFD04) -#define HFA384x_RID_NICSERIALNUMBER ((UINT16)0xFD0A) -#define HFA384x_RID_NICIDENTITY ((UINT16)0xFD0B) -#define HFA384x_RID_MFISUPRANGE ((UINT16)0xFD0C) -#define HFA384x_RID_CFISUPRANGE ((UINT16)0xFD0D) -#define HFA384x_RID_CHANNELLIST ((UINT16)0xFD10) -#define HFA384x_RID_REGULATORYDOMAINS ((UINT16)0xFD11) -#define HFA384x_RID_TEMPTYPE ((UINT16)0xFD12) -#define HFA384x_RID_CIS ((UINT16)0xFD13) -#define HFA384x_RID_STAIDENTITY ((UINT16)0xFD20) -#define HFA384x_RID_STASUPRANGE ((UINT16)0xFD21) -#define HFA384x_RID_STA_MFIACTRANGES ((UINT16)0xFD22) -#define HFA384x_RID_STA_CFIACTRANGES ((UINT16)0xFD23) -#define HFA384x_RID_BUILDSEQ ((UINT16)0xFFFE) -#define HFA384x_RID_FWID ((UINT16)0xFFFF) +#define HFA384x_RID_MAXLOADTIME ((uint16_t)0xFD00) +#define HFA384x_RID_DOWNLOADBUFFER ((uint16_t)0xFD01) +#define HFA384x_RID_PRIIDENTITY ((uint16_t)0xFD02) +#define HFA384x_RID_PRISUPRANGE ((uint16_t)0xFD03) +#define HFA384x_RID_PRI_CFIACTRANGES ((uint16_t)0xFD04) +#define HFA384x_RID_NICSERIALNUMBER ((uint16_t)0xFD0A) +#define HFA384x_RID_NICIDENTITY ((uint16_t)0xFD0B) +#define HFA384x_RID_MFISUPRANGE ((uint16_t)0xFD0C) +#define HFA384x_RID_CFISUPRANGE ((uint16_t)0xFD0D) +#define HFA384x_RID_CHANNELLIST ((uint16_t)0xFD10) +#define HFA384x_RID_REGULATORYDOMAINS ((uint16_t)0xFD11) +#define HFA384x_RID_TEMPTYPE ((uint16_t)0xFD12) +#define HFA384x_RID_CIS ((uint16_t)0xFD13) +#define HFA384x_RID_STAIDENTITY ((uint16_t)0xFD20) +#define HFA384x_RID_STASUPRANGE ((uint16_t)0xFD21) +#define HFA384x_RID_STA_MFIACTRANGES ((uint16_t)0xFD22) +#define HFA384x_RID_STA_CFIACTRANGES ((uint16_t)0xFD23) +#define HFA384x_RID_BUILDSEQ ((uint16_t)0xFFFE) +#define HFA384x_RID_FWID ((uint16_t)0xFFFF) /*---------------------------------------------------------------------- Information RID Lengths: NIC Information - This is the length of JUST the DATA part of the RID (does not + This is the length of JUST the DATA part of the RID (does not include the len or code fields) --------------------------------------------------------------------*/ -#define HFA384x_RID_MAXLOADTIME_LEN ((UINT16)0) -#define HFA384x_RID_DOWNLOADBUFFER_LEN ((UINT16)sizeof(hfa384x_downloadbuffer_t)) -#define HFA384x_RID_PRIIDENTITY_LEN ((UINT16)8) -#define HFA384x_RID_PRISUPRANGE_LEN ((UINT16)10) -#define HFA384x_RID_CFIACTRANGES_LEN ((UINT16)10) -#define HFA384x_RID_NICSERIALNUMBER_LEN ((UINT16)12) -#define HFA384x_RID_NICIDENTITY_LEN ((UINT16)8) -#define HFA384x_RID_MFISUPRANGE_LEN ((UINT16)10) -#define HFA384x_RID_CFISUPRANGE_LEN ((UINT16)10) -#define HFA384x_RID_CHANNELLIST_LEN ((UINT16)0) -#define HFA384x_RID_REGULATORYDOMAINS_LEN ((UINT16)12) -#define HFA384x_RID_TEMPTYPE_LEN ((UINT16)0) -#define HFA384x_RID_CIS_LEN ((UINT16)480) -#define HFA384x_RID_STAIDENTITY_LEN ((UINT16)8) -#define HFA384x_RID_STASUPRANGE_LEN ((UINT16)10) -#define HFA384x_RID_MFIACTRANGES_LEN ((UINT16)10) -#define HFA384x_RID_CFIACTRANGES2_LEN ((UINT16)10) -#define HFA384x_RID_BUILDSEQ_LEN ((UINT16)sizeof(hfa384x_BuildSeq_t)) -#define HFA384x_RID_FWID_LEN ((UINT16)sizeof(hfa384x_FWID_t)) +#define HFA384x_RID_MAXLOADTIME_LEN ((uint16_t)0) +#define HFA384x_RID_DOWNLOADBUFFER_LEN ((uint16_t)sizeof(hfa384x_downloadbuffer_t)) +#define HFA384x_RID_PRIIDENTITY_LEN ((uint16_t)8) +#define HFA384x_RID_PRISUPRANGE_LEN ((uint16_t)10) +#define HFA384x_RID_CFIACTRANGES_LEN ((uint16_t)10) +#define HFA384x_RID_NICSERIALNUMBER_LEN ((uint16_t)12) +#define HFA384x_RID_NICIDENTITY_LEN ((uint16_t)8) +#define HFA384x_RID_MFISUPRANGE_LEN ((uint16_t)10) +#define HFA384x_RID_CFISUPRANGE_LEN ((uint16_t)10) +#define HFA384x_RID_CHANNELLIST_LEN ((uint16_t)0) +#define HFA384x_RID_REGULATORYDOMAINS_LEN ((uint16_t)12) +#define HFA384x_RID_TEMPTYPE_LEN ((uint16_t)0) +#define HFA384x_RID_CIS_LEN ((uint16_t)480) +#define HFA384x_RID_STAIDENTITY_LEN ((uint16_t)8) +#define HFA384x_RID_STASUPRANGE_LEN ((uint16_t)10) +#define HFA384x_RID_MFIACTRANGES_LEN ((uint16_t)10) +#define HFA384x_RID_CFIACTRANGES2_LEN ((uint16_t)10) +#define HFA384x_RID_BUILDSEQ_LEN ((uint16_t)sizeof(hfa384x_BuildSeq_t)) +#define HFA384x_RID_FWID_LEN ((uint16_t)sizeof(hfa384x_FWID_t)) /*-------------------------------------------------------------------- Information RIDs: MAC Information --------------------------------------------------------------------*/ -#define HFA384x_RID_PORTSTATUS ((UINT16)0xFD40) -#define HFA384x_RID_CURRENTSSID ((UINT16)0xFD41) -#define HFA384x_RID_CURRENTBSSID ((UINT16)0xFD42) -#define HFA384x_RID_COMMSQUALITY ((UINT16)0xFD43) -#define HFA384x_RID_CURRENTTXRATE ((UINT16)0xFD44) -#define HFA384x_RID_CURRENTBCNINT ((UINT16)0xFD45) -#define HFA384x_RID_CURRENTSCALETHRESH ((UINT16)0xFD46) -#define HFA384x_RID_PROTOCOLRSPTIME ((UINT16)0xFD47) -#define HFA384x_RID_SHORTRETRYLIMIT ((UINT16)0xFD48) -#define HFA384x_RID_LONGRETRYLIMIT ((UINT16)0xFD49) -#define HFA384x_RID_MAXTXLIFETIME ((UINT16)0xFD4A) -#define HFA384x_RID_MAXRXLIFETIME ((UINT16)0xFD4B) -#define HFA384x_RID_CFPOLLABLE ((UINT16)0xFD4C) -#define HFA384x_RID_AUTHALGORITHMS ((UINT16)0xFD4D) -#define HFA384x_RID_PRIVACYOPTIMP ((UINT16)0xFD4F) -#define HFA384x_RID_DBMCOMMSQUALITY ((UINT16)0xFD51) -#define HFA384x_RID_CURRENTTXRATE1 ((UINT16)0xFD80) -#define HFA384x_RID_CURRENTTXRATE2 ((UINT16)0xFD81) -#define HFA384x_RID_CURRENTTXRATE3 ((UINT16)0xFD82) -#define HFA384x_RID_CURRENTTXRATE4 ((UINT16)0xFD83) -#define HFA384x_RID_CURRENTTXRATE5 ((UINT16)0xFD84) -#define HFA384x_RID_CURRENTTXRATE6 ((UINT16)0xFD85) -#define HFA384x_RID_OWNMACADDRESS ((UINT16)0xFD86) -// #define HFA384x_RID_PCFINFO ((UINT16)0xFD87) -#define HFA384x_RID_SCANRESULTS ((UINT16)0xFD88) // NEW -#define HFA384x_RID_HOSTSCANRESULTS ((UINT16)0xFD89) // NEW -#define HFA384x_RID_AUTHENTICATIONUSED ((UINT16)0xFD8A) // NEW -#define HFA384x_RID_ASSOCIATEFAILURE ((UINT16)0xFD8D) // 1.8.0 +#define HFA384x_RID_PORTSTATUS ((uint16_t)0xFD40) +#define HFA384x_RID_CURRENTSSID ((uint16_t)0xFD41) +#define HFA384x_RID_CURRENTBSSID ((uint16_t)0xFD42) +#define HFA384x_RID_COMMSQUALITY ((uint16_t)0xFD43) +#define HFA384x_RID_CURRENTTXRATE ((uint16_t)0xFD44) +#define HFA384x_RID_CURRENTBCNint ((uint16_t)0xFD45) +#define HFA384x_RID_CURRENTSCALETHRESH ((uint16_t)0xFD46) +#define HFA384x_RID_PROTOCOLRSPTIME ((uint16_t)0xFD47) +#define HFA384x_RID_SHORTRETRYLIMIT ((uint16_t)0xFD48) +#define HFA384x_RID_LONGRETRYLIMIT ((uint16_t)0xFD49) +#define HFA384x_RID_MAXTXLIFETIME ((uint16_t)0xFD4A) +#define HFA384x_RID_MAXRXLIFETIME ((uint16_t)0xFD4B) +#define HFA384x_RID_CFPOLLABLE ((uint16_t)0xFD4C) +#define HFA384x_RID_AUTHALGORITHMS ((uint16_t)0xFD4D) +#define HFA384x_RID_PRIVACYOPTIMP ((uint16_t)0xFD4F) +#define HFA384x_RID_DBMCOMMSQUALITY ((uint16_t)0xFD51) +#define HFA384x_RID_CURRENTTXRATE1 ((uint16_t)0xFD80) +#define HFA384x_RID_CURRENTTXRATE2 ((uint16_t)0xFD81) +#define HFA384x_RID_CURRENTTXRATE3 ((uint16_t)0xFD82) +#define HFA384x_RID_CURRENTTXRATE4 ((uint16_t)0xFD83) +#define HFA384x_RID_CURRENTTXRATE5 ((uint16_t)0xFD84) +#define HFA384x_RID_CURRENTTXRATE6 ((uint16_t)0xFD85) +#define HFA384x_RID_OWNMACADDRESS ((uint16_t)0xFD86) +// #define HFA384x_RID_PCFINFO ((uint16_t)0xFD87) +#define HFA384x_RID_SCANRESULTS ((uint16_t)0xFD88) // NEW +#define HFA384x_RID_HOSTSCANRESULTS ((uint16_t)0xFD89) // NEW +#define HFA384x_RID_AUTHENTICATIONUSED ((uint16_t)0xFD8A) // NEW +#define HFA384x_RID_ASSOCIATEFAILURE ((uint16_t)0xFD8D) // 1.8.0 /*-------------------------------------------------------------------- Information RID Lengths: MAC Information - This is the length of JUST the DATA part of the RID (does not + This is the length of JUST the DATA part of the RID (does not include the len or code fields) --------------------------------------------------------------------*/ -#define HFA384x_RID_PORTSTATUS_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTSSID_LEN ((UINT16)34) -#define HFA384x_RID_CURRENTBSSID_LEN ((UINT16)WLAN_BSSID_LEN) -#define HFA384x_RID_COMMSQUALITY_LEN ((UINT16)sizeof(hfa384x_commsquality_t)) -#define HFA384x_RID_DBMCOMMSQUALITY_LEN ((UINT16)sizeof(hfa384x_dbmcommsquality_t)) -#define HFA384x_RID_CURRENTTXRATE_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTBCNINT_LEN ((UINT16)0) -#define HFA384x_RID_STACURSCALETHRESH_LEN ((UINT16)12) -#define HFA384x_RID_APCURSCALETHRESH_LEN ((UINT16)6) -#define HFA384x_RID_PROTOCOLRSPTIME_LEN ((UINT16)0) -#define HFA384x_RID_SHORTRETRYLIMIT_LEN ((UINT16)0) -#define HFA384x_RID_LONGRETRYLIMIT_LEN ((UINT16)0) -#define HFA384x_RID_MAXTXLIFETIME_LEN ((UINT16)0) -#define HFA384x_RID_MAXRXLIFETIME_LEN ((UINT16)0) -#define HFA384x_RID_CFPOLLABLE_LEN ((UINT16)0) -#define HFA384x_RID_AUTHALGORITHMS_LEN ((UINT16)4) -#define HFA384x_RID_PRIVACYOPTIMP_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTTXRATE1_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTTXRATE2_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTTXRATE3_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTTXRATE4_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTTXRATE5_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTTXRATE6_LEN ((UINT16)0) -#define HFA384x_RID_OWNMACADDRESS_LEN ((UINT16)6) -#define HFA384x_RID_PCFINFO_LEN ((UINT16)6) -#define HFA384x_RID_CNFAPPCFINFO_LEN ((UINT16)sizeof(hfa384x_PCFInfo_data_t)) -#define HFA384x_RID_SCANREQUEST_LEN ((UINT16)sizeof(hfa384x_ScanRequest_data_t)) -#define HFA384x_RID_JOINREQUEST_LEN ((UINT16)sizeof(hfa384x_JoinRequest_data_t)) -#define HFA384x_RID_AUTHENTICATESTA_LEN ((UINT16)sizeof(hfa384x_authenticateStation_data_t)) -#define HFA384x_RID_CHANNELINFOREQUEST_LEN ((UINT16)sizeof(hfa384x_ChannelInfoRequest_data_t)) +#define HFA384x_RID_PORTSTATUS_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTSSID_LEN ((uint16_t)34) +#define HFA384x_RID_CURRENTBSSID_LEN ((uint16_t)WLAN_BSSID_LEN) +#define HFA384x_RID_COMMSQUALITY_LEN ((uint16_t)sizeof(hfa384x_commsquality_t)) +#define HFA384x_RID_DBMCOMMSQUALITY_LEN ((uint16_t)sizeof(hfa384x_dbmcommsquality_t)) +#define HFA384x_RID_CURRENTTXRATE_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTBCNINT_LEN ((uint16_t)0) +#define HFA384x_RID_STACURSCALETHRESH_LEN ((uint16_t)12) +#define HFA384x_RID_APCURSCALETHRESH_LEN ((uint16_t)6) +#define HFA384x_RID_PROTOCOLRSPTIME_LEN ((uint16_t)0) +#define HFA384x_RID_SHORTRETRYLIMIT_LEN ((uint16_t)0) +#define HFA384x_RID_LONGRETRYLIMIT_LEN ((uint16_t)0) +#define HFA384x_RID_MAXTXLIFETIME_LEN ((uint16_t)0) +#define HFA384x_RID_MAXRXLIFETIME_LEN ((uint16_t)0) +#define HFA384x_RID_CFPOLLABLE_LEN ((uint16_t)0) +#define HFA384x_RID_AUTHALGORITHMS_LEN ((uint16_t)4) +#define HFA384x_RID_PRIVACYOPTIMP_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTTXRATE1_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTTXRATE2_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTTXRATE3_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTTXRATE4_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTTXRATE5_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTTXRATE6_LEN ((uint16_t)0) +#define HFA384x_RID_OWNMACADDRESS_LEN ((uint16_t)6) +#define HFA384x_RID_PCFINFO_LEN ((uint16_t)6) +#define HFA384x_RID_CNFAPPCFINFO_LEN ((uint16_t)sizeof(hfa384x_PCFInfo_data_t)) +#define HFA384x_RID_SCANREQUEST_LEN ((uint16_t)sizeof(hfa384x_ScanRequest_data_t)) +#define HFA384x_RID_JOINREQUEST_LEN ((uint16_t)sizeof(hfa384x_JoinRequest_data_t)) +#define HFA384x_RID_AUTHENTICATESTA_LEN ((uint16_t)sizeof(hfa384x_authenticateStation_data_t)) +#define HFA384x_RID_CHANNELINFOREQUEST_LEN ((uint16_t)sizeof(hfa384x_ChannelInfoRequest_data_t)) /*-------------------------------------------------------------------- Information RIDs: Modem Information --------------------------------------------------------------------*/ -#define HFA384x_RID_PHYTYPE ((UINT16)0xFDC0) -#define HFA384x_RID_CURRENTCHANNEL ((UINT16)0xFDC1) -#define HFA384x_RID_CURRENTPOWERSTATE ((UINT16)0xFDC2) -#define HFA384x_RID_CCAMODE ((UINT16)0xFDC3) -#define HFA384x_RID_SUPPORTEDDATARATES ((UINT16)0xFDC6) -#define HFA384x_RID_LFOSTATUS ((UINT16)0xFDC7) // 1.7.1 +#define HFA384x_RID_PHYTYPE ((uint16_t)0xFDC0) +#define HFA384x_RID_CURRENTCHANNEL ((uint16_t)0xFDC1) +#define HFA384x_RID_CURRENTPOWERSTATE ((uint16_t)0xFDC2) +#define HFA384x_RID_CCAMODE ((uint16_t)0xFDC3) +#define HFA384x_RID_SUPPORTEDDATARATES ((uint16_t)0xFDC6) +#define HFA384x_RID_LFOSTATUS ((uint16_t)0xFDC7) // 1.7.1 /*-------------------------------------------------------------------- -Information RID Lengths: Modem Information - This is the length of JUST the DATA part of the RID (does not +Information RID Lengths: Modem Information + This is the length of JUST the DATA part of the RID (does not include the len or code fields) --------------------------------------------------------------------*/ -#define HFA384x_RID_PHYTYPE_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTCHANNEL_LEN ((UINT16)0) -#define HFA384x_RID_CURRENTPOWERSTATE_LEN ((UINT16)0) -#define HFA384x_RID_CCAMODE_LEN ((UINT16)0) -#define HFA384x_RID_SUPPORTEDDATARATES_LEN ((UINT16)10) +#define HFA384x_RID_PHYTYPE_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTCHANNEL_LEN ((uint16_t)0) +#define HFA384x_RID_CURRENTPOWERSTATE_LEN ((uint16_t)0) +#define HFA384x_RID_CCAMODE_LEN ((uint16_t)0) +#define HFA384x_RID_SUPPORTEDDATARATES_LEN ((uint16_t)10) /*-------------------------------------------------------------------- API ENHANCEMENTS (NOT ALREADY IMPLEMENTED) --------------------------------------------------------------------*/ -#define HFA384x_RID_CNFWEPDEFAULTKEYID ((UINT16)0xFC23) -#define HFA384x_RID_CNFWEPDEFAULTKEY0 ((UINT16)0xFC24) -#define HFA384x_RID_CNFWEPDEFAULTKEY1 ((UINT16)0xFC25) -#define HFA384x_RID_CNFWEPDEFAULTKEY2 ((UINT16)0xFC26) -#define HFA384x_RID_CNFWEPDEFAULTKEY3 ((UINT16)0xFC27) -#define HFA384x_RID_CNFWEPFLAGS ((UINT16)0xFC28) -#define HFA384x_RID_CNFWEPKEYMAPTABLE ((UINT16)0xFC29) -#define HFA384x_RID_CNFAUTHENTICATION ((UINT16)0xFC2A) -#define HFA384x_RID_CNFMAXASSOCSTATIONS ((UINT16)0xFC2B) -#define HFA384x_RID_CNFTXCONTROL ((UINT16)0xFC2C) -#define HFA384x_RID_CNFROAMINGMODE ((UINT16)0xFC2D) -#define HFA384x_RID_CNFHOSTAUTHASSOC ((UINT16)0xFC2E) -#define HFA384x_RID_CNFRCVCRCERROR ((UINT16)0xFC30) -// #define HFA384x_RID_CNFMMLIFE ((UINT16)0xFC31) -#define HFA384x_RID_CNFALTRETRYCNT ((UINT16)0xFC32) -#define HFA384x_RID_CNFAPBCNINT ((UINT16)0xFC33) -#define HFA384x_RID_CNFAPPCFINFO ((UINT16)0xFC34) -#define HFA384x_RID_CNFSTAPCFINFO ((UINT16)0xFC35) -#define HFA384x_RID_CNFPRIORITYQUSAGE ((UINT16)0xFC37) -#define HFA384x_RID_CNFTIMCTRL ((UINT16)0xFC40) -#define HFA384x_RID_CNFTHIRTY2TALLY ((UINT16)0xFC42) -#define HFA384x_RID_CNFENHSECURITY ((UINT16)0xFC43) -#define HFA384x_RID_CNFDBMADJUST ((UINT16)0xFC46) // NEW -#define HFA384x_RID_CNFWPADATA ((UINT16)0xFC48) // 1.7.0 -#define HFA384x_RID_CNFPROPOGATIONDELAY ((UINT16)0xFC49) // 1.7.6 -#define HFA384x_RID_CNFSHORTPREAMBLE ((UINT16)0xFCB0) -#define HFA384x_RID_CNFEXCLONGPREAMBLE ((UINT16)0xFCB1) -#define HFA384x_RID_CNFAUTHRSPTIMEOUT ((UINT16)0xFCB2) -#define HFA384x_RID_CNFBASICRATES ((UINT16)0xFCB3) -#define HFA384x_RID_CNFSUPPRATES ((UINT16)0xFCB4) -#define HFA384x_RID_CNFFALLBACKCTRL ((UINT16)0xFCB5) // NEW -#define HFA384x_RID_WEPKEYSTATUS ((UINT16)0xFCB6) // NEW -#define HFA384x_RID_WEPKEYMAPINDEX ((UINT16)0xFCB7) // NEW -#define HFA384x_RID_BROADCASTKEYID ((UINT16)0xFCB8) // NEW -#define HFA384x_RID_ENTSECFLAGEYID ((UINT16)0xFCB9) // NEW -#define HFA384x_RID_CNFPASSIVESCANCTRL ((UINT16)0xFCBA) // NEW STA -#define HFA384x_RID_CNFWPAHANDLING ((UINT16)0xFCBB) // 1.7.0 -#define HFA384x_RID_MDCCONTROL ((UINT16)0xFCBC) // 1.7.0/1.4.0 -#define HFA384x_RID_MDCCOUNTRY ((UINT16)0xFCBD) // 1.7.0/1.4.0 -#define HFA384x_RID_TXPOWERMAX ((UINT16)0xFCBE) // 1.7.0/1.4.0 -#define HFA384x_RID_CNFLFOENBLED ((UINT16)0xFCBF) // 1.6.3 -#define HFA384x_RID_CAPINFO ((UINT16)0xFCC0) // 1.7.0/1.3.7 -#define HFA384x_RID_LISTENINTERVAL ((UINT16)0xFCC1) // 1.7.0/1.3.7 -#define HFA384x_RID_DIVERSITYENABLED ((UINT16)0xFCC2) // 1.7.0/1.3.7 -#define HFA384x_RID_LED_CONTROL ((UINT16)0xFCC4) // 1.7.6 -#define HFA384x_RID_HFO_DELAY ((UINT16)0xFCC5) // 1.7.6 -#define HFA384x_RID_DISSALOWEDBSSID ((UINT16)0xFCC6) // 1.8.0 -#define HFA384x_RID_SCANREQUEST ((UINT16)0xFCE1) -#define HFA384x_RID_JOINREQUEST ((UINT16)0xFCE2) -#define HFA384x_RID_AUTHENTICATESTA ((UINT16)0xFCE3) -#define HFA384x_RID_CHANNELINFOREQUEST ((UINT16)0xFCE4) -#define HFA384x_RID_HOSTSCAN ((UINT16)0xFCE5) // NEW STA -#define HFA384x_RID_ASSOCIATESTA ((UINT16)0xFCE6) - -#define HFA384x_RID_CNFWEPDEFAULTKEY_LEN ((UINT16)6) -#define HFA384x_RID_CNFWEP128DEFAULTKEY_LEN ((UINT16)14) -#define HFA384x_RID_CNFPRIOQUSAGE_LEN ((UINT16)4) +#define HFA384x_RID_CNFWEPDEFAULTKEYID ((uint16_t)0xFC23) +#define HFA384x_RID_CNFWEPDEFAULTKEY0 ((uint16_t)0xFC24) +#define HFA384x_RID_CNFWEPDEFAULTKEY1 ((uint16_t)0xFC25) +#define HFA384x_RID_CNFWEPDEFAULTKEY2 ((uint16_t)0xFC26) +#define HFA384x_RID_CNFWEPDEFAULTKEY3 ((uint16_t)0xFC27) +#define HFA384x_RID_CNFWEPFLAGS ((uint16_t)0xFC28) +#define HFA384x_RID_CNFWEPKEYMAPTABLE ((uint16_t)0xFC29) +#define HFA384x_RID_CNFAUTHENTICATION ((uint16_t)0xFC2A) +#define HFA384x_RID_CNFMAXASSOCSTATIONS ((uint16_t)0xFC2B) +#define HFA384x_RID_CNFTXCONTROL ((uint16_t)0xFC2C) +#define HFA384x_RID_CNFROAMINGMODE ((uint16_t)0xFC2D) +#define HFA384x_RID_CNFHOSTAUTHASSOC ((uint16_t)0xFC2E) +#define HFA384x_RID_CNFRCVCRCERROR ((uint16_t)0xFC30) +// #define HFA384x_RID_CNFMMLIFE ((uint16_t)0xFC31) +#define HFA384x_RID_CNFALTRETRYCNT ((uint16_t)0xFC32) +#define HFA384x_RID_CNFAPBCNint ((uint16_t)0xFC33) +#define HFA384x_RID_CNFAPPCFINFO ((uint16_t)0xFC34) +#define HFA384x_RID_CNFSTAPCFINFO ((uint16_t)0xFC35) +#define HFA384x_RID_CNFPRIORITYQUSAGE ((uint16_t)0xFC37) +#define HFA384x_RID_CNFTIMCTRL ((uint16_t)0xFC40) +#define HFA384x_RID_CNFTHIRTY2TALLY ((uint16_t)0xFC42) +#define HFA384x_RID_CNFENHSECURITY ((uint16_t)0xFC43) +#define HFA384x_RID_CNFDBMADJUST ((uint16_t)0xFC46) // NEW +#define HFA384x_RID_CNFWPADATA ((uint16_t)0xFC48) // 1.7.0 +#define HFA384x_RID_CNFPROPOGATIONDELAY ((uint16_t)0xFC49) // 1.7.6 +#define HFA384x_RID_CNFSHORTPREAMBLE ((uint16_t)0xFCB0) +#define HFA384x_RID_CNFEXCLONGPREAMBLE ((uint16_t)0xFCB1) +#define HFA384x_RID_CNFAUTHRSPTIMEOUT ((uint16_t)0xFCB2) +#define HFA384x_RID_CNFBASICRATES ((uint16_t)0xFCB3) +#define HFA384x_RID_CNFSUPPRATES ((uint16_t)0xFCB4) +#define HFA384x_RID_CNFFALLBACKCTRL ((uint16_t)0xFCB5) // NEW +#define HFA384x_RID_WEPKEYSTATUS ((uint16_t)0xFCB6) // NEW +#define HFA384x_RID_WEPKEYMAPINDEX ((uint16_t)0xFCB7) // NEW +#define HFA384x_RID_BROADCASTKEYID ((uint16_t)0xFCB8) // NEW +#define HFA384x_RID_ENTSECFLAGEYID ((uint16_t)0xFCB9) // NEW +#define HFA384x_RID_CNFPASSIVESCANCTRL ((uint16_t)0xFCBA) // NEW STA +#define HFA384x_RID_CNFWPAHANDLING ((uint16_t)0xFCBB) // 1.7.0 +#define HFA384x_RID_MDCCONTROL ((uint16_t)0xFCBC) // 1.7.0/1.4.0 +#define HFA384x_RID_MDCCOUNTRY ((uint16_t)0xFCBD) // 1.7.0/1.4.0 +#define HFA384x_RID_TXPOWERMAX ((uint16_t)0xFCBE) // 1.7.0/1.4.0 +#define HFA384x_RID_CNFLFOENBLED ((uint16_t)0xFCBF) // 1.6.3 +#define HFA384x_RID_CAPINFO ((uint16_t)0xFCC0) // 1.7.0/1.3.7 +#define HFA384x_RID_LISTENINTERVAL ((uint16_t)0xFCC1) // 1.7.0/1.3.7 +#define HFA384x_RID_DIVERSITYENABLED ((uint16_t)0xFCC2) // 1.7.0/1.3.7 +#define HFA384x_RID_LED_CONTROL ((uint16_t)0xFCC4) // 1.7.6 +#define HFA384x_RID_HFO_DELAY ((uint16_t)0xFCC5) // 1.7.6 +#define HFA384x_RID_DISSALOWEDBSSID ((uint16_t)0xFCC6) // 1.8.0 +#define HFA384x_RID_SCANREQUEST ((uint16_t)0xFCE1) +#define HFA384x_RID_JOINREQUEST ((uint16_t)0xFCE2) +#define HFA384x_RID_AUTHENTICATESTA ((uint16_t)0xFCE3) +#define HFA384x_RID_CHANNELINFOREQUEST ((uint16_t)0xFCE4) +#define HFA384x_RID_HOSTSCAN ((uint16_t)0xFCE5) // NEW STA +#define HFA384x_RID_ASSOCIATESTA ((uint16_t)0xFCE6) + +#define HFA384x_RID_CNFWEPDEFAULTKEY_LEN ((uint16_t)6) +#define HFA384x_RID_CNFWEP128DEFAULTKEY_LEN ((uint16_t)14) +#define HFA384x_RID_CNFPRIOQUSAGE_LEN ((uint16_t)4) /*-------------------------------------------------------------------- PD Record codes --------------------------------------------------------------------*/ -#define HFA384x_PDR_PCB_PARTNUM ((UINT16)0x0001) -#define HFA384x_PDR_PDAVER ((UINT16)0x0002) -#define HFA384x_PDR_NIC_SERIAL ((UINT16)0x0003) -#define HFA384x_PDR_MKK_MEASUREMENTS ((UINT16)0x0004) -#define HFA384x_PDR_NIC_RAMSIZE ((UINT16)0x0005) -#define HFA384x_PDR_MFISUPRANGE ((UINT16)0x0006) -#define HFA384x_PDR_CFISUPRANGE ((UINT16)0x0007) -#define HFA384x_PDR_NICID ((UINT16)0x0008) -//#define HFA384x_PDR_REFDAC_MEASUREMENTS ((UINT16)0x0010) -//#define HFA384x_PDR_VGDAC_MEASUREMENTS ((UINT16)0x0020) -//#define HFA384x_PDR_LEVEL_COMP_MEASUREMENTS ((UINT16)0x0030) -//#define HFA384x_PDR_MODEM_TRIMDAC_MEASUREMENTS ((UINT16)0x0040) -//#define HFA384x_PDR_COREGA_HACK ((UINT16)0x00ff) -#define HFA384x_PDR_MAC_ADDRESS ((UINT16)0x0101) -//#define HFA384x_PDR_MKK_CALLNAME ((UINT16)0x0102) -#define HFA384x_PDR_REGDOMAIN ((UINT16)0x0103) -#define HFA384x_PDR_ALLOWED_CHANNEL ((UINT16)0x0104) -#define HFA384x_PDR_DEFAULT_CHANNEL ((UINT16)0x0105) -//#define HFA384x_PDR_PRIVACY_OPTION ((UINT16)0x0106) -#define HFA384x_PDR_TEMPTYPE ((UINT16)0x0107) -//#define HFA384x_PDR_REFDAC_SETUP ((UINT16)0x0110) -//#define HFA384x_PDR_VGDAC_SETUP ((UINT16)0x0120) -//#define HFA384x_PDR_LEVEL_COMP_SETUP ((UINT16)0x0130) -//#define HFA384x_PDR_TRIMDAC_SETUP ((UINT16)0x0140) -#define HFA384x_PDR_IFR_SETTING ((UINT16)0x0200) -#define HFA384x_PDR_RFR_SETTING ((UINT16)0x0201) -#define HFA384x_PDR_HFA3861_BASELINE ((UINT16)0x0202) -#define HFA384x_PDR_HFA3861_SHADOW ((UINT16)0x0203) -#define HFA384x_PDR_HFA3861_IFRF ((UINT16)0x0204) -#define HFA384x_PDR_HFA3861_CHCALSP ((UINT16)0x0300) -#define HFA384x_PDR_HFA3861_CHCALI ((UINT16)0x0301) -#define HFA384x_PDR_MAX_TX_POWER ((UINT16)0x0302) -#define HFA384x_PDR_MASTER_CHAN_LIST ((UINT16)0x0303) -#define HFA384x_PDR_3842_NIC_CONFIG ((UINT16)0x0400) -#define HFA384x_PDR_USB_ID ((UINT16)0x0401) -#define HFA384x_PDR_PCI_ID ((UINT16)0x0402) -#define HFA384x_PDR_PCI_IFCONF ((UINT16)0x0403) -#define HFA384x_PDR_PCI_PMCONF ((UINT16)0x0404) -#define HFA384x_PDR_RFENRGY ((UINT16)0x0406) -#define HFA384x_PDR_USB_POWER_TYPE ((UINT16)0x0407) -//#define HFA384x_PDR_UNKNOWN408 ((UINT16)0x0408) -#define HFA384x_PDR_USB_MAX_POWER ((UINT16)0x0409) -#define HFA384x_PDR_USB_MANUFACTURER ((UINT16)0x0410) -#define HFA384x_PDR_USB_PRODUCT ((UINT16)0x0411) -#define HFA384x_PDR_ANT_DIVERSITY ((UINT16)0x0412) -#define HFA384x_PDR_HFO_DELAY ((UINT16)0x0413) -#define HFA384x_PDR_SCALE_THRESH ((UINT16)0x0414) - -#define HFA384x_PDR_HFA3861_MANF_TESTSP ((UINT16)0x0900) -#define HFA384x_PDR_HFA3861_MANF_TESTI ((UINT16)0x0901) -#define HFA384x_PDR_END_OF_PDA ((UINT16)0x0000) +#define HFA384x_PDR_PCB_PARTNUM ((uint16_t)0x0001) +#define HFA384x_PDR_PDAVER ((uint16_t)0x0002) +#define HFA384x_PDR_NIC_SERIAL ((uint16_t)0x0003) +#define HFA384x_PDR_MKK_MEASUREMENTS ((uint16_t)0x0004) +#define HFA384x_PDR_NIC_RAMSIZE ((uint16_t)0x0005) +#define HFA384x_PDR_MFISUPRANGE ((uint16_t)0x0006) +#define HFA384x_PDR_CFISUPRANGE ((uint16_t)0x0007) +#define HFA384x_PDR_NICID ((uint16_t)0x0008) +//#define HFA384x_PDR_REFDAC_MEASUREMENTS ((uint16_t)0x0010) +//#define HFA384x_PDR_VGDAC_MEASUREMENTS ((uint16_t)0x0020) +//#define HFA384x_PDR_LEVEL_COMP_MEASUREMENTS ((uint16_t)0x0030) +//#define HFA384x_PDR_MODEM_TRIMDAC_MEASUREMENTS ((uint16_t)0x0040) +//#define HFA384x_PDR_COREGA_HACK ((uint16_t)0x00ff) +#define HFA384x_PDR_MAC_ADDRESS ((uint16_t)0x0101) +//#define HFA384x_PDR_MKK_CALLNAME ((uint16_t)0x0102) +#define HFA384x_PDR_REGDOMAIN ((uint16_t)0x0103) +#define HFA384x_PDR_ALLOWED_CHANNEL ((uint16_t)0x0104) +#define HFA384x_PDR_DEFAULT_CHANNEL ((uint16_t)0x0105) +//#define HFA384x_PDR_PRIVACY_OPTION ((uint16_t)0x0106) +#define HFA384x_PDR_TEMPTYPE ((uint16_t)0x0107) +//#define HFA384x_PDR_REFDAC_SETUP ((uint16_t)0x0110) +//#define HFA384x_PDR_VGDAC_SETUP ((uint16_t)0x0120) +//#define HFA384x_PDR_LEVEL_COMP_SETUP ((uint16_t)0x0130) +//#define HFA384x_PDR_TRIMDAC_SETUP ((uint16_t)0x0140) +#define HFA384x_PDR_IFR_SETTING ((uint16_t)0x0200) +#define HFA384x_PDR_RFR_SETTING ((uint16_t)0x0201) +#define HFA384x_PDR_HFA3861_BASELINE ((uint16_t)0x0202) +#define HFA384x_PDR_HFA3861_SHADOW ((uint16_t)0x0203) +#define HFA384x_PDR_HFA3861_IFRF ((uint16_t)0x0204) +#define HFA384x_PDR_HFA3861_CHCALSP ((uint16_t)0x0300) +#define HFA384x_PDR_HFA3861_CHCALI ((uint16_t)0x0301) +#define HFA384x_PDR_MAX_TX_POWER ((uint16_t)0x0302) +#define HFA384x_PDR_MASTER_CHAN_LIST ((uint16_t)0x0303) +#define HFA384x_PDR_3842_NIC_CONFIG ((uint16_t)0x0400) +#define HFA384x_PDR_USB_ID ((uint16_t)0x0401) +#define HFA384x_PDR_PCI_ID ((uint16_t)0x0402) +#define HFA384x_PDR_PCI_IFCONF ((uint16_t)0x0403) +#define HFA384x_PDR_PCI_PMCONF ((uint16_t)0x0404) +#define HFA384x_PDR_RFENRGY ((uint16_t)0x0406) +#define HFA384x_PDR_USB_POWER_TYPE ((uint16_t)0x0407) +//#define HFA384x_PDR_UNKNOWN408 ((uint16_t)0x0408) +#define HFA384x_PDR_USB_MAX_POWER ((uint16_t)0x0409) +#define HFA384x_PDR_USB_MANUFACTURER ((uint16_t)0x0410) +#define HFA384x_PDR_USB_PRODUCT ((uint16_t)0x0411) +#define HFA384x_PDR_ANT_DIVERSITY ((uint16_t)0x0412) +#define HFA384x_PDR_HFO_DELAY ((uint16_t)0x0413) +#define HFA384x_PDR_SCALE_THRESH ((uint16_t)0x0414) + +#define HFA384x_PDR_HFA3861_MANF_TESTSP ((uint16_t)0x0900) +#define HFA384x_PDR_HFA3861_MANF_TESTI ((uint16_t)0x0901) +#define HFA384x_PDR_END_OF_PDA ((uint16_t)0x0000) /*=============================================================*/ @@ -819,96 +819,96 @@ PD Record codes /*--- Register Test/Get/Set Field macros ------------------------*/ -#define HFA384x_CMD_ISBUSY(value) ((UINT16)(((UINT16)value) & HFA384x_CMD_BUSY)) -#define HFA384x_CMD_AINFO_GET(value) ((UINT16)(((UINT16)(value) & HFA384x_CMD_AINFO) >> 8)) -#define HFA384x_CMD_AINFO_SET(value) ((UINT16)((UINT16)(value) << 8)) -#define HFA384x_CMD_MACPORT_GET(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_MACPORT))) -#define HFA384x_CMD_MACPORT_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET(value)) -#define HFA384x_CMD_ISRECL(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_RECL))) -#define HFA384x_CMD_RECL_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET(value)) -#define HFA384x_CMD_QOS_GET(value) ((UINT16((((UINT16)(value))&((UINT16)0x3000)) >> 12)) -#define HFA384x_CMD_QOS_SET(value) ((UINT16)((((UINT16)(value)) << 12) & 0x3000)) -#define HFA384x_CMD_ISWRITE(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_WRITE))) -#define HFA384x_CMD_WRITE_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value)) -#define HFA384x_CMD_PROGMODE_GET(value) ((UINT16)(HFA384x_CMD_AINFO_GET((UINT16)(value) & HFA384x_CMD_PROGMODE))) -#define HFA384x_CMD_PROGMODE_SET(value) ((UINT16)HFA384x_CMD_AINFO_SET((UINT16)value)) -#define HFA384x_CMD_CMDCODE_GET(value) ((UINT16)(((UINT16)(value)) & HFA384x_CMD_CMDCODE)) -#define HFA384x_CMD_CMDCODE_SET(value) ((UINT16)(value)) - -#define HFA384x_STATUS_RESULT_GET(value) ((UINT16)((((UINT16)(value)) & HFA384x_STATUS_RESULT) >> 8)) -#define HFA384x_STATUS_RESULT_SET(value) (((UINT16)(value)) << 8) -#define HFA384x_STATUS_CMDCODE_GET(value) (((UINT16)(value)) & HFA384x_STATUS_CMDCODE) -#define HFA384x_STATUS_CMDCODE_SET(value) ((UINT16)(value)) - -#define HFA384x_OFFSET_ISBUSY(value) ((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_BUSY)) -#define HFA384x_OFFSET_ISERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_ERR)) -#define HFA384x_OFFSET_DATAOFF_GET(value) ((UINT16)(((UINT16)(value)) & HFA384x_OFFSET_DATAOFF)) -#define HFA384x_OFFSET_DATAOFF_SET(value) ((UINT16)(value)) - -#define HFA384x_EVSTAT_ISTICK(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TICK)) -#define HFA384x_EVSTAT_ISWTERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_WTERR)) -#define HFA384x_EVSTAT_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_INFDROP)) -#define HFA384x_EVSTAT_ISINFO(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_INFO)) -#define HFA384x_EVSTAT_ISDTIM(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_DTIM)) -#define HFA384x_EVSTAT_ISCMD(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_CMD)) -#define HFA384x_EVSTAT_ISALLOC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_ALLOC)) -#define HFA384x_EVSTAT_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TXEXC)) -#define HFA384x_EVSTAT_ISTX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_TX)) -#define HFA384x_EVSTAT_ISRX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVSTAT_RX)) - -#define HFA384x_EVSTAT_ISBAP_OP(value) ((UINT16)(((UINT16)(value)) & HFA384x_INT_BAP_OP)) - -#define HFA384x_INTEN_ISTICK(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TICK)) -#define HFA384x_INTEN_TICK_SET(value) ((UINT16)(((UINT16)(value)) << 15)) -#define HFA384x_INTEN_ISWTERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_WTERR)) -#define HFA384x_INTEN_WTERR_SET(value) ((UINT16)(((UINT16)(value)) << 14)) -#define HFA384x_INTEN_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_INFDROP)) -#define HFA384x_INTEN_INFDROP_SET(value) ((UINT16)(((UINT16)(value)) << 13)) -#define HFA384x_INTEN_ISINFO(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_INFO)) -#define HFA384x_INTEN_INFO_SET(value) ((UINT16)(((UINT16)(value)) << 7)) -#define HFA384x_INTEN_ISDTIM(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_DTIM)) -#define HFA384x_INTEN_DTIM_SET(value) ((UINT16)(((UINT16)(value)) << 5)) -#define HFA384x_INTEN_ISCMD(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_CMD)) -#define HFA384x_INTEN_CMD_SET(value) ((UINT16)(((UINT16)(value)) << 4)) -#define HFA384x_INTEN_ISALLOC(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_ALLOC)) -#define HFA384x_INTEN_ALLOC_SET(value) ((UINT16)(((UINT16)(value)) << 3)) -#define HFA384x_INTEN_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TXEXC)) -#define HFA384x_INTEN_TXEXC_SET(value) ((UINT16)(((UINT16)(value)) << 2)) -#define HFA384x_INTEN_ISTX(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_TX)) -#define HFA384x_INTEN_TX_SET(value) ((UINT16)(((UINT16)(value)) << 1)) -#define HFA384x_INTEN_ISRX(value) ((UINT16)(((UINT16)(value)) & HFA384x_INTEN_RX)) -#define HFA384x_INTEN_RX_SET(value) ((UINT16)(((UINT16)(value)) << 0)) - -#define HFA384x_EVACK_ISTICK(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TICK)) -#define HFA384x_EVACK_TICK_SET(value) ((UINT16)(((UINT16)(value)) << 15)) -#define HFA384x_EVACK_ISWTERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_WTERR)) -#define HFA384x_EVACK_WTERR_SET(value) ((UINT16)(((UINT16)(value)) << 14)) -#define HFA384x_EVACK_ISINFDROP(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_INFDROP)) -#define HFA384x_EVACK_INFDROP_SET(value) ((UINT16)(((UINT16)(value)) << 13)) -#define HFA384x_EVACK_ISINFO(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_INFO)) -#define HFA384x_EVACK_INFO_SET(value) ((UINT16)(((UINT16)(value)) << 7)) -#define HFA384x_EVACK_ISDTIM(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_DTIM)) -#define HFA384x_EVACK_DTIM_SET(value) ((UINT16)(((UINT16)(value)) << 5)) -#define HFA384x_EVACK_ISCMD(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_CMD)) -#define HFA384x_EVACK_CMD_SET(value) ((UINT16)(((UINT16)(value)) << 4)) -#define HFA384x_EVACK_ISALLOC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_ALLOC)) -#define HFA384x_EVACK_ALLOC_SET(value) ((UINT16)(((UINT16)(value)) << 3)) -#define HFA384x_EVACK_ISTXEXC(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TXEXC)) -#define HFA384x_EVACK_TXEXC_SET(value) ((UINT16)(((UINT16)(value)) << 2)) -#define HFA384x_EVACK_ISTX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_TX)) -#define HFA384x_EVACK_TX_SET(value) ((UINT16)(((UINT16)(value)) << 1)) -#define HFA384x_EVACK_ISRX(value) ((UINT16)(((UINT16)(value)) & HFA384x_EVACK_RX)) -#define HFA384x_EVACK_RX_SET(value) ((UINT16)(((UINT16)(value)) << 0)) - -#define HFA384x_CONTROL_AUXEN_SET(value) ((UINT16)(((UINT16)(value)) << 14)) -#define HFA384x_CONTROL_AUXEN_GET(value) ((UINT16)(((UINT16)(value)) >> 14)) +#define HFA384x_CMD_ISBUSY(value) ((uint16_t)(((uint16_t)value) & HFA384x_CMD_BUSY)) +#define HFA384x_CMD_AINFO_GET(value) ((uint16_t)(((uint16_t)(value) & HFA384x_CMD_AINFO) >> 8)) +#define HFA384x_CMD_AINFO_SET(value) ((uint16_t)((uint16_t)(value) << 8)) +#define HFA384x_CMD_MACPORT_GET(value) ((uint16_t)(HFA384x_CMD_AINFO_GET((uint16_t)(value) & HFA384x_CMD_MACPORT))) +#define HFA384x_CMD_MACPORT_SET(value) ((uint16_t)HFA384x_CMD_AINFO_SET(value)) +#define HFA384x_CMD_ISRECL(value) ((uint16_t)(HFA384x_CMD_AINFO_GET((uint16_t)(value) & HFA384x_CMD_RECL))) +#define HFA384x_CMD_RECL_SET(value) ((uint16_t)HFA384x_CMD_AINFO_SET(value)) +#define HFA384x_CMD_QOS_GET(value) ((uint16_t((((uint16_t)(value))&((uint16_t)0x3000)) >> 12)) +#define HFA384x_CMD_QOS_SET(value) ((uint16_t)((((uint16_t)(value)) << 12) & 0x3000)) +#define HFA384x_CMD_ISWRITE(value) ((uint16_t)(HFA384x_CMD_AINFO_GET((uint16_t)(value) & HFA384x_CMD_WRITE))) +#define HFA384x_CMD_WRITE_SET(value) ((uint16_t)HFA384x_CMD_AINFO_SET((uint16_t)value)) +#define HFA384x_CMD_PROGMODE_GET(value) ((uint16_t)(HFA384x_CMD_AINFO_GET((uint16_t)(value) & HFA384x_CMD_PROGMODE))) +#define HFA384x_CMD_PROGMODE_SET(value) ((uint16_t)HFA384x_CMD_AINFO_SET((uint16_t)value)) +#define HFA384x_CMD_CMDCODE_GET(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_CMD_CMDCODE)) +#define HFA384x_CMD_CMDCODE_SET(value) ((uint16_t)(value)) + +#define HFA384x_STATUS_RESULT_GET(value) ((uint16_t)((((uint16_t)(value)) & HFA384x_STATUS_RESULT) >> 8)) +#define HFA384x_STATUS_RESULT_SET(value) (((uint16_t)(value)) << 8) +#define HFA384x_STATUS_CMDCODE_GET(value) (((uint16_t)(value)) & HFA384x_STATUS_CMDCODE) +#define HFA384x_STATUS_CMDCODE_SET(value) ((uint16_t)(value)) + +#define HFA384x_OFFSET_ISBUSY(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_OFFSET_BUSY)) +#define HFA384x_OFFSET_ISERR(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_OFFSET_ERR)) +#define HFA384x_OFFSET_DATAOFF_GET(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_OFFSET_DATAOFF)) +#define HFA384x_OFFSET_DATAOFF_SET(value) ((uint16_t)(value)) + +#define HFA384x_EVSTAT_ISTICK(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_TICK)) +#define HFA384x_EVSTAT_ISWTERR(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_WTERR)) +#define HFA384x_EVSTAT_ISINFDROP(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_INFDROP)) +#define HFA384x_EVSTAT_ISINFO(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_INFO)) +#define HFA384x_EVSTAT_ISDTIM(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_DTIM)) +#define HFA384x_EVSTAT_ISCMD(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_CMD)) +#define HFA384x_EVSTAT_ISALLOC(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_ALLOC)) +#define HFA384x_EVSTAT_ISTXEXC(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_TXEXC)) +#define HFA384x_EVSTAT_ISTX(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_TX)) +#define HFA384x_EVSTAT_ISRX(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVSTAT_RX)) + +#define HFA384x_EVSTAT_ISBAP_OP(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INT_BAP_OP)) + +#define HFA384x_INTEN_ISTICK(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_TICK)) +#define HFA384x_INTEN_TICK_SET(value) ((uint16_t)(((uint16_t)(value)) << 15)) +#define HFA384x_INTEN_ISWTERR(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_WTERR)) +#define HFA384x_INTEN_WTERR_SET(value) ((uint16_t)(((uint16_t)(value)) << 14)) +#define HFA384x_INTEN_ISINFDROP(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_INFDROP)) +#define HFA384x_INTEN_INFDROP_SET(value) ((uint16_t)(((uint16_t)(value)) << 13)) +#define HFA384x_INTEN_ISINFO(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_INFO)) +#define HFA384x_INTEN_INFO_SET(value) ((uint16_t)(((uint16_t)(value)) << 7)) +#define HFA384x_INTEN_ISDTIM(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_DTIM)) +#define HFA384x_INTEN_DTIM_SET(value) ((uint16_t)(((uint16_t)(value)) << 5)) +#define HFA384x_INTEN_ISCMD(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_CMD)) +#define HFA384x_INTEN_CMD_SET(value) ((uint16_t)(((uint16_t)(value)) << 4)) +#define HFA384x_INTEN_ISALLOC(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_ALLOC)) +#define HFA384x_INTEN_ALLOC_SET(value) ((uint16_t)(((uint16_t)(value)) << 3)) +#define HFA384x_INTEN_ISTXEXC(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_TXEXC)) +#define HFA384x_INTEN_TXEXC_SET(value) ((uint16_t)(((uint16_t)(value)) << 2)) +#define HFA384x_INTEN_ISTX(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_TX)) +#define HFA384x_INTEN_TX_SET(value) ((uint16_t)(((uint16_t)(value)) << 1)) +#define HFA384x_INTEN_ISRX(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_INTEN_RX)) +#define HFA384x_INTEN_RX_SET(value) ((uint16_t)(((uint16_t)(value)) << 0)) + +#define HFA384x_EVACK_ISTICK(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_TICK)) +#define HFA384x_EVACK_TICK_SET(value) ((uint16_t)(((uint16_t)(value)) << 15)) +#define HFA384x_EVACK_ISWTERR(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_WTERR)) +#define HFA384x_EVACK_WTERR_SET(value) ((uint16_t)(((uint16_t)(value)) << 14)) +#define HFA384x_EVACK_ISINFDROP(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_INFDROP)) +#define HFA384x_EVACK_INFDROP_SET(value) ((uint16_t)(((uint16_t)(value)) << 13)) +#define HFA384x_EVACK_ISINFO(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_INFO)) +#define HFA384x_EVACK_INFO_SET(value) ((uint16_t)(((uint16_t)(value)) << 7)) +#define HFA384x_EVACK_ISDTIM(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_DTIM)) +#define HFA384x_EVACK_DTIM_SET(value) ((uint16_t)(((uint16_t)(value)) << 5)) +#define HFA384x_EVACK_ISCMD(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_CMD)) +#define HFA384x_EVACK_CMD_SET(value) ((uint16_t)(((uint16_t)(value)) << 4)) +#define HFA384x_EVACK_ISALLOC(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_ALLOC)) +#define HFA384x_EVACK_ALLOC_SET(value) ((uint16_t)(((uint16_t)(value)) << 3)) +#define HFA384x_EVACK_ISTXEXC(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_TXEXC)) +#define HFA384x_EVACK_TXEXC_SET(value) ((uint16_t)(((uint16_t)(value)) << 2)) +#define HFA384x_EVACK_ISTX(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_TX)) +#define HFA384x_EVACK_TX_SET(value) ((uint16_t)(((uint16_t)(value)) << 1)) +#define HFA384x_EVACK_ISRX(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_EVACK_RX)) +#define HFA384x_EVACK_RX_SET(value) ((uint16_t)(((uint16_t)(value)) << 0)) + +#define HFA384x_CONTROL_AUXEN_SET(value) ((uint16_t)(((uint16_t)(value)) << 14)) +#define HFA384x_CONTROL_AUXEN_GET(value) ((uint16_t)(((uint16_t)(value)) >> 14)) /* Byte Order */ #ifdef __KERNEL__ -#define hfa384x2host_16(n) (__le16_to_cpu((UINT16)(n))) -#define hfa384x2host_32(n) (__le32_to_cpu((UINT32)(n))) -#define host2hfa384x_16(n) (__cpu_to_le16((UINT16)(n))) -#define host2hfa384x_32(n) (__cpu_to_le32((UINT32)(n))) +#define hfa384x2host_16(n) (__le16_to_cpu((uint16_t)(n))) +#define hfa384x2host_32(n) (__le32_to_cpu((uint32_t)(n))) +#define host2hfa384x_16(n) (__cpu_to_le16((uint16_t)(n))) +#define host2hfa384x_32(n) (__cpu_to_le32((uint32_t)(n))) #endif /* Host Maintained State Info */ @@ -929,14 +929,14 @@ PD Record codes /* Commonly used basic types */ typedef struct hfa384x_bytestr { - UINT16 len; - UINT8 data[0]; + uint16_t len; + uint8_t data[0]; } __WLAN_ATTRIB_PACK__ hfa384x_bytestr_t; typedef struct hfa384x_bytestr32 { - UINT16 len; - UINT8 data[32]; + uint16_t len; + uint8_t data[32]; } __WLAN_ATTRIB_PACK__ hfa384x_bytestr32_t; /*-------------------------------------------------------------------- @@ -946,114 +946,114 @@ Configuration Record Structures: /* Prototype structure: all configuration record structures start with these members */ -typedef struct hfa384x_record +typedef struct hfa384x_record { - UINT16 reclen; - UINT16 rid; + uint16_t reclen; + uint16_t rid; } __WLAN_ATTRIB_PACK__ hfa384x_rec_t; typedef struct hfa384x_record16 { - UINT16 reclen; - UINT16 rid; - UINT16 val; + uint16_t reclen; + uint16_t rid; + uint16_t val; } __WLAN_ATTRIB_PACK__ hfa384x_rec16_t; typedef struct hfa384x_record32 { - UINT16 reclen; - UINT16 rid; - UINT32 val; + uint16_t reclen; + uint16_t rid; + uint32_t val; } __WLAN_ATTRIB_PACK__ hfa384x_rec32; /*-- Hardware/Firmware Component Information ----------*/ typedef struct hfa384x_compident { - UINT16 id; - UINT16 variant; - UINT16 major; - UINT16 minor; + uint16_t id; + uint16_t variant; + uint16_t major; + uint16_t minor; } __WLAN_ATTRIB_PACK__ hfa384x_compident_t; typedef struct hfa384x_caplevel { - UINT16 role; - UINT16 id; - UINT16 variant; - UINT16 bottom; - UINT16 top; + uint16_t role; + uint16_t id; + uint16_t variant; + uint16_t bottom; + uint16_t top; } __WLAN_ATTRIB_PACK__ hfa384x_caplevel_t; /*-- Configuration Record: cnfPortType --*/ typedef struct hfa384x_cnfPortType { - UINT16 cnfPortType; + uint16_t cnfPortType; } __WLAN_ATTRIB_PACK__ hfa384x_cnfPortType_t; /*-- Configuration Record: cnfOwnMACAddress --*/ typedef struct hfa384x_cnfOwnMACAddress { - UINT8 cnfOwnMACAddress[6]; + uint8_t cnfOwnMACAddress[6]; } __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnMACAddress_t; /*-- Configuration Record: cnfDesiredSSID --*/ typedef struct hfa384x_cnfDesiredSSID { - UINT8 cnfDesiredSSID[34]; + uint8_t cnfDesiredSSID[34]; } __WLAN_ATTRIB_PACK__ hfa384x_cnfDesiredSSID_t; /*-- Configuration Record: cnfOwnChannel --*/ typedef struct hfa384x_cnfOwnChannel { - UINT16 cnfOwnChannel; + uint16_t cnfOwnChannel; } __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnChannel_t; /*-- Configuration Record: cnfOwnSSID --*/ typedef struct hfa384x_cnfOwnSSID { - UINT8 cnfOwnSSID[34]; + uint8_t cnfOwnSSID[34]; } __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnSSID_t; /*-- Configuration Record: cnfOwnATIMWindow --*/ typedef struct hfa384x_cnfOwnATIMWindow { - UINT16 cnfOwnATIMWindow; + uint16_t cnfOwnATIMWindow; } __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnATIMWindow_t; /*-- Configuration Record: cnfSystemScale --*/ typedef struct hfa384x_cnfSystemScale { - UINT16 cnfSystemScale; + uint16_t cnfSystemScale; } __WLAN_ATTRIB_PACK__ hfa384x_cnfSystemScale_t; /*-- Configuration Record: cnfMaxDataLength --*/ typedef struct hfa384x_cnfMaxDataLength { - UINT16 cnfMaxDataLength; + uint16_t cnfMaxDataLength; } __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxDataLength_t; /*-- Configuration Record: cnfWDSAddress --*/ typedef struct hfa384x_cnfWDSAddress { - UINT8 cnfWDSAddress[6]; + uint8_t cnfWDSAddress[6]; } __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddress_t; /*-- Configuration Record: cnfPMEnabled --*/ typedef struct hfa384x_cnfPMEnabled { - UINT16 cnfPMEnabled; + uint16_t cnfPMEnabled; } __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEnabled_t; /*-- Configuration Record: cnfPMEPS --*/ typedef struct hfa384x_cnfPMEPS { - UINT16 cnfPMEPS; + uint16_t cnfPMEPS; } __WLAN_ATTRIB_PACK__ hfa384x_cnfPMEPS_t; /*-- Configuration Record: cnfMulticastReceive --*/ typedef struct hfa384x_cnfMulticastReceive { - UINT16 cnfMulticastReceive; + uint16_t cnfMulticastReceive; } __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastReceive_t; /*-- Configuration Record: cnfAuthentication --*/ @@ -1064,37 +1064,37 @@ typedef struct hfa384x_cnfMulticastReceive /*-- Configuration Record: cnfMaxSleepDuration --*/ typedef struct hfa384x_cnfMaxSleepDuration { - UINT16 cnfMaxSleepDuration; + uint16_t cnfMaxSleepDuration; } __WLAN_ATTRIB_PACK__ hfa384x_cnfMaxSleepDuration_t; /*-- Configuration Record: cnfPMHoldoverDuration --*/ typedef struct hfa384x_cnfPMHoldoverDuration { - UINT16 cnfPMHoldoverDuration; + uint16_t cnfPMHoldoverDuration; } __WLAN_ATTRIB_PACK__ hfa384x_cnfPMHoldoverDuration_t; /*-- Configuration Record: cnfOwnName --*/ typedef struct hfa384x_cnfOwnName { - UINT8 cnfOwnName[34]; + uint8_t cnfOwnName[34]; } __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnName_t; /*-- Configuration Record: cnfOwnDTIMPeriod --*/ typedef struct hfa384x_cnfOwnDTIMPeriod { - UINT16 cnfOwnDTIMPeriod; + uint16_t cnfOwnDTIMPeriod; } __WLAN_ATTRIB_PACK__ hfa384x_cnfOwnDTIMPeriod_t; /*-- Configuration Record: cnfWDSAddress --*/ typedef struct hfa384x_cnfWDSAddressN { - UINT8 cnfWDSAddress[6]; + uint8_t cnfWDSAddress[6]; } __WLAN_ATTRIB_PACK__ hfa384x_cnfWDSAddressN_t; /*-- Configuration Record: cnfMulticastPMBuffering --*/ typedef struct hfa384x_cnfMulticastPMBuffering { - UINT16 cnfMulticastPMBuffering; + uint16_t cnfMulticastPMBuffering; } __WLAN_ATTRIB_PACK__ hfa384x_cnfMulticastPMBuffering_t; /*-------------------------------------------------------------------- @@ -1105,13 +1105,13 @@ Configuration Record Structures: /*-- Configuration Record: GroupAddresses --*/ typedef struct hfa384x_GroupAddresses { - UINT8 MACAddress[16][6]; + uint8_t MACAddress[16][6]; } __WLAN_ATTRIB_PACK__ hfa384x_GroupAddresses_t; /*-- Configuration Record: CreateIBSS --*/ typedef struct hfa384x_CreateIBSS { - UINT16 CreateIBSS; + uint16_t CreateIBSS; } __WLAN_ATTRIB_PACK__ hfa384x_CreateIBSS_t; #define HFA384x_CREATEIBSS_JOINCREATEIBSS 0 @@ -1122,87 +1122,87 @@ typedef struct hfa384x_CreateIBSS /*-- Configuration Record: FragmentationThreshold --*/ typedef struct hfa384x_FragmentationThreshold { - UINT16 FragmentationThreshold; + uint16_t FragmentationThreshold; } __WLAN_ATTRIB_PACK__ hfa384x_FragmentationThreshold_t; /*-- Configuration Record: RTSThreshold --*/ typedef struct hfa384x_RTSThreshold { - UINT16 RTSThreshold; + uint16_t RTSThreshold; } __WLAN_ATTRIB_PACK__ hfa384x_RTSThreshold_t; /*-- Configuration Record: TxRateControl --*/ typedef struct hfa384x_TxRateControl { - UINT16 TxRateControl; + uint16_t TxRateControl; } __WLAN_ATTRIB_PACK__ hfa384x_TxRateControl_t; /*-- Configuration Record: PromiscuousMode --*/ typedef struct hfa384x_PromiscuousMode { - UINT16 PromiscuousMode; + uint16_t PromiscuousMode; } __WLAN_ATTRIB_PACK__ hfa384x_PromiscuousMode_t; /*-- Configuration Record: ScanRequest (data portion only) --*/ typedef struct hfa384x_ScanRequest_data { - UINT16 channelList; - UINT16 txRate; + uint16_t channelList; + uint16_t txRate; } __WLAN_ATTRIB_PACK__ hfa384x_ScanRequest_data_t; /*-- Configuration Record: HostScanRequest (data portion only) --*/ typedef struct hfa384x_HostScanRequest_data { - UINT16 channelList; - UINT16 txRate; + uint16_t channelList; + uint16_t txRate; hfa384x_bytestr32_t ssid; } __WLAN_ATTRIB_PACK__ hfa384x_HostScanRequest_data_t; /*-- Configuration Record: JoinRequest (data portion only) --*/ typedef struct hfa384x_JoinRequest_data { - UINT8 bssid[WLAN_BSSID_LEN]; - UINT16 channel; + uint8_t bssid[WLAN_BSSID_LEN]; + uint16_t channel; } __WLAN_ATTRIB_PACK__ hfa384x_JoinRequest_data_t; /*-- Configuration Record: authenticateStation (data portion only) --*/ typedef struct hfa384x_authenticateStation_data { - UINT8 address[WLAN_ADDR_LEN]; - UINT16 status; - UINT16 algorithm; + uint8_t address[WLAN_ADDR_LEN]; + uint16_t status; + uint16_t algorithm; } __WLAN_ATTRIB_PACK__ hfa384x_authenticateStation_data_t; /*-- Configuration Record: associateStation (data portion only) --*/ typedef struct hfa384x_associateStation_data { - UINT8 address[WLAN_ADDR_LEN]; - UINT16 status; - UINT16 type; + uint8_t address[WLAN_ADDR_LEN]; + uint16_t status; + uint16_t type; } __WLAN_ATTRIB_PACK__ hfa384x_associateStation_data_t; /*-- Configuration Record: ChannelInfoRequest (data portion only) --*/ typedef struct hfa384x_ChannelInfoRequest_data { - UINT16 channelList; - UINT16 channelDwellTime; + uint16_t channelList; + uint16_t channelDwellTime; } __WLAN_ATTRIB_PACK__ hfa384x_ChannelInfoRequest_data_t; /*-- Configuration Record: WEPKeyMapping (data portion only) --*/ typedef struct hfa384x_WEPKeyMapping { - UINT8 address[WLAN_ADDR_LEN]; - UINT16 key_index; - UINT8 key[16]; - UINT8 mic_transmit_key[4]; - UINT8 mic_receive_key[4]; + uint8_t address[WLAN_ADDR_LEN]; + uint16_t key_index; + uint8_t key[16]; + uint8_t mic_transmit_key[4]; + uint8_t mic_receive_key[4]; } __WLAN_ATTRIB_PACK__ hfa384x_WEPKeyMapping_t; /*-- Configuration Record: WPAData (data portion only) --*/ typedef struct hfa384x_WPAData { - UINT16 datalen; - UINT8 data[0]; // max 80 + uint16_t datalen; + uint8_t data[0]; // max 80 } __WLAN_ATTRIB_PACK__ hfa384x_WPAData_t; /*-------------------------------------------------------------------- @@ -1212,7 +1212,7 @@ Configuration Record Structures: Behavior Parameters /*-- Configuration Record: TickTime --*/ typedef struct hfa384x_TickTime { - UINT16 TickTime; + uint16_t TickTime; } __WLAN_ATTRIB_PACK__ hfa384x_TickTime_t; /*-------------------------------------------------------------------- @@ -1222,146 +1222,146 @@ Information Record Structures: NIC Information /*-- Information Record: MaxLoadTime --*/ typedef struct hfa384x_MaxLoadTime { - UINT16 MaxLoadTime; + uint16_t MaxLoadTime; } __WLAN_ATTRIB_PACK__ hfa384x_MaxLoadTime_t; /*-- Information Record: DownLoadBuffer --*/ /* NOTE: The page and offset are in AUX format */ typedef struct hfa384x_downloadbuffer { - UINT16 page; - UINT16 offset; - UINT16 len; + uint16_t page; + uint16_t offset; + uint16_t len; } __WLAN_ATTRIB_PACK__ hfa384x_downloadbuffer_t; /*-- Information Record: PRIIdentity --*/ typedef struct hfa384x_PRIIdentity { - UINT16 PRICompID; - UINT16 PRIVariant; - UINT16 PRIMajorVersion; - UINT16 PRIMinorVersion; + uint16_t PRICompID; + uint16_t PRIVariant; + uint16_t PRIMajorVersion; + uint16_t PRIMinorVersion; } __WLAN_ATTRIB_PACK__ hfa384x_PRIIdentity_t; /*-- Information Record: PRISupRange --*/ typedef struct hfa384x_PRISupRange { - UINT16 PRIRole; - UINT16 PRIID; - UINT16 PRIVariant; - UINT16 PRIBottom; - UINT16 PRITop; + uint16_t PRIRole; + uint16_t PRIID; + uint16_t PRIVariant; + uint16_t PRIBottom; + uint16_t PRITop; } __WLAN_ATTRIB_PACK__ hfa384x_PRISupRange_t; /*-- Information Record: CFIActRanges --*/ typedef struct hfa384x_CFIActRanges { - UINT16 CFIRole; - UINT16 CFIID; - UINT16 CFIVariant; - UINT16 CFIBottom; - UINT16 CFITop; + uint16_t CFIRole; + uint16_t CFIID; + uint16_t CFIVariant; + uint16_t CFIBottom; + uint16_t CFITop; } __WLAN_ATTRIB_PACK__ hfa384x_CFIActRanges_t; /*-- Information Record: NICSerialNumber --*/ typedef struct hfa384x_NICSerialNumber { - UINT8 NICSerialNumber[12]; + uint8_t NICSerialNumber[12]; } __WLAN_ATTRIB_PACK__ hfa384x_NICSerialNumber_t; /*-- Information Record: NICIdentity --*/ typedef struct hfa384x_NICIdentity { - UINT16 NICCompID; - UINT16 NICVariant; - UINT16 NICMajorVersion; - UINT16 NICMinorVersion; + uint16_t NICCompID; + uint16_t NICVariant; + uint16_t NICMajorVersion; + uint16_t NICMinorVersion; } __WLAN_ATTRIB_PACK__ hfa384x_NICIdentity_t; /*-- Information Record: MFISupRange --*/ typedef struct hfa384x_MFISupRange { - UINT16 MFIRole; - UINT16 MFIID; - UINT16 MFIVariant; - UINT16 MFIBottom; - UINT16 MFITop; + uint16_t MFIRole; + uint16_t MFIID; + uint16_t MFIVariant; + uint16_t MFIBottom; + uint16_t MFITop; } __WLAN_ATTRIB_PACK__ hfa384x_MFISupRange_t; /*-- Information Record: CFISupRange --*/ typedef struct hfa384x_CFISupRange { - UINT16 CFIRole; - UINT16 CFIID; - UINT16 CFIVariant; - UINT16 CFIBottom; - UINT16 CFITop; + uint16_t CFIRole; + uint16_t CFIID; + uint16_t CFIVariant; + uint16_t CFIBottom; + uint16_t CFITop; } __WLAN_ATTRIB_PACK__ hfa384x_CFISupRange_t; /*-- Information Record: BUILDSEQ:BuildSeq --*/ typedef struct hfa384x_BuildSeq { - UINT16 primary; - UINT16 secondary; + uint16_t primary; + uint16_t secondary; } __WLAN_ATTRIB_PACK__ hfa384x_BuildSeq_t; /*-- Information Record: FWID --*/ #define HFA384x_FWID_LEN 14 typedef struct hfa384x_FWID { - UINT8 primary[HFA384x_FWID_LEN]; - UINT8 secondary[HFA384x_FWID_LEN]; + uint8_t primary[HFA384x_FWID_LEN]; + uint8_t secondary[HFA384x_FWID_LEN]; } __WLAN_ATTRIB_PACK__ hfa384x_FWID_t; /*-- Information Record: ChannelList --*/ typedef struct hfa384x_ChannelList { - UINT16 ChannelList; + uint16_t ChannelList; } __WLAN_ATTRIB_PACK__ hfa384x_ChannelList_t; /*-- Information Record: RegulatoryDomains --*/ typedef struct hfa384x_RegulatoryDomains { - UINT8 RegulatoryDomains[12]; + uint8_t RegulatoryDomains[12]; } __WLAN_ATTRIB_PACK__ hfa384x_RegulatoryDomains_t; /*-- Information Record: TempType --*/ typedef struct hfa384x_TempType { - UINT16 TempType; + uint16_t TempType; } __WLAN_ATTRIB_PACK__ hfa384x_TempType_t; /*-- Information Record: CIS --*/ typedef struct hfa384x_CIS { - UINT8 CIS[480]; + uint8_t CIS[480]; } __WLAN_ATTRIB_PACK__ hfa384x_CIS_t; /*-- Information Record: STAIdentity --*/ typedef struct hfa384x_STAIdentity { - UINT16 STACompID; - UINT16 STAVariant; - UINT16 STAMajorVersion; - UINT16 STAMinorVersion; + uint16_t STACompID; + uint16_t STAVariant; + uint16_t STAMajorVersion; + uint16_t STAMinorVersion; } __WLAN_ATTRIB_PACK__ hfa384x_STAIdentity_t; /*-- Information Record: STASupRange --*/ typedef struct hfa384x_STASupRange { - UINT16 STARole; - UINT16 STAID; - UINT16 STAVariant; - UINT16 STABottom; - UINT16 STATop; + uint16_t STARole; + uint16_t STAID; + uint16_t STAVariant; + uint16_t STABottom; + uint16_t STATop; } __WLAN_ATTRIB_PACK__ hfa384x_STASupRange_t; /*-- Information Record: MFIActRanges --*/ typedef struct hfa384x_MFIActRanges { - UINT16 MFIRole; - UINT16 MFIID; - UINT16 MFIVariant; - UINT16 MFIBottom; - UINT16 MFITop; + uint16_t MFIRole; + uint16_t MFIID; + uint16_t MFIVariant; + uint16_t MFIBottom; + uint16_t MFITop; } __WLAN_ATTRIB_PACK__ hfa384x_MFIActRanges_t; /*-------------------------------------------------------------------- @@ -1371,187 +1371,187 @@ Information Record Structures: NIC Information /*-- Information Record: PortStatus --*/ typedef struct hfa384x_PortStatus { - UINT16 PortStatus; + uint16_t PortStatus; } __WLAN_ATTRIB_PACK__ hfa384x_PortStatus_t; -#define HFA384x_PSTATUS_DISABLED ((UINT16)1) -#define HFA384x_PSTATUS_SEARCHING ((UINT16)2) -#define HFA384x_PSTATUS_CONN_IBSS ((UINT16)3) -#define HFA384x_PSTATUS_CONN_ESS ((UINT16)4) -#define HFA384x_PSTATUS_OUTOFRANGE ((UINT16)5) -#define HFA384x_PSTATUS_CONN_WDS ((UINT16)6) +#define HFA384x_PSTATUS_DISABLED ((uint16_t)1) +#define HFA384x_PSTATUS_SEARCHING ((uint16_t)2) +#define HFA384x_PSTATUS_CONN_IBSS ((uint16_t)3) +#define HFA384x_PSTATUS_CONN_ESS ((uint16_t)4) +#define HFA384x_PSTATUS_OUTOFRANGE ((uint16_t)5) +#define HFA384x_PSTATUS_CONN_WDS ((uint16_t)6) /*-- Information Record: CurrentSSID --*/ typedef struct hfa384x_CurrentSSID { - UINT8 CurrentSSID[34]; + uint8_t CurrentSSID[34]; } __WLAN_ATTRIB_PACK__ hfa384x_CurrentSSID_t; /*-- Information Record: CurrentBSSID --*/ typedef struct hfa384x_CurrentBSSID { - UINT8 CurrentBSSID[6]; + uint8_t CurrentBSSID[6]; } __WLAN_ATTRIB_PACK__ hfa384x_CurrentBSSID_t; /*-- Information Record: commsquality --*/ typedef struct hfa384x_commsquality { - UINT16 CQ_currBSS; - UINT16 ASL_currBSS; - UINT16 ANL_currFC; + uint16_t CQ_currBSS; + uint16_t ASL_currBSS; + uint16_t ANL_currFC; } __WLAN_ATTRIB_PACK__ hfa384x_commsquality_t; /*-- Information Record: dmbcommsquality --*/ typedef struct hfa384x_dbmcommsquality { - UINT16 CQdbm_currBSS; - UINT16 ASLdbm_currBSS; - UINT16 ANLdbm_currFC; + uint16_t CQdbm_currBSS; + uint16_t ASLdbm_currBSS; + uint16_t ANLdbm_currFC; } __WLAN_ATTRIB_PACK__ hfa384x_dbmcommsquality_t; /*-- Information Record: CurrentTxRate --*/ typedef struct hfa384x_CurrentTxRate { - UINT16 CurrentTxRate; + uint16_t CurrentTxRate; } __WLAN_ATTRIB_PACK__ hfa384x_CurrentTxRate_t; /*-- Information Record: CurrentBeaconInterval --*/ typedef struct hfa384x_CurrentBeaconInterval { - UINT16 CurrentBeaconInterval; + uint16_t CurrentBeaconInterval; } __WLAN_ATTRIB_PACK__ hfa384x_CurrentBeaconInterval_t; /*-- Information Record: CurrentScaleThresholds --*/ typedef struct hfa384x_CurrentScaleThresholds { - UINT16 EnergyDetectThreshold; - UINT16 CarrierDetectThreshold; - UINT16 DeferDetectThreshold; - UINT16 CellSearchThreshold; /* Stations only */ - UINT16 DeadSpotThreshold; /* Stations only */ + uint16_t EnergyDetectThreshold; + uint16_t CarrierDetectThreshold; + uint16_t DeferDetectThreshold; + uint16_t CellSearchThreshold; /* Stations only */ + uint16_t DeadSpotThreshold; /* Stations only */ } __WLAN_ATTRIB_PACK__ hfa384x_CurrentScaleThresholds_t; /*-- Information Record: ProtocolRspTime --*/ typedef struct hfa384x_ProtocolRspTime { - UINT16 ProtocolRspTime; + uint16_t ProtocolRspTime; } __WLAN_ATTRIB_PACK__ hfa384x_ProtocolRspTime_t; /*-- Information Record: ShortRetryLimit --*/ typedef struct hfa384x_ShortRetryLimit { - UINT16 ShortRetryLimit; + uint16_t ShortRetryLimit; } __WLAN_ATTRIB_PACK__ hfa384x_ShortRetryLimit_t; /*-- Information Record: LongRetryLimit --*/ typedef struct hfa384x_LongRetryLimit { - UINT16 LongRetryLimit; + uint16_t LongRetryLimit; } __WLAN_ATTRIB_PACK__ hfa384x_LongRetryLimit_t; /*-- Information Record: MaxTransmitLifetime --*/ typedef struct hfa384x_MaxTransmitLifetime { - UINT16 MaxTransmitLifetime; + uint16_t MaxTransmitLifetime; } __WLAN_ATTRIB_PACK__ hfa384x_MaxTransmitLifetime_t; /*-- Information Record: MaxReceiveLifetime --*/ typedef struct hfa384x_MaxReceiveLifetime { - UINT16 MaxReceiveLifetime; + uint16_t MaxReceiveLifetime; } __WLAN_ATTRIB_PACK__ hfa384x_MaxReceiveLifetime_t; /*-- Information Record: CFPollable --*/ typedef struct hfa384x_CFPollable { - UINT16 CFPollable; + uint16_t CFPollable; } __WLAN_ATTRIB_PACK__ hfa384x_CFPollable_t; /*-- Information Record: AuthenticationAlgorithms --*/ typedef struct hfa384x_AuthenticationAlgorithms { - UINT16 AuthenticationType; - UINT16 TypeEnabled; + uint16_t AuthenticationType; + uint16_t TypeEnabled; } __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_t; /*-- Information Record: AuthenticationAlgorithms (data only --*/ typedef struct hfa384x_AuthenticationAlgorithms_data { - UINT16 AuthenticationType; - UINT16 TypeEnabled; + uint16_t AuthenticationType; + uint16_t TypeEnabled; } __WLAN_ATTRIB_PACK__ hfa384x_AuthenticationAlgorithms_data_t; /*-- Information Record: PrivacyOptionImplemented --*/ typedef struct hfa384x_PrivacyOptionImplemented { - UINT16 PrivacyOptionImplemented; + uint16_t PrivacyOptionImplemented; } __WLAN_ATTRIB_PACK__ hfa384x_PrivacyOptionImplemented_t; /*-- Information Record: OwnMACAddress --*/ typedef struct hfa384x_OwnMACAddress { - UINT8 OwnMACAddress[6]; + uint8_t OwnMACAddress[6]; } __WLAN_ATTRIB_PACK__ hfa384x_OwnMACAddress_t; /*-- Information Record: PCFInfo --*/ typedef struct hfa384x_PCFInfo { - UINT16 MediumOccupancyLimit; - UINT16 CFPPeriod; - UINT16 CFPMaxDuration; - UINT16 CFPFlags; + uint16_t MediumOccupancyLimit; + uint16_t CFPPeriod; + uint16_t CFPMaxDuration; + uint16_t CFPFlags; } __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_t; /*-- Information Record: PCFInfo (data portion only) --*/ typedef struct hfa384x_PCFInfo_data { - UINT16 MediumOccupancyLimit; - UINT16 CFPPeriod; - UINT16 CFPMaxDuration; - UINT16 CFPFlags; + uint16_t MediumOccupancyLimit; + uint16_t CFPPeriod; + uint16_t CFPMaxDuration; + uint16_t CFPFlags; } __WLAN_ATTRIB_PACK__ hfa384x_PCFInfo_data_t; /*-------------------------------------------------------------------- -Information Record Structures: Modem Information Records +Information Record Structures: Modem Information Records --------------------------------------------------------------------*/ /*-- Information Record: PHYType --*/ typedef struct hfa384x_PHYType { - UINT16 PHYType; + uint16_t PHYType; } __WLAN_ATTRIB_PACK__ hfa384x_PHYType_t; /*-- Information Record: CurrentChannel --*/ typedef struct hfa384x_CurrentChannel { - UINT16 CurrentChannel; + uint16_t CurrentChannel; } __WLAN_ATTRIB_PACK__ hfa384x_CurrentChannel_t; /*-- Information Record: CurrentPowerState --*/ typedef struct hfa384x_CurrentPowerState { - UINT16 CurrentPowerState; + uint16_t CurrentPowerState; } __WLAN_ATTRIB_PACK__ hfa384x_CurrentPowerState_t; /*-- Information Record: CCAMode --*/ typedef struct hfa384x_CCAMode { - UINT16 CCAMode; + uint16_t CCAMode; } __WLAN_ATTRIB_PACK__ hfa384x_CCAMode_t; /*-- Information Record: SupportedDataRates --*/ typedef struct hfa384x_SupportedDataRates { - UINT8 SupportedDataRates[10]; + uint8_t SupportedDataRates[10]; } __WLAN_ATTRIB_PACK__ hfa384x_SupportedDataRates_t; /*-- Information Record: LFOStatus --*/ -typedef struct hfa384x_LFOStatus +typedef struct hfa384x_LFOStatus { - UINT16 TestResults; - UINT16 LFOResult; - UINT16 VRHFOResult; + uint16_t TestResults; + uint16_t LFOResult; + uint16_t VRHFOResult; } __WLAN_ATTRIB_PACK__ hfa384x_LFOStatus_t; #define HFA384x_TESTRESULT_ALLPASSED BIT0 @@ -1563,11 +1563,11 @@ typedef struct hfa384x_LFOStatus /*-- Information Record: LEDControl --*/ typedef struct hfa384x_LEDControl { - UINT16 searching_on; - UINT16 searching_off; - UINT16 assoc_on; - UINT16 assoc_off; - UINT16 activity; + uint16_t searching_on; + uint16_t searching_off; + uint16_t assoc_on; + uint16_t assoc_off; + uint16_t activity; } __WLAN_ATTRIB_PACK__ hfa384x_LEDControl_t; /*-------------------------------------------------------------------- @@ -1578,32 +1578,32 @@ FRAME DESCRIPTORS: Offsets ---------------------------------------------------------------------- Control Info (offset 44-51) --------------------------------------------------------------------*/ -#define HFA384x_FD_STATUS_OFF ((UINT16)0x44) -#define HFA384x_FD_TIME_OFF ((UINT16)0x46) -#define HFA384x_FD_SWSUPPORT_OFF ((UINT16)0x4A) -#define HFA384x_FD_SILENCE_OFF ((UINT16)0x4A) -#define HFA384x_FD_SIGNAL_OFF ((UINT16)0x4B) -#define HFA384x_FD_RATE_OFF ((UINT16)0x4C) -#define HFA384x_FD_RXFLOW_OFF ((UINT16)0x4D) -#define HFA384x_FD_RESERVED_OFF ((UINT16)0x4E) -#define HFA384x_FD_TXCONTROL_OFF ((UINT16)0x50) +#define HFA384x_FD_STATUS_OFF ((uint16_t)0x44) +#define HFA384x_FD_TIME_OFF ((uint16_t)0x46) +#define HFA384x_FD_SWSUPPORT_OFF ((uint16_t)0x4A) +#define HFA384x_FD_SILENCE_OFF ((uint16_t)0x4A) +#define HFA384x_FD_SIGNAL_OFF ((uint16_t)0x4B) +#define HFA384x_FD_RATE_OFF ((uint16_t)0x4C) +#define HFA384x_FD_RXFLOW_OFF ((uint16_t)0x4D) +#define HFA384x_FD_RESERVED_OFF ((uint16_t)0x4E) +#define HFA384x_FD_TXCONTROL_OFF ((uint16_t)0x50) /*-------------------------------------------------------------------- 802.11 Header (offset 52-6B) --------------------------------------------------------------------*/ -#define HFA384x_FD_FRAMECONTROL_OFF ((UINT16)0x52) -#define HFA384x_FD_DURATIONID_OFF ((UINT16)0x54) -#define HFA384x_FD_ADDRESS1_OFF ((UINT16)0x56) -#define HFA384x_FD_ADDRESS2_OFF ((UINT16)0x5C) -#define HFA384x_FD_ADDRESS3_OFF ((UINT16)0x62) -#define HFA384x_FD_SEQCONTROL_OFF ((UINT16)0x68) -#define HFA384x_FD_ADDRESS4_OFF ((UINT16)0x6A) -#define HFA384x_FD_DATALEN_OFF ((UINT16)0x70) +#define HFA384x_FD_FRAMECONTROL_OFF ((uint16_t)0x52) +#define HFA384x_FD_DURATIONID_OFF ((uint16_t)0x54) +#define HFA384x_FD_ADDRESS1_OFF ((uint16_t)0x56) +#define HFA384x_FD_ADDRESS2_OFF ((uint16_t)0x5C) +#define HFA384x_FD_ADDRESS3_OFF ((uint16_t)0x62) +#define HFA384x_FD_SEQCONTROL_OFF ((uint16_t)0x68) +#define HFA384x_FD_ADDRESS4_OFF ((uint16_t)0x6A) +#define HFA384x_FD_DATALEN_OFF ((uint16_t)0x70) /*-------------------------------------------------------------------- 802.3 Header (offset 72-7F) --------------------------------------------------------------------*/ -#define HFA384x_FD_DESTADDRESS_OFF ((UINT16)0x72) -#define HFA384x_FD_SRCADDRESS_OFF ((UINT16)0x78) -#define HFA384x_FD_DATALENGTH_OFF ((UINT16)0x7E) +#define HFA384x_FD_DESTADDRESS_OFF ((uint16_t)0x72) +#define HFA384x_FD_SRCADDRESS_OFF ((uint16_t)0x78) +#define HFA384x_FD_DATALENGTH_OFF ((uint16_t)0x7E) /*-------------------------------------------------------------------- FRAME STRUCTURES: Communication Frames @@ -1613,67 +1613,67 @@ Communication Frames: Transmit Frames /*-- Communication Frame: Transmit Frame Structure --*/ typedef struct hfa384x_tx_frame { - UINT16 status; - UINT16 reserved1; - UINT16 reserved2; - UINT32 sw_support; - UINT8 tx_retrycount; - UINT8 tx_rate; - UINT16 tx_control; + uint16_t status; + uint16_t reserved1; + uint16_t reserved2; + uint32_t sw_support; + uint8_t tx_retrycount; + uint8_t tx_rate; + uint16_t tx_control; /*-- 802.11 Header Information --*/ - UINT16 frame_control; - UINT16 duration_id; - UINT8 address1[6]; - UINT8 address2[6]; - UINT8 address3[6]; - UINT16 sequence_control; - UINT8 address4[6]; - UINT16 data_len; /* little endian format */ + uint16_t frame_control; + uint16_t duration_id; + uint8_t address1[6]; + uint8_t address2[6]; + uint8_t address3[6]; + uint16_t sequence_control; + uint8_t address4[6]; + uint16_t data_len; /* little endian format */ /*-- 802.3 Header Information --*/ - UINT8 dest_addr[6]; - UINT8 src_addr[6]; - UINT16 data_length; /* big endian format */ + uint8_t dest_addr[6]; + uint8_t src_addr[6]; + uint16_t data_length; /* big endian format */ } __WLAN_ATTRIB_PACK__ hfa384x_tx_frame_t; /*-------------------------------------------------------------------- Communication Frames: Field Masks for Transmit Frames --------------------------------------------------------------------*/ /*-- Status Field --*/ -#define HFA384x_TXSTATUS_ACKERR ((UINT16)BIT5) -#define HFA384x_TXSTATUS_FORMERR ((UINT16)BIT3) -#define HFA384x_TXSTATUS_DISCON ((UINT16)BIT2) -#define HFA384x_TXSTATUS_AGEDERR ((UINT16)BIT1) -#define HFA384x_TXSTATUS_RETRYERR ((UINT16)BIT0) +#define HFA384x_TXSTATUS_ACKERR ((uint16_t)BIT5) +#define HFA384x_TXSTATUS_FORMERR ((uint16_t)BIT3) +#define HFA384x_TXSTATUS_DISCON ((uint16_t)BIT2) +#define HFA384x_TXSTATUS_AGEDERR ((uint16_t)BIT1) +#define HFA384x_TXSTATUS_RETRYERR ((uint16_t)BIT0) /*-- Transmit Control Field --*/ -#define HFA384x_TX_CFPOLL ((UINT16)BIT12) -#define HFA384x_TX_PRST ((UINT16)BIT11) -#define HFA384x_TX_MACPORT ((UINT16)(BIT10 | BIT9 | BIT8)) -#define HFA384x_TX_NOENCRYPT ((UINT16)BIT7) -#define HFA384x_TX_RETRYSTRAT ((UINT16)(BIT6 | BIT5)) -#define HFA384x_TX_STRUCTYPE ((UINT16)(BIT4 | BIT3)) -#define HFA384x_TX_TXEX ((UINT16)BIT2) -#define HFA384x_TX_TXOK ((UINT16)BIT1) +#define HFA384x_TX_CFPOLL ((uint16_t)BIT12) +#define HFA384x_TX_PRST ((uint16_t)BIT11) +#define HFA384x_TX_MACPORT ((uint16_t)(BIT10 | BIT9 | BIT8)) +#define HFA384x_TX_NOENCRYPT ((uint16_t)BIT7) +#define HFA384x_TX_RETRYSTRAT ((uint16_t)(BIT6 | BIT5)) +#define HFA384x_TX_STRUCTYPE ((uint16_t)(BIT4 | BIT3)) +#define HFA384x_TX_TXEX ((uint16_t)BIT2) +#define HFA384x_TX_TXOK ((uint16_t)BIT1) /*-------------------------------------------------------------------- Communication Frames: Test/Get/Set Field Values for Transmit Frames --------------------------------------------------------------------*/ /*-- Status Field --*/ #define HFA384x_TXSTATUS_ISERROR(v) \ - (((UINT16)(v))&\ + (((uint16_t)(v))&\ (HFA384x_TXSTATUS_ACKERR|HFA384x_TXSTATUS_FORMERR|\ HFA384x_TXSTATUS_DISCON|HFA384x_TXSTATUS_AGEDERR|\ HFA384x_TXSTATUS_RETRYERR)) -#define HFA384x_TXSTATUS_ISACKERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_ACKERR)) -#define HFA384x_TXSTATUS_ISFORMERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_FORMERR)) -#define HFA384x_TXSTATUS_ISDISCON(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_DISCON)) -#define HFA384x_TXSTATUS_ISAGEDERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_AGEDERR)) -#define HFA384x_TXSTATUS_ISRETRYERR(v) ((UINT16)(((UINT16)(v)) & HFA384x_TXSTATUS_RETRYERR)) +#define HFA384x_TXSTATUS_ISACKERR(v) ((uint16_t)(((uint16_t)(v)) & HFA384x_TXSTATUS_ACKERR)) +#define HFA384x_TXSTATUS_ISFORMERR(v) ((uint16_t)(((uint16_t)(v)) & HFA384x_TXSTATUS_FORMERR)) +#define HFA384x_TXSTATUS_ISDISCON(v) ((uint16_t)(((uint16_t)(v)) & HFA384x_TXSTATUS_DISCON)) +#define HFA384x_TXSTATUS_ISAGEDERR(v) ((uint16_t)(((uint16_t)(v)) & HFA384x_TXSTATUS_AGEDERR)) +#define HFA384x_TXSTATUS_ISRETRYERR(v) ((uint16_t)(((uint16_t)(v)) & HFA384x_TXSTATUS_RETRYERR)) -#define HFA384x_TX_GET(v,m,s) ((((UINT16)(v))&((UINT16)(m)))>>((UINT16)(s))) -#define HFA384x_TX_SET(v,m,s) ((((UINT16)(v))<<((UINT16)(s)))&((UINT16)(m))) +#define HFA384x_TX_GET(v,m,s) ((((uint16_t)(v))&((uint16_t)(m)))>>((uint16_t)(s))) +#define HFA384x_TX_SET(v,m,s) ((((uint16_t)(v))<<((uint16_t)(s)))&((uint16_t)(m))) #define HFA384x_TX_CFPOLL_GET(v) HFA384x_TX_GET(v, HFA384x_TX_CFPOLL,12) #define HFA384x_TX_CFPOLL_SET(v) HFA384x_TX_SET(v, HFA384x_TX_CFPOLL,12) @@ -1698,70 +1698,70 @@ Communication Frames: Receive Frames typedef struct hfa384x_rx_frame { /*-- MAC rx descriptor (hfa384x byte order) --*/ - UINT16 status; - UINT32 time; - UINT8 silence; - UINT8 signal; - UINT8 rate; - UINT8 rx_flow; - UINT16 reserved1; - UINT16 reserved2; + uint16_t status; + uint32_t time; + uint8_t silence; + uint8_t signal; + uint8_t rate; + uint8_t rx_flow; + uint16_t reserved1; + uint16_t reserved2; /*-- 802.11 Header Information (802.11 byte order) --*/ - UINT16 frame_control; - UINT16 duration_id; - UINT8 address1[6]; - UINT8 address2[6]; - UINT8 address3[6]; - UINT16 sequence_control; - UINT8 address4[6]; - UINT16 data_len; /* hfa384x (little endian) format */ + uint16_t frame_control; + uint16_t duration_id; + uint8_t address1[6]; + uint8_t address2[6]; + uint8_t address3[6]; + uint16_t sequence_control; + uint8_t address4[6]; + uint16_t data_len; /* hfa384x (little endian) format */ /*-- 802.3 Header Information --*/ - UINT8 dest_addr[6]; - UINT8 src_addr[6]; - UINT16 data_length; /* IEEE? (big endian) format */ + uint8_t dest_addr[6]; + uint8_t src_addr[6]; + uint16_t data_length; /* IEEE? (big endian) format */ } __WLAN_ATTRIB_PACK__ hfa384x_rx_frame_t; /*-------------------------------------------------------------------- Communication Frames: Field Masks for Receive Frames --------------------------------------------------------------------*/ /*-- Offsets --------*/ -#define HFA384x_RX_DATA_LEN_OFF ((UINT16)44) -#define HFA384x_RX_80211HDR_OFF ((UINT16)14) -#define HFA384x_RX_DATA_OFF ((UINT16)60) +#define HFA384x_RX_DATA_LEN_OFF ((uint16_t)44) +#define HFA384x_RX_80211HDR_OFF ((uint16_t)14) +#define HFA384x_RX_DATA_OFF ((uint16_t)60) /*-- Status Fields --*/ -#define HFA384x_RXSTATUS_MSGTYPE ((UINT16)(BIT15 | BIT14 | BIT13)) -#define HFA384x_RXSTATUS_MACPORT ((UINT16)(BIT10 | BIT9 | BIT8)) -#define HFA384x_RXSTATUS_UNDECR ((UINT16)BIT1) -#define HFA384x_RXSTATUS_FCSERR ((UINT16)BIT0) +#define HFA384x_RXSTATUS_MSGTYPE ((uint16_t)(BIT15 | BIT14 | BIT13)) +#define HFA384x_RXSTATUS_MACPORT ((uint16_t)(BIT10 | BIT9 | BIT8)) +#define HFA384x_RXSTATUS_UNDECR ((uint16_t)BIT1) +#define HFA384x_RXSTATUS_FCSERR ((uint16_t)BIT0) /*-------------------------------------------------------------------- Communication Frames: Test/Get/Set Field Values for Receive Frames --------------------------------------------------------------------*/ -#define HFA384x_RXSTATUS_MSGTYPE_GET(value) ((UINT16)((((UINT16)(value)) & HFA384x_RXSTATUS_MSGTYPE) >> 13)) -#define HFA384x_RXSTATUS_MSGTYPE_SET(value) ((UINT16)(((UINT16)(value)) << 13)) -#define HFA384x_RXSTATUS_MACPORT_GET(value) ((UINT16)((((UINT16)(value)) & HFA384x_RXSTATUS_MACPORT) >> 8)) -#define HFA384x_RXSTATUS_MACPORT_SET(value) ((UINT16)(((UINT16)(value)) << 8)) -#define HFA384x_RXSTATUS_ISUNDECR(value) ((UINT16)(((UINT16)(value)) & HFA384x_RXSTATUS_UNDECR)) -#define HFA384x_RXSTATUS_ISFCSERR(value) ((UINT16)(((UINT16)(value)) & HFA384x_RXSTATUS_FCSERR)) +#define HFA384x_RXSTATUS_MSGTYPE_GET(value) ((uint16_t)((((uint16_t)(value)) & HFA384x_RXSTATUS_MSGTYPE) >> 13)) +#define HFA384x_RXSTATUS_MSGTYPE_SET(value) ((uint16_t)(((uint16_t)(value)) << 13)) +#define HFA384x_RXSTATUS_MACPORT_GET(value) ((uint16_t)((((uint16_t)(value)) & HFA384x_RXSTATUS_MACPORT) >> 8)) +#define HFA384x_RXSTATUS_MACPORT_SET(value) ((uint16_t)(((uint16_t)(value)) << 8)) +#define HFA384x_RXSTATUS_ISUNDECR(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_RXSTATUS_UNDECR)) +#define HFA384x_RXSTATUS_ISFCSERR(value) ((uint16_t)(((uint16_t)(value)) & HFA384x_RXSTATUS_FCSERR)) /*-------------------------------------------------------------------- FRAME STRUCTURES: Information Types and Information Frame Structures ---------------------------------------------------------------------- Information Types --------------------------------------------------------------------*/ -#define HFA384x_IT_HANDOVERADDR ((UINT16)0xF000UL) -#define HFA384x_IT_HANDOVERDEAUTHADDRESS ((UINT16)0xF001UL)//AP 1.3.7 -#define HFA384x_IT_COMMTALLIES ((UINT16)0xF100UL) -#define HFA384x_IT_SCANRESULTS ((UINT16)0xF101UL) -#define HFA384x_IT_CHINFORESULTS ((UINT16)0xF102UL) -#define HFA384x_IT_HOSTSCANRESULTS ((UINT16)0xF103UL) -#define HFA384x_IT_LINKSTATUS ((UINT16)0xF200UL) -#define HFA384x_IT_ASSOCSTATUS ((UINT16)0xF201UL) -#define HFA384x_IT_AUTHREQ ((UINT16)0xF202UL) -#define HFA384x_IT_PSUSERCNT ((UINT16)0xF203UL) -#define HFA384x_IT_KEYIDCHANGED ((UINT16)0xF204UL) -#define HFA384x_IT_ASSOCREQ ((UINT16)0xF205UL) -#define HFA384x_IT_MICFAILURE ((UINT16)0xF206UL) +#define HFA384x_IT_HANDOVERADDR ((uint16_t)0xF000UL) +#define HFA384x_IT_HANDOVERDEAUTHADDRESS ((uint16_t)0xF001UL)//AP 1.3.7 +#define HFA384x_IT_COMMTALLIES ((uint16_t)0xF100UL) +#define HFA384x_IT_SCANRESULTS ((uint16_t)0xF101UL) +#define HFA384x_IT_CHINFORESULTS ((uint16_t)0xF102UL) +#define HFA384x_IT_HOSTSCANRESULTS ((uint16_t)0xF103UL) +#define HFA384x_IT_LINKSTATUS ((uint16_t)0xF200UL) +#define HFA384x_IT_ASSOCSTATUS ((uint16_t)0xF201UL) +#define HFA384x_IT_AUTHREQ ((uint16_t)0xF202UL) +#define HFA384x_IT_PSUSERCNT ((uint16_t)0xF203UL) +#define HFA384x_IT_KEYIDCHANGED ((uint16_t)0xF204UL) +#define HFA384x_IT_ASSOCREQ ((uint16_t)0xF205UL) +#define HFA384x_IT_MICFAILURE ((uint16_t)0xF206UL) /*-------------------------------------------------------------------- Information Frames Structures @@ -1771,80 +1771,80 @@ Information Frames: Notification Frame Structures /*-- Notification Frame,MAC Mgmt: Handover Address --*/ typedef struct hfa384x_HandoverAddr { - UINT16 framelen; - UINT16 infotype; - UINT8 handover_addr[WLAN_BSSID_LEN]; + uint16_t framelen; + uint16_t infotype; + uint8_t handover_addr[WLAN_BSSID_LEN]; } __WLAN_ATTRIB_PACK__ hfa384x_HandoverAddr_t; /*-- Inquiry Frame, Diagnose: Communication Tallies --*/ typedef struct hfa384x_CommTallies16 { - UINT16 txunicastframes; - UINT16 txmulticastframes; - UINT16 txfragments; - UINT16 txunicastoctets; - UINT16 txmulticastoctets; - UINT16 txdeferredtrans; - UINT16 txsingleretryframes; - UINT16 txmultipleretryframes; - UINT16 txretrylimitexceeded; - UINT16 txdiscards; - UINT16 rxunicastframes; - UINT16 rxmulticastframes; - UINT16 rxfragments; - UINT16 rxunicastoctets; - UINT16 rxmulticastoctets; - UINT16 rxfcserrors; - UINT16 rxdiscardsnobuffer; - UINT16 txdiscardswrongsa; - UINT16 rxdiscardswepundecr; - UINT16 rxmsginmsgfrag; - UINT16 rxmsginbadmsgfrag; + uint16_t txunicastframes; + uint16_t txmulticastframes; + uint16_t txfragments; + uint16_t txunicastoctets; + uint16_t txmulticastoctets; + uint16_t txdeferredtrans; + uint16_t txsingleretryframes; + uint16_t txmultipleretryframes; + uint16_t txretrylimitexceeded; + uint16_t txdiscards; + uint16_t rxunicastframes; + uint16_t rxmulticastframes; + uint16_t rxfragments; + uint16_t rxunicastoctets; + uint16_t rxmulticastoctets; + uint16_t rxfcserrors; + uint16_t rxdiscardsnobuffer; + uint16_t txdiscardswrongsa; + uint16_t rxdiscardswepundecr; + uint16_t rxmsginmsgfrag; + uint16_t rxmsginbadmsgfrag; } __WLAN_ATTRIB_PACK__ hfa384x_CommTallies16_t; typedef struct hfa384x_CommTallies32 { - UINT32 txunicastframes; - UINT32 txmulticastframes; - UINT32 txfragments; - UINT32 txunicastoctets; - UINT32 txmulticastoctets; - UINT32 txdeferredtrans; - UINT32 txsingleretryframes; - UINT32 txmultipleretryframes; - UINT32 txretrylimitexceeded; - UINT32 txdiscards; - UINT32 rxunicastframes; - UINT32 rxmulticastframes; - UINT32 rxfragments; - UINT32 rxunicastoctets; - UINT32 rxmulticastoctets; - UINT32 rxfcserrors; - UINT32 rxdiscardsnobuffer; - UINT32 txdiscardswrongsa; - UINT32 rxdiscardswepundecr; - UINT32 rxmsginmsgfrag; - UINT32 rxmsginbadmsgfrag; + uint32_t txunicastframes; + uint32_t txmulticastframes; + uint32_t txfragments; + uint32_t txunicastoctets; + uint32_t txmulticastoctets; + uint32_t txdeferredtrans; + uint32_t txsingleretryframes; + uint32_t txmultipleretryframes; + uint32_t txretrylimitexceeded; + uint32_t txdiscards; + uint32_t rxunicastframes; + uint32_t rxmulticastframes; + uint32_t rxfragments; + uint32_t rxunicastoctets; + uint32_t rxmulticastoctets; + uint32_t rxfcserrors; + uint32_t rxdiscardsnobuffer; + uint32_t txdiscardswrongsa; + uint32_t rxdiscardswepundecr; + uint32_t rxmsginmsgfrag; + uint32_t rxmsginbadmsgfrag; } __WLAN_ATTRIB_PACK__ hfa384x_CommTallies32_t; /*-- Inquiry Frame, Diagnose: Scan Results & Subfields--*/ typedef struct hfa384x_ScanResultSub { - UINT16 chid; - UINT16 anl; - UINT16 sl; - UINT8 bssid[WLAN_BSSID_LEN]; - UINT16 bcnint; - UINT16 capinfo; + uint16_t chid; + uint16_t anl; + uint16_t sl; + uint8_t bssid[WLAN_BSSID_LEN]; + uint16_t bcnint; + uint16_t capinfo; hfa384x_bytestr32_t ssid; - UINT8 supprates[10]; /* 802.11 info element */ - UINT16 proberesp_rate; + uint8_t supprates[10]; /* 802.11 info element */ + uint16_t proberesp_rate; } __WLAN_ATTRIB_PACK__ hfa384x_ScanResultSub_t; typedef struct hfa384x_ScanResult { - UINT16 rsvd; - UINT16 scanreason; + uint16_t rsvd; + uint16_t scanreason; hfa384x_ScanResultSub_t result[HFA384x_SCANRESULT_MAX]; } __WLAN_ATTRIB_PACK__ hfa384x_ScanResult_t; @@ -1852,10 +1852,10 @@ typedef struct hfa384x_ScanResult /*-- Inquiry Frame, Diagnose: ChInfo Results & Subfields--*/ typedef struct hfa384x_ChInfoResultSub { - UINT16 chid; - UINT16 anl; - UINT16 pnl; - UINT16 active; + uint16_t chid; + uint16_t anl; + uint16_t pnl; + uint16_t active; } __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResultSub_t; #define HFA384x_CHINFORESULT_BSSACTIVE BIT0 @@ -1863,83 +1863,83 @@ typedef struct hfa384x_ChInfoResultSub typedef struct hfa384x_ChInfoResult { - UINT16 scanchannels; - hfa384x_ChInfoResultSub_t + uint16_t scanchannels; + hfa384x_ChInfoResultSub_t result[HFA384x_CHINFORESULT_MAX]; } __WLAN_ATTRIB_PACK__ hfa384x_ChInfoResult_t; /*-- Inquiry Frame, Diagnose: Host Scan Results & Subfields--*/ typedef struct hfa384x_HScanResultSub { - UINT16 chid; - UINT16 anl; - UINT16 sl; - UINT8 bssid[WLAN_BSSID_LEN]; - UINT16 bcnint; - UINT16 capinfo; + uint16_t chid; + uint16_t anl; + uint16_t sl; + uint8_t bssid[WLAN_BSSID_LEN]; + uint16_t bcnint; + uint16_t capinfo; hfa384x_bytestr32_t ssid; - UINT8 supprates[10]; /* 802.11 info element */ - UINT16 proberesp_rate; - UINT16 atim; + uint8_t supprates[10]; /* 802.11 info element */ + uint16_t proberesp_rate; + uint16_t atim; } __WLAN_ATTRIB_PACK__ hfa384x_HScanResultSub_t; typedef struct hfa384x_HScanResult { - UINT16 nresult; - UINT16 rsvd; + uint16_t nresult; + uint16_t rsvd; hfa384x_HScanResultSub_t result[HFA384x_HSCANRESULT_MAX]; } __WLAN_ATTRIB_PACK__ hfa384x_HScanResult_t; /*-- Unsolicited Frame, MAC Mgmt: LinkStatus --*/ -#define HFA384x_LINK_NOTCONNECTED ((UINT16)0) -#define HFA384x_LINK_CONNECTED ((UINT16)1) -#define HFA384x_LINK_DISCONNECTED ((UINT16)2) -#define HFA384x_LINK_AP_CHANGE ((UINT16)3) -#define HFA384x_LINK_AP_OUTOFRANGE ((UINT16)4) -#define HFA384x_LINK_AP_INRANGE ((UINT16)5) -#define HFA384x_LINK_ASSOCFAIL ((UINT16)6) +#define HFA384x_LINK_NOTCONNECTED ((uint16_t)0) +#define HFA384x_LINK_CONNECTED ((uint16_t)1) +#define HFA384x_LINK_DISCONNECTED ((uint16_t)2) +#define HFA384x_LINK_AP_CHANGE ((uint16_t)3) +#define HFA384x_LINK_AP_OUTOFRANGE ((uint16_t)4) +#define HFA384x_LINK_AP_INRANGE ((uint16_t)5) +#define HFA384x_LINK_ASSOCFAIL ((uint16_t)6) typedef struct hfa384x_LinkStatus { - UINT16 linkstatus; + uint16_t linkstatus; } __WLAN_ATTRIB_PACK__ hfa384x_LinkStatus_t; /*-- Unsolicited Frame, MAC Mgmt: AssociationStatus (--*/ -#define HFA384x_ASSOCSTATUS_STAASSOC ((UINT16)1) -#define HFA384x_ASSOCSTATUS_REASSOC ((UINT16)2) -#define HFA384x_ASSOCSTATUS_DISASSOC ((UINT16)3) -#define HFA384x_ASSOCSTATUS_ASSOCFAIL ((UINT16)4) -#define HFA384x_ASSOCSTATUS_AUTHFAIL ((UINT16)5) +#define HFA384x_ASSOCSTATUS_STAASSOC ((uint16_t)1) +#define HFA384x_ASSOCSTATUS_REASSOC ((uint16_t)2) +#define HFA384x_ASSOCSTATUS_DISASSOC ((uint16_t)3) +#define HFA384x_ASSOCSTATUS_ASSOCFAIL ((uint16_t)4) +#define HFA384x_ASSOCSTATUS_AUTHFAIL ((uint16_t)5) typedef struct hfa384x_AssocStatus { - UINT16 assocstatus; - UINT8 sta_addr[WLAN_ADDR_LEN]; + uint16_t assocstatus; + uint8_t sta_addr[WLAN_ADDR_LEN]; /* old_ap_addr is only valid if assocstatus == 2 */ - UINT8 old_ap_addr[WLAN_ADDR_LEN]; - UINT16 reason; - UINT16 reserved; + uint8_t old_ap_addr[WLAN_ADDR_LEN]; + uint16_t reason; + uint16_t reserved; } __WLAN_ATTRIB_PACK__ hfa384x_AssocStatus_t; /*-- Unsolicited Frame, MAC Mgmt: AuthRequest (AP Only) --*/ typedef struct hfa384x_AuthRequest { - UINT8 sta_addr[WLAN_ADDR_LEN]; - UINT16 algorithm; + uint8_t sta_addr[WLAN_ADDR_LEN]; + uint16_t algorithm; } __WLAN_ATTRIB_PACK__ hfa384x_AuthReq_t; /*-- Unsolicited Frame, MAC Mgmt: AssocRequest (AP Only) --*/ typedef struct hfa384x_AssocRequest { - UINT8 sta_addr[WLAN_ADDR_LEN]; - UINT16 type; - UINT8 wpa_data[80]; + uint8_t sta_addr[WLAN_ADDR_LEN]; + uint16_t type; + uint8_t wpa_data[80]; } __WLAN_ATTRIB_PACK__ hfa384x_AssocReq_t; @@ -1948,23 +1948,23 @@ typedef struct hfa384x_AssocRequest /*-- Unsolicited Frame, MAC Mgmt: MIC Failure (AP Only) --*/ -typedef struct hfa384x_MicFailure +typedef struct hfa384x_MicFailure { - UINT8 sender[WLAN_ADDR_LEN]; - UINT8 dest[WLAN_ADDR_LEN]; + uint8_t sender[WLAN_ADDR_LEN]; + uint8_t dest[WLAN_ADDR_LEN]; } __WLAN_ATTRIB_PACK__ hfa384x_MicFailure_t; /*-- Unsolicited Frame, MAC Mgmt: PSUserCount (AP Only) --*/ typedef struct hfa384x_PSUserCount { - UINT16 usercnt; + uint16_t usercnt; } __WLAN_ATTRIB_PACK__ hfa384x_PSUserCount_t; typedef struct hfa384x_KeyIDChanged { - UINT8 sta_addr[WLAN_ADDR_LEN]; - UINT16 keyid; + uint8_t sta_addr[WLAN_ADDR_LEN]; + uint16_t keyid; } __WLAN_ATTRIB_PACK__ hfa384x_KeyIDChanged_t; /*-- Collection of all Inf frames ---------------*/ @@ -1983,8 +1983,8 @@ typedef union hfa384x_infodata { typedef struct hfa384x_InfFrame { - UINT16 framelen; - UINT16 infotype; + uint16_t framelen; + uint16_t infotype; hfa384x_infodata_t info; } __WLAN_ATTRIB_PACK__ hfa384x_InfFrame_t; @@ -2022,46 +2022,46 @@ USB Packet structures and constants. typedef struct hfa384x_usb_txfrm { hfa384x_tx_frame_t desc; - UINT8 data[WLAN_DATA_MAXLEN]; + uint8_t data[WLAN_DATA_MAXLEN]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_txfrm_t; typedef struct hfa384x_usb_cmdreq { - UINT16 type; - UINT16 cmd; - UINT16 parm0; - UINT16 parm1; - UINT16 parm2; - UINT8 pad[54]; + uint16_t type; + uint16_t cmd; + uint16_t parm0; + uint16_t parm1; + uint16_t parm2; + uint8_t pad[54]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdreq_t; typedef struct hfa384x_usb_wridreq { - UINT16 type; - UINT16 frmlen; - UINT16 rid; - UINT8 data[HFA384x_RIDDATA_MAXLEN]; + uint16_t type; + uint16_t frmlen; + uint16_t rid; + uint8_t data[HFA384x_RIDDATA_MAXLEN]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_wridreq_t; typedef struct hfa384x_usb_rridreq { - UINT16 type; - UINT16 frmlen; - UINT16 rid; - UINT8 pad[58]; + uint16_t type; + uint16_t frmlen; + uint16_t rid; + uint8_t pad[58]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_rridreq_t; typedef struct hfa384x_usb_wmemreq { - UINT16 type; - UINT16 frmlen; - UINT16 offset; - UINT16 page; - UINT8 data[HFA384x_USB_RWMEM_MAXLEN]; + uint16_t type; + uint16_t frmlen; + uint16_t offset; + uint16_t page; + uint8_t data[HFA384x_USB_RWMEM_MAXLEN]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_wmemreq_t; typedef struct hfa384x_usb_rmemreq { - UINT16 type; - UINT16 frmlen; - UINT16 offset; - UINT16 page; - UINT8 pad[56]; + uint16_t type; + uint16_t frmlen; + uint16_t offset; + uint16_t page; + uint8_t pad[56]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemreq_t; /*------------------------------------*/ @@ -2069,54 +2069,54 @@ typedef struct hfa384x_usb_rmemreq { typedef struct hfa384x_usb_rxfrm { hfa384x_rx_frame_t desc; - UINT8 data[WLAN_DATA_MAXLEN]; + uint8_t data[WLAN_DATA_MAXLEN]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_rxfrm_t; typedef struct hfa384x_usb_infofrm { - UINT16 type; + uint16_t type; hfa384x_InfFrame_t info; } __WLAN_ATTRIB_PACK__ hfa384x_usb_infofrm_t; typedef struct hfa384x_usb_statusresp { - UINT16 type; - UINT16 status; - UINT16 resp0; - UINT16 resp1; - UINT16 resp2; + uint16_t type; + uint16_t status; + uint16_t resp0; + uint16_t resp1; + uint16_t resp2; } __WLAN_ATTRIB_PACK__ hfa384x_usb_cmdresp_t; typedef hfa384x_usb_cmdresp_t hfa384x_usb_wridresp_t; typedef struct hfa384x_usb_rridresp { - UINT16 type; - UINT16 frmlen; - UINT16 rid; - UINT8 data[HFA384x_RIDDATA_MAXLEN]; + uint16_t type; + uint16_t frmlen; + uint16_t rid; + uint8_t data[HFA384x_RIDDATA_MAXLEN]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_rridresp_t; typedef hfa384x_usb_cmdresp_t hfa384x_usb_wmemresp_t; typedef struct hfa384x_usb_rmemresp { - UINT16 type; - UINT16 frmlen; - UINT8 data[HFA384x_USB_RWMEM_MAXLEN]; + uint16_t type; + uint16_t frmlen; + uint8_t data[HFA384x_USB_RWMEM_MAXLEN]; } __WLAN_ATTRIB_PACK__ hfa384x_usb_rmemresp_t; typedef struct hfa384x_usb_bufavail { - UINT16 type; - UINT16 frmlen; + uint16_t type; + uint16_t frmlen; } __WLAN_ATTRIB_PACK__ hfa384x_usb_bufavail_t; typedef struct hfa384x_usb_error { - UINT16 type; - UINT16 errortype; + uint16_t type; + uint16_t errortype; } __WLAN_ATTRIB_PACK__ hfa384x_usb_error_t; /*----------------------------------------------------------*/ /* Unions for packaging all the known packet types together */ typedef union hfa384x_usbout { - UINT16 type; + uint16_t type; hfa384x_usb_txfrm_t txfrm; hfa384x_usb_cmdreq_t cmdreq; hfa384x_usb_wridreq_t wridreq; @@ -2126,7 +2126,7 @@ typedef union hfa384x_usbout { } __WLAN_ATTRIB_PACK__ hfa384x_usbout_t; typedef union hfa384x_usbin { - UINT16 type; + uint16_t type; hfa384x_usb_rxfrm_t rxfrm; hfa384x_usb_txfrm_t txfrm; hfa384x_usb_infofrm_t infofrm; @@ -2137,7 +2137,7 @@ typedef union hfa384x_usbin { hfa384x_usb_rmemresp_t rmemresp; hfa384x_usb_bufavail_t bufavail; hfa384x_usb_error_t usberror; - UINT8 boguspad[3000]; + uint8_t boguspad[3000]; } __WLAN_ATTRIB_PACK__ hfa384x_usbin_t; #endif /* WLAN_USB */ @@ -2148,17 +2148,17 @@ PD record structures. typedef struct hfa384x_pdr_pcb_partnum { - UINT8 num[8]; + uint8_t num[8]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_partnum_t; typedef struct hfa384x_pdr_pcb_tracenum { - UINT8 num[8]; + uint8_t num[8]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_pcb_tracenum_t; typedef struct hfa384x_pdr_nic_serial { - UINT8 num[12]; + uint8_t num[12]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_serial_t; typedef struct hfa384x_pdr_mkk_measurements @@ -2182,170 +2182,170 @@ typedef struct hfa384x_pdr_mkk_measurements typedef struct hfa384x_pdr_nic_ramsize { - UINT8 size[12]; /* units of KB */ + uint8_t size[12]; /* units of KB */ } __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_ramsize_t; typedef struct hfa384x_pdr_mfisuprange { - UINT16 id; - UINT16 variant; - UINT16 bottom; - UINT16 top; + uint16_t id; + uint16_t variant; + uint16_t bottom; + uint16_t top; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_mfisuprange_t; typedef struct hfa384x_pdr_cfisuprange { - UINT16 id; - UINT16 variant; - UINT16 bottom; - UINT16 top; + uint16_t id; + uint16_t variant; + uint16_t bottom; + uint16_t top; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_cfisuprange_t; typedef struct hfa384x_pdr_nicid { - UINT16 id; - UINT16 variant; - UINT16 major; - UINT16 minor; + uint16_t id; + uint16_t variant; + uint16_t major; + uint16_t minor; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_nicid_t; typedef struct hfa384x_pdr_refdac_measurements { - UINT16 value[0]; + uint16_t value[0]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_measurements_t; typedef struct hfa384x_pdr_vgdac_measurements { - UINT16 value[0]; + uint16_t value[0]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_measurements_t; typedef struct hfa384x_pdr_level_comp_measurements { - UINT16 value[0]; + uint16_t value[0]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_compc_measurements_t; typedef struct hfa384x_pdr_mac_address { - UINT8 addr[6]; + uint8_t addr[6]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_mac_address_t; typedef struct hfa384x_pdr_mkk_callname { - UINT8 callname[8]; + uint8_t callname[8]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_mkk_callname_t; typedef struct hfa384x_pdr_regdomain { - UINT16 numdomains; - UINT16 domain[5]; + uint16_t numdomains; + uint16_t domain[5]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_regdomain_t; typedef struct hfa384x_pdr_allowed_channel { - UINT16 ch_bitmap; + uint16_t ch_bitmap; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_allowed_channel_t; typedef struct hfa384x_pdr_default_channel { - UINT16 channel; + uint16_t channel; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_default_channel_t; typedef struct hfa384x_pdr_privacy_option { - UINT16 available; + uint16_t available; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_privacy_option_t; typedef struct hfa384x_pdr_temptype { - UINT16 type; + uint16_t type; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_temptype_t; typedef struct hfa384x_pdr_refdac_setup { - UINT16 ch_value[14]; + uint16_t ch_value[14]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_refdac_setup_t; typedef struct hfa384x_pdr_vgdac_setup { - UINT16 ch_value[14]; + uint16_t ch_value[14]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_vgdac_setup_t; typedef struct hfa384x_pdr_level_comp_setup { - UINT16 ch_value[14]; + uint16_t ch_value[14]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_level_comp_setup_t; typedef struct hfa384x_pdr_trimdac_setup { - UINT16 trimidac; - UINT16 trimqdac; + uint16_t trimidac; + uint16_t trimqdac; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_trimdac_setup_t; typedef struct hfa384x_pdr_ifr_setting { - UINT16 value[3]; + uint16_t value[3]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_ifr_setting_t; typedef struct hfa384x_pdr_rfr_setting { - UINT16 value[3]; + uint16_t value[3]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_rfr_setting_t; typedef struct hfa384x_pdr_hfa3861_baseline { - UINT16 value[50]; + uint16_t value[50]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_baseline_t; typedef struct hfa384x_pdr_hfa3861_shadow { - UINT32 value[32]; + uint32_t value[32]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_shadow_t; typedef struct hfa384x_pdr_hfa3861_ifrf { - UINT32 value[20]; + uint32_t value[20]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_ifrf_t; typedef struct hfa384x_pdr_hfa3861_chcalsp { - UINT16 value[14]; + uint16_t value[14]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcalsp_t; typedef struct hfa384x_pdr_hfa3861_chcali { - UINT16 value[17]; + uint16_t value[17]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_chcali_t; typedef struct hfa384x_pdr_hfa3861_nic_config { - UINT16 config_bitmap; + uint16_t config_bitmap; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_nic_config_t; typedef struct hfa384x_pdr_hfo_delay { - UINT8 hfo_delay; + uint8_t hfo_delay; } __WLAN_ATTRIB_PACK__ hfa384x_hfo_delay_t; typedef struct hfa384x_pdr_hfa3861_manf_testsp { - UINT16 value[30]; + uint16_t value[30]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testsp_t; typedef struct hfa384x_pdr_hfa3861_manf_testi { - UINT16 value[30]; + uint16_t value[30]; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_hfa3861_manf_testi_t; typedef struct hfa384x_end_of_pda { - UINT16 crc; + uint16_t crc; } __WLAN_ATTRIB_PACK__ hfa384x_pdr_end_of_pda_t; typedef struct hfa384x_pdrec { - UINT16 len; /* in words */ - UINT16 code; + uint16_t len; /* in words */ + uint16_t code; union pdr { hfa384x_pdr_pcb_partnum_t pcb_partnum; hfa384x_pdr_pcb_tracenum_t pcb_tracenum; @@ -2393,19 +2393,19 @@ typedef struct hfa384x_pdrec --------------------------------------------------------------------*/ typedef struct hfa384x_statusresult { - UINT16 status; - UINT16 resp0; - UINT16 resp1; - UINT16 resp2; + uint16_t status; + uint16_t resp0; + uint16_t resp1; + uint16_t resp2; } hfa384x_cmdresult_t; #if (WLAN_HOSTIF == WLAN_USB) /* USB Control Exchange (CTLX): - * A queue of the structure below is maintained for all of the + * A queue of the structure below is maintained for all of the * Request/Response type USB packets supported by Prism2. */ -/* The following hfa384x_* structures are arguments to +/* The following hfa384x_* structures are arguments to * the usercb() for the different CTLX types. */ typedef hfa384x_cmdresult_t hfa384x_wridresult_t; @@ -2413,9 +2413,9 @@ typedef hfa384x_cmdresult_t hfa384x_wmemresult_t; typedef struct hfa384x_rridresult { - UINT16 rid; + uint16_t rid; const void *riddata; - UINT riddata_len; + unsigned int riddata_len; } hfa384x_rridresult_t; enum ctlx_state { @@ -2437,7 +2437,7 @@ struct hfa384x; typedef void (*ctlx_cmdcb_t)( struct hfa384x*, const struct hfa384x_usbctlx* ); typedef void (*ctlx_usercb_t)( - struct hfa384x *hw, + struct hfa384x *hw, void *ctlxresult, void *usercb_data); @@ -2473,14 +2473,14 @@ typedef struct hfa384x_usbctlxq typedef struct hfa484x_metacmd { - UINT16 cmd; + uint16_t cmd; - UINT16 parm0; - UINT16 parm1; - UINT16 parm2; + uint16_t parm0; + uint16_t parm1; + uint16_t parm2; #if 0 //XXX cmd irq stuff - UINT16 bulkid; /* what RID/FID to copy down. */ + uint16_t bulkid; /* what RID/FID to copy down. */ int bulklen; /* how much to copy from BAP */ char *bulkdata; /* And to where? */ #endif @@ -2509,27 +2509,27 @@ typedef struct hfa484x_metacmd /* XXX These are going away ASAP */ typedef struct prism2sta_authlist { - UINT cnt; - UINT8 addr[WLAN_AUTH_MAX][WLAN_ADDR_LEN]; - UINT8 assoc[WLAN_AUTH_MAX]; + unsigned int cnt; + uint8_t addr[WLAN_AUTH_MAX][WLAN_ADDR_LEN]; + uint8_t assoc[WLAN_AUTH_MAX]; } prism2sta_authlist_t; typedef struct prism2sta_accesslist { - UINT modify; - UINT cnt; - UINT8 addr[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; - UINT cnt1; - UINT8 addr1[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; + unsigned int modify; + unsigned int cnt; + uint8_t addr[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; + unsigned int cnt1; + uint8_t addr1[WLAN_ACCESS_MAX][WLAN_ADDR_LEN]; } prism2sta_accesslist_t; typedef struct hfa384x { #if (WLAN_HOSTIF != WLAN_USB) /* Resource config */ - UINT32 iobase; + uint32_t iobase; char __iomem *membase; - UINT32 irq; + uint32_t irq; #else /* USB support data */ struct usb_device *usb; @@ -2574,25 +2574,25 @@ typedef struct hfa384x #endif int sniff_fcs; - int sniff_channel; - int sniff_truncate; + int sniff_channel; + int sniff_truncate; int sniffhdr; wait_queue_head_t cmdq; /* wait queue itself */ /* Controller state */ - UINT32 state; - UINT32 isap; - UINT8 port_enabled[HFA384x_NUMPORTS_MAX]; + uint32_t state; + uint32_t isap; + uint8_t port_enabled[HFA384x_NUMPORTS_MAX]; #if (WLAN_HOSTIF != WLAN_USB) - UINT auxen; - UINT isram16; + unsigned int auxen; + unsigned int isram16; #endif /* !USB */ /* Download support */ - UINT dlstate; + unsigned int dlstate; hfa384x_downloadbuffer_t bufinfo; - UINT16 dltimeout; + uint16_t dltimeout; #if (WLAN_HOSTIF != WLAN_USB) spinlock_t cmdlock; @@ -2600,15 +2600,15 @@ typedef struct hfa384x hfa384x_metacmd_t *cmddata; /* for our async callback */ /* BAP support */ - spinlock_t baplock; + spinlock_t baplock; struct tasklet_struct bap_tasklet; /* MAC buffer ids */ - UINT16 txfid_head; - UINT16 txfid_tail; - UINT txfid_N; - UINT16 txfid_queue[HFA384x_DRVR_FIDSTACKLEN_MAX]; - UINT16 infofid; + uint16_t txfid_head; + uint16_t txfid_tail; + unsigned int txfid_N; + uint16_t txfid_queue[HFA384x_DRVR_FIDSTACKLEN_MAX]; + uint16_t infofid; struct semaphore infofid_sem; #endif /* !USB */ @@ -2625,31 +2625,31 @@ typedef struct hfa384x hfa384x_commsquality_t qual; struct timer_list commsqual_timer; - UINT16 link_status; - UINT16 link_status_new; + uint16_t link_status; + uint16_t link_status_new; struct sk_buff_head authq; /* And here we have stuff that used to be in priv */ /* State variables */ - UINT presniff_port_type; - UINT16 presniff_wepflags; - UINT32 dot11_desired_bss_type; + unsigned int presniff_port_type; + uint16_t presniff_wepflags; + uint32_t dot11_desired_bss_type; int ap; /* AP flag: 0 - Station, 1 - Access Point. */ int dbmadjust; /* Group Addresses - right now, there are up to a total of MAX_GRP_ADDR group addresses */ - UINT8 dot11_grp_addr[MAX_GRP_ADDR][WLAN_ADDR_LEN]; - UINT dot11_grpcnt; + uint8_t dot11_grp_addr[MAX_GRP_ADDR][WLAN_ADDR_LEN]; + unsigned int dot11_grpcnt; /* Component Identities */ hfa384x_compident_t ident_nic; hfa384x_compident_t ident_pri_fw; hfa384x_compident_t ident_sta_fw; hfa384x_compident_t ident_ap_fw; - UINT16 mm_mods; + uint16_t mm_mods; /* Supplier compatibility ranges */ hfa384x_caplevel_t cap_sup_mfi; @@ -2665,14 +2665,14 @@ typedef struct hfa384x hfa384x_caplevel_t cap_act_ap_cfi; /* ap f/w to controller interface */ hfa384x_caplevel_t cap_act_ap_mfi; /* ap f/w to modem interface */ - UINT32 psusercount; /* Power save user count. */ + uint32_t psusercount; /* Power save user count. */ hfa384x_CommTallies32_t tallies; /* Communication tallies. */ - UINT8 comment[WLAN_COMMENT_MAX+1]; /* User comment */ + uint8_t comment[WLAN_COMMENT_MAX+1]; /* User comment */ /* Channel Info request results (AP only) */ struct { atomic_t done; - UINT8 count; + uint8_t count; hfa384x_ChInfoResult_t results; } channel_info; @@ -2680,7 +2680,7 @@ typedef struct hfa384x prism2sta_authlist_t authlist; /* Authenticated station list. */ - UINT accessmode; /* Access mode. */ + unsigned int accessmode; /* Access mode. */ prism2sta_accesslist_t allow; /* Allowed station list. */ prism2sta_accesslist_t deny; /* Denied station list. */ @@ -2690,23 +2690,23 @@ typedef struct hfa384x /*--- Function Declarations -----------------------------------*/ /*=============================================================*/ #if (WLAN_HOSTIF == WLAN_USB) -void -hfa384x_create( - hfa384x_t *hw, +void +hfa384x_create( + hfa384x_t *hw, struct usb_device *usb); #else -void -hfa384x_create( - hfa384x_t *hw, - UINT irq, - UINT32 iobase, - UINT8 __iomem *membase); +void +hfa384x_create( + hfa384x_t *hw, + unsigned int irq, + uint32_t iobase, + uint8_t __iomem *membase); #endif void hfa384x_destroy(hfa384x_t *hw); irqreturn_t -hfa384x_interrupt(int irq, void *dev_id PT_REGS); +hfa384x_INTerrupt(int irq, void *dev_id PT_REGS); int hfa384x_corereset( hfa384x_t *hw, int holdtime, int settletime, int genesis); int @@ -2714,97 +2714,97 @@ hfa384x_drvr_chinforesults( hfa384x_t *hw); int hfa384x_drvr_commtallies( hfa384x_t *hw); int -hfa384x_drvr_disable(hfa384x_t *hw, UINT16 macport); +hfa384x_drvr_disable(hfa384x_t *hw, uint16_t macport); int -hfa384x_drvr_enable(hfa384x_t *hw, UINT16 macport); +hfa384x_drvr_enable(hfa384x_t *hw, uint16_t macport); int hfa384x_drvr_flashdl_enable(hfa384x_t *hw); int hfa384x_drvr_flashdl_disable(hfa384x_t *hw); int -hfa384x_drvr_flashdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len); +hfa384x_drvr_flashdl_write(hfa384x_t *hw, uint32_t daddr, void* buf, uint32_t len); int -hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len); +hfa384x_drvr_getconfig(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len); int -hfa384x_drvr_handover( hfa384x_t *hw, UINT8 *addr); +hfa384x_drvr_handover( hfa384x_t *hw, uint8_t *addr); int hfa384x_drvr_hostscanresults( hfa384x_t *hw); int hfa384x_drvr_low_level(hfa384x_t *hw, hfa384x_metacmd_t *cmd); int -hfa384x_drvr_mmi_read(hfa384x_t *hw, UINT32 address, UINT32 *result); +hfa384x_drvr_mmi_read(hfa384x_t *hw, uint32_t address, uint32_t *result); int -hfa384x_drvr_mmi_write(hfa384x_t *hw, UINT32 address, UINT32 data); +hfa384x_drvr_mmi_write(hfa384x_t *hw, uint32_t address, uint32_t data); int -hfa384x_drvr_ramdl_enable(hfa384x_t *hw, UINT32 exeaddr); +hfa384x_drvr_ramdl_enable(hfa384x_t *hw, uint32_t exeaddr); int hfa384x_drvr_ramdl_disable(hfa384x_t *hw); int -hfa384x_drvr_ramdl_write(hfa384x_t *hw, UINT32 daddr, void* buf, UINT32 len); +hfa384x_drvr_ramdl_write(hfa384x_t *hw, uint32_t daddr, void* buf, uint32_t len); int -hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, UINT len); +hfa384x_drvr_readpda(hfa384x_t *hw, void *buf, unsigned int len); int hfa384x_drvr_scanresults( hfa384x_t *hw); int -hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len); +hfa384x_drvr_setconfig(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len); -static inline int -hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val) +static inline int +hfa384x_drvr_getconfig16(hfa384x_t *hw, uint16_t rid, void *val) { int result = 0; - result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16)); + result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(uint16_t)); if ( result == 0 ) { - *((UINT16*)val) = hfa384x2host_16(*((UINT16*)val)); + *((uint16_t*)val) = hfa384x2host_16(*((uint16_t*)val)); } return result; } -static inline int -hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val) +static inline int +hfa384x_drvr_getconfig32(hfa384x_t *hw, uint16_t rid, void *val) { int result = 0; - result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32)); + result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(uint32_t)); if ( result == 0 ) { - *((UINT32*)val) = hfa384x2host_32(*((UINT32*)val)); + *((uint32_t*)val) = hfa384x2host_32(*((uint32_t*)val)); } return result; } static inline int -hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 val) +hfa384x_drvr_setconfig16(hfa384x_t *hw, uint16_t rid, uint16_t val) { - UINT16 value = host2hfa384x_16(val); + uint16_t value = host2hfa384x_16(val); return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); } static inline int -hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 val) +hfa384x_drvr_setconfig32(hfa384x_t *hw, uint16_t rid, uint32_t val) { - UINT32 value = host2hfa384x_32(val); + uint32_t value = host2hfa384x_32(val); return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value)); } -#if (WLAN_HOSTIF == WLAN_USB) -int -hfa384x_drvr_getconfig_async(hfa384x_t *hw, - UINT16 rid, - ctlx_usercb_t usercb, - void *usercb_data); - -int -hfa384x_drvr_setconfig_async(hfa384x_t *hw, - UINT16 rid, - void *buf, - UINT16 len, - ctlx_usercb_t usercb, - void *usercb_data); +#if (WLAN_HOSTIF == WLAN_USB) +int +hfa384x_drvr_getconfig_async(hfa384x_t *hw, + uint16_t rid, + ctlx_usercb_t usercb, + void *usercb_data); + +int +hfa384x_drvr_setconfig_async(hfa384x_t *hw, + uint16_t rid, + void *buf, + uint16_t len, + ctlx_usercb_t usercb, + void *usercb_data); #else static inline int -hfa384x_drvr_setconfig_async(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len, - void *ptr1, void *ptr2) +hfa384x_drvr_setconfig_async(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len, + void *ptr1, void *ptr2) { (void)ptr1; (void)ptr2; @@ -2813,19 +2813,19 @@ hfa384x_drvr_setconfig_async(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len, #endif static inline int -hfa384x_drvr_setconfig16_async(hfa384x_t *hw, UINT16 rid, UINT16 val) -{ - UINT16 value = host2hfa384x_16(val); - return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), - NULL , NULL); +hfa384x_drvr_setconfig16_async(hfa384x_t *hw, uint16_t rid, uint16_t val) +{ + uint16_t value = host2hfa384x_16(val); + return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), + NULL , NULL); } static inline int -hfa384x_drvr_setconfig32_async(hfa384x_t *hw, UINT16 rid, UINT32 val) -{ - UINT32 value = host2hfa384x_32(val); - return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), - NULL , NULL); +hfa384x_drvr_setconfig32_async(hfa384x_t *hw, uint16_t rid, uint32_t val) +{ + uint32_t value = host2hfa384x_32(val); + return hfa384x_drvr_setconfig_async(hw, rid, &value, sizeof(value), + NULL , NULL); } @@ -2841,87 +2841,87 @@ hfa384x_tx_timeout(wlandevice_t *wlandev); int hfa384x_cmd_initialize(hfa384x_t *hw); int -hfa384x_cmd_enable(hfa384x_t *hw, UINT16 macport); +hfa384x_cmd_enable(hfa384x_t *hw, uint16_t macport); int -hfa384x_cmd_disable(hfa384x_t *hw, UINT16 macport); +hfa384x_cmd_disable(hfa384x_t *hw, uint16_t macport); int hfa384x_cmd_diagnose(hfa384x_t *hw); int -hfa384x_cmd_allocate(hfa384x_t *hw, UINT16 len); +hfa384x_cmd_allocate(hfa384x_t *hw, uint16_t len); int -hfa384x_cmd_transmit(hfa384x_t *hw, UINT16 reclaim, UINT16 qos, UINT16 fid); +hfa384x_cmd_transmit(hfa384x_t *hw, uint16_t reclaim, uint16_t qos, uint16_t fid); int -hfa384x_cmd_clearpersist(hfa384x_t *hw, UINT16 fid); +hfa384x_cmd_clearpersist(hfa384x_t *hw, uint16_t fid); int -hfa384x_cmd_notify(hfa384x_t *hw, UINT16 reclaim, UINT16 fid, void *buf, UINT16 len); +hfa384x_cmd_notify(hfa384x_t *hw, uint16_t reclaim, uint16_t fid, void *buf, uint16_t len); int -hfa384x_cmd_inquire(hfa384x_t *hw, UINT16 fid); +hfa384x_cmd_inquire(hfa384x_t *hw, uint16_t fid); int -hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid, void *buf, UINT16 len); +hfa384x_cmd_access(hfa384x_t *hw, uint16_t write, uint16_t rid, void *buf, uint16_t len); int -hfa384x_cmd_monitor(hfa384x_t *hw, UINT16 enable); +hfa384x_cmd_monitor(hfa384x_t *hw, uint16_t enable); int hfa384x_cmd_download( - hfa384x_t *hw, - UINT16 mode, - UINT16 lowaddr, - UINT16 highaddr, - UINT16 codelen); + hfa384x_t *hw, + uint16_t mode, + uint16_t lowaddr, + uint16_t highaddr, + uint16_t codelen); int hfa384x_cmd_aux_enable(hfa384x_t *hw, int force); int hfa384x_cmd_aux_disable(hfa384x_t *hw); int hfa384x_copy_from_bap( - hfa384x_t *hw, - UINT16 bap, - UINT16 id, - UINT16 offset, + hfa384x_t *hw, + uint16_t bap, + uint16_t id, + uint16_t offset, void *buf, - UINT len); + unsigned int len); int hfa384x_copy_to_bap( - hfa384x_t *hw, - UINT16 bap, - UINT16 id, - UINT16 offset, - void *buf, - UINT len); -void + hfa384x_t *hw, + uint16_t bap, + uint16_t id, + uint16_t offset, + void *buf, + unsigned int len); +void hfa384x_copy_from_aux( - hfa384x_t *hw, - UINT32 cardaddr, - UINT32 auxctl, - void *buf, - UINT len); -void + hfa384x_t *hw, + uint32_t cardaddr, + uint32_t auxctl, + void *buf, + unsigned int len); +void hfa384x_copy_to_aux( - hfa384x_t *hw, - UINT32 cardaddr, - UINT32 auxctl, - void *buf, - UINT len); + hfa384x_t *hw, + uint32_t cardaddr, + uint32_t auxctl, + void *buf, + unsigned int len); #if (WLAN_HOSTIF != WLAN_USB) -/* +/* HFA384x is a LITTLE ENDIAN part. the get/setreg functions implicitly byte-swap the data to LE. the _noswap variants do not perform a byte-swap on the data. */ -static inline UINT16 -__hfa384x_getreg(hfa384x_t *hw, UINT reg); +static inline uint16_t +__hfa384x_getreg(hfa384x_t *hw, unsigned int reg); -static inline void -__hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg); +static inline void +__hfa384x_setreg(hfa384x_t *hw, uint16_t val, unsigned int reg); -static inline UINT16 -__hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg); +static inline uint16_t +__hfa384x_getreg_noswap(hfa384x_t *hw, unsigned int reg); static inline void -__hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg); +__hfa384x_setreg_noswap(hfa384x_t *hw, uint16_t val, unsigned int reg); #ifdef REVERSE_ENDIAN #define hfa384x_getreg __hfa384x_getreg_noswap @@ -2949,8 +2949,8 @@ __hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg); * Returns: * Value from the register in HOST ORDER!!!! ----------------------------------------------------------------*/ -static inline UINT16 -__hfa384x_getreg(hfa384x_t *hw, UINT reg) +static inline uint16_t +__hfa384x_getreg(hfa384x_t *hw, unsigned int reg) { /* printk(KERN_DEBUG "Reading from 0x%0x\n", hw->membase + reg); */ #if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) @@ -2976,7 +2976,7 @@ __hfa384x_getreg(hfa384x_t *hw, UINT reg) * Nothing ----------------------------------------------------------------*/ static inline void -__hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg) +__hfa384x_setreg(hfa384x_t *hw, uint16_t val, unsigned int reg) { #if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) wlan_outw_cpu_to_le16( val, hw->iobase + reg); @@ -3001,8 +3001,8 @@ __hfa384x_setreg(hfa384x_t *hw, UINT16 val, UINT reg) * Returns: * Value from the register. ----------------------------------------------------------------*/ -static inline UINT16 -__hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg) +static inline uint16_t +__hfa384x_getreg_noswap(hfa384x_t *hw, unsigned int reg) { #if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) return wlan_inw(hw->iobase+reg); @@ -3026,8 +3026,8 @@ __hfa384x_getreg_noswap(hfa384x_t *hw, UINT reg) * Returns: * Nothing ----------------------------------------------------------------*/ -static inline void -__hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg) +static inline void +__hfa384x_setreg_noswap(hfa384x_t *hw, uint16_t val, unsigned int reg) { #if ((WLAN_HOSTIF == WLAN_PCMCIA) || (WLAN_HOSTIF == WLAN_PLX)) wlan_outw( val, hw->iobase + reg); @@ -3041,25 +3041,25 @@ __hfa384x_setreg_noswap(hfa384x_t *hw, UINT16 val, UINT reg) static inline void hfa384x_events_all(hfa384x_t *hw) { - hfa384x_setreg(hw, + hfa384x_setreg(hw, HFA384x_INT_NORMAL #ifdef CMD_IRQ | HFA384x_INTEN_CMD_SET(1) #endif , - HFA384x_INTEN); + HFA384x_INTEN); } static inline void hfa384x_events_nobap(hfa384x_t *hw) { - hfa384x_setreg(hw, + hfa384x_setreg(hw, (HFA384x_INT_NORMAL & ~HFA384x_INT_BAP_OP) #ifdef CMD_IRQ | HFA384x_INTEN_CMD_SET(1) #endif , - HFA384x_INTEN); + HFA384x_INTEN); } diff --git a/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h b/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h index 259b9ec3a..8ac179de0 100644 --- a/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h +++ b/roms/ipxe/src/drivers/net/igbvf/igbvf_osdep.h @@ -56,9 +56,6 @@ typedef enum { true = 1 } boolean_t; -#define TRUE 1 -#define FALSE 0 - #define usec_delay(x) udelay(x) #define msec_delay(x) mdelay(x) #define msec_delay_irq(x) mdelay(x) diff --git a/roms/ipxe/src/drivers/net/intel.c b/roms/ipxe/src/drivers/net/intel.c index ce17e9f2d..6684bdbd9 100644 --- a/roms/ipxe/src/drivers/net/intel.c +++ b/roms/ipxe/src/drivers/net/intel.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/iobuf.h> #include <ipxe/malloc.h> #include <ipxe/pci.h> +#include <ipxe/profile.h> #include "intel.h" /** @file @@ -38,6 +39,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** VM transmit profiler */ +static struct profiler intel_vm_tx_profiler __profiler = + { .name = "intel.vm_tx" }; + +/** VM receive refill profiler */ +static struct profiler intel_vm_refill_profiler __profiler = + { .name = "intel.vm_refill" }; + +/** VM poll profiler */ +static struct profiler intel_vm_poll_profiler __profiler = + { .name = "intel.vm_poll" }; + /****************************************************************************** * * EEPROM interface @@ -247,11 +260,16 @@ static int intel_fetch_mac ( struct intel_nic *intel, uint8_t *hw_addr ) { */ static void __attribute__ (( unused )) intel_diag ( struct intel_nic *intel ) { - DBGC ( intel, "INTEL %p TDH=%04x TDT=%04x RDH=%04x RDT=%04x\n", intel, - readl ( intel->regs + INTEL_TDH ), - readl ( intel->regs + INTEL_TDT ), - readl ( intel->regs + INTEL_RDH ), - readl ( intel->regs + INTEL_RDT ) ); + DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) " + "RX %04x(%02x)/%04x(%02x)\n", intel, + ( intel->tx.cons & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDH ), + ( intel->tx.prod & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDT ), + ( intel->rx.cons & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDH ), + ( intel->rx.prod & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDT ) ); } /****************************************************************************** @@ -360,8 +378,7 @@ static void intel_check_link ( struct net_device *netdev ) { * @v ring Descriptor ring * @ret rc Return status code */ -static int intel_create_ring ( struct intel_nic *intel, - struct intel_ring *ring ) { +int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { physaddr_t address; uint32_t dctl; @@ -412,8 +429,7 @@ static int intel_create_ring ( struct intel_nic *intel, * @v intel Intel device * @v ring Descriptor ring */ -static void intel_destroy_ring ( struct intel_nic *intel, - struct intel_ring *ring ) { +void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { /* Clear ring length */ writel ( 0, ( intel->regs + ring->reg + INTEL_xDLEN ) ); @@ -434,25 +450,26 @@ static void intel_destroy_ring ( struct intel_nic *intel, * * @v intel Intel device */ -static void intel_refill_rx ( struct intel_nic *intel ) { +void intel_refill_rx ( struct intel_nic *intel ) { struct intel_descriptor *rx; struct io_buffer *iobuf; unsigned int rx_idx; unsigned int rx_tail; physaddr_t address; + unsigned int refilled = 0; + /* Refill ring */ while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) { /* Allocate I/O buffer */ iobuf = alloc_iob ( INTEL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ - return; + break; } /* Get next receive descriptor */ rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC ); - rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); rx = &intel->rx.desc[rx_idx]; /* Populate receive descriptor */ @@ -461,18 +478,39 @@ static void intel_refill_rx ( struct intel_nic *intel ) { rx->length = 0; rx->status = 0; rx->errors = 0; - wmb(); /* Record I/O buffer */ assert ( intel->rx_iobuf[rx_idx] == NULL ); intel->rx_iobuf[rx_idx] = iobuf; - /* Push descriptor to card */ - writel ( rx_tail, intel->regs + INTEL_RDT ); - DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx, ( ( unsigned long long ) address ), ( ( unsigned long long ) address + INTEL_RX_MAX_LEN ) ); + refilled++; + } + + /* Push descriptors to card, if applicable */ + if ( refilled ) { + wmb(); + rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); + profile_start ( &intel_vm_refill_profiler ); + writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT ); + profile_stop ( &intel_vm_refill_profiler ); + } +} + +/** + * Discard unused receive I/O buffers + * + * @v intel Intel device + */ +void intel_empty_rx ( struct intel_nic *intel ) { + unsigned int i; + + for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { + if ( intel->rx_iobuf[i] ) + free_iob ( intel->rx_iobuf[i] ); + intel->rx_iobuf[i] = NULL; } } @@ -540,7 +578,6 @@ static int intel_open ( struct net_device *netdev ) { */ static void intel_close ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; - unsigned int i; /* Disable receiver */ writel ( 0, intel->regs + INTEL_RCTL ); @@ -552,11 +589,7 @@ static void intel_close ( struct net_device *netdev ) { intel_destroy_ring ( intel, &intel->rx ); /* Discard any unused receive buffers */ - for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { - if ( intel->rx_iobuf[i] ) - free_iob ( intel->rx_iobuf[i] ); - intel->rx_iobuf[i] = NULL; - } + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ intel_destroy_ring ( intel, &intel->tx ); @@ -572,8 +605,7 @@ static void intel_close ( struct net_device *netdev ) { * @v iobuf I/O buffer * @ret rc Return status code */ -static int intel_transmit ( struct net_device *netdev, - struct io_buffer *iobuf ) { +int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *tx; unsigned int tx_idx; @@ -581,7 +613,7 @@ static int intel_transmit ( struct net_device *netdev, physaddr_t address; /* Get next transmit descriptor */ - if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_NUM_TX_DESC ) { + if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) { DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel ); return -ENOBUFS; } @@ -599,7 +631,9 @@ static int intel_transmit ( struct net_device *netdev, wmb(); /* Notify card that there are packets ready to transmit */ - writel ( tx_tail, intel->regs + INTEL_TDT ); + profile_start ( &intel_vm_tx_profiler ); + writel ( tx_tail, intel->regs + intel->tx.reg + INTEL_xDT ); + profile_stop ( &intel_vm_tx_profiler ); DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx, ( ( unsigned long long ) address ), @@ -613,7 +647,7 @@ static int intel_transmit ( struct net_device *netdev, * * @v netdev Network device */ -static void intel_poll_tx ( struct net_device *netdev ) { +void intel_poll_tx ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *tx; unsigned int tx_idx; @@ -642,7 +676,7 @@ static void intel_poll_tx ( struct net_device *netdev ) { * * @v netdev Network device */ -static void intel_poll_rx ( struct net_device *netdev ) { +void intel_poll_rx ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *rx; struct io_buffer *iobuf; @@ -691,7 +725,9 @@ static void intel_poll ( struct net_device *netdev ) { uint32_t icr; /* Check for and acknowledge interrupts */ + profile_start ( &intel_vm_poll_profiler ); icr = readl ( intel->regs + INTEL_ICR ); + profile_stop ( &intel_vm_poll_profiler ); if ( ! icr ) return; @@ -946,6 +982,7 @@ static struct pci_device_id intel_nics[] = { PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ), PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ), PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ), + PCI_ROM ( 0x8086, 0x153b, "i217", "I217", 0 ), PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ), PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ), }; diff --git a/roms/ipxe/src/drivers/net/intel.h b/roms/ipxe/src/drivers/net/intel.h index e9e9052b8..8ce9ea973 100644 --- a/roms/ipxe/src/drivers/net/intel.h +++ b/roms/ipxe/src/drivers/net/intel.h @@ -156,6 +156,9 @@ enum intel_descriptor_status { */ #define INTEL_NUM_TX_DESC 16 +/** Transmit descriptor ring maximum fill level */ +#define INTEL_TX_FILL ( INTEL_NUM_TX_DESC - 1 ) + /** Receive/Transmit Descriptor Base Address Low (offset) */ #define INTEL_xDBAL 0x00 @@ -175,18 +178,6 @@ enum intel_descriptor_status { #define INTEL_xDCTL 0x28 #define INTEL_xDCTL_ENABLE 0x02000000UL /**< Queue enable */ -/** Receive Descriptor Head */ -#define INTEL_RDH ( INTEL_RD + INTEL_xDH ) - -/** Receive Descriptor Tail */ -#define INTEL_RDT ( INTEL_RD + INTEL_xDT ) - -/** Transmit Descriptor Head */ -#define INTEL_TDH ( INTEL_TD + INTEL_xDH ) - -/** Transmit Descriptor Tail */ -#define INTEL_TDT ( INTEL_TD + INTEL_xDT ) - /** Receive Address Low */ #define INTEL_RAL0 0x05400UL @@ -254,4 +245,15 @@ struct intel_nic { struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; }; +extern int intel_create_ring ( struct intel_nic *intel, + struct intel_ring *ring ); +extern void intel_destroy_ring ( struct intel_nic *intel, + struct intel_ring *ring ); +extern void intel_refill_rx ( struct intel_nic *intel ); +extern void intel_empty_rx ( struct intel_nic *intel ); +extern int intel_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ); +extern void intel_poll_tx ( struct net_device *netdev ); +extern void intel_poll_rx ( struct net_device *netdev ); + #endif /* _INTEL_H */ diff --git a/roms/ipxe/src/drivers/net/intelx.c b/roms/ipxe/src/drivers/net/intelx.c new file mode 100644 index 000000000..eb8b2a640 --- /dev/null +++ b/roms/ipxe/src/drivers/net/intelx.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> +#include <ipxe/iobuf.h> +#include <ipxe/malloc.h> +#include <ipxe/pci.h> +#include "intelx.h" + +/** @file + * + * Intel 10 Gigabit Ethernet network card driver + * + */ + +/****************************************************************************** + * + * MAC address + * + ****************************************************************************** + */ + +/** + * Try to fetch initial MAC address + * + * @v intel Intel device + * @v ral0 RAL0 register address + * @v hw_addr Hardware address to fill in + * @ret rc Return status code + */ +static int intelx_try_fetch_mac ( struct intel_nic *intel, unsigned int ral0, + uint8_t *hw_addr ) { + union intel_receive_address mac; + + /* Read current address from RAL0/RAH0 */ + mac.reg.low = cpu_to_le32 ( readl ( intel->regs + ral0 ) ); + mac.reg.high = cpu_to_le32 ( readl ( intel->regs + ral0 + + ( INTELX_RAH0 - INTELX_RAL0 ) ) ); + + /* Use current address if valid */ + if ( is_valid_ether_addr ( mac.raw ) ) { + DBGC ( intel, "INTEL %p has autoloaded MAC address %s at " + "%#05x\n", intel, eth_ntoa ( mac.raw ), ral0 ); + memcpy ( hw_addr, mac.raw, ETH_ALEN ); + return 0; + } + + return -ENOENT; +} + +/** + * Fetch initial MAC address + * + * @v intel Intel device + * @v hw_addr Hardware address to fill in + * @ret rc Return status code + */ +static int intelx_fetch_mac ( struct intel_nic *intel, uint8_t *hw_addr ) { + int rc; + + /* Try to fetch address from INTELX_RAL0 */ + if ( ( rc = intelx_try_fetch_mac ( intel, INTELX_RAL0, + hw_addr ) ) == 0 ) { + return 0; + } + + /* Try to fetch address from INTELX_RAL0_ALT */ + if ( ( rc = intelx_try_fetch_mac ( intel, INTELX_RAL0_ALT, + hw_addr ) ) == 0 ) { + return 0; + } + + DBGC ( intel, "INTEL %p has no MAC address to use\n", intel ); + return -ENOENT; +} + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset hardware + * + * @v intel Intel device + * @ret rc Return status code + */ +static int intelx_reset ( struct intel_nic *intel ) { + uint32_t ctrl; + + /* Perform a global software reset */ + ctrl = readl ( intel->regs + INTELX_CTRL ); + writel ( ( ctrl | INTELX_CTRL_RST | INTELX_CTRL_LRST ), + intel->regs + INTELX_CTRL ); + mdelay ( INTELX_RESET_DELAY_MS ); + + DBGC ( intel, "INTEL %p reset (ctrl %08x)\n", intel, ctrl ); + return 0; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void intelx_check_link ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + uint32_t links; + + /* Read link status */ + links = readl ( intel->regs + INTELX_LINKS ); + DBGC ( intel, "INTEL %p link status is %08x\n", intel, links ); + + /* Update network device */ + if ( links & INTELX_LINKS_UP ) { + netdev_link_up ( netdev ); + } else { + netdev_link_down ( netdev ); + } +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int intelx_open ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + union intel_receive_address mac; + uint32_t ral0; + uint32_t rah0; + uint32_t dmatxctl; + uint32_t fctrl; + uint32_t srrctl; + uint32_t hlreg0; + uint32_t maxfrs; + uint32_t rdrxctl; + uint32_t rxctrl; + uint32_t dca_rxctrl; + int rc; + + /* Create transmit descriptor ring */ + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) + goto err_create_tx; + + /* Create receive descriptor ring */ + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) + goto err_create_rx; + + /* Program MAC address */ + memset ( &mac, 0, sizeof ( mac ) ); + memcpy ( mac.raw, netdev->ll_addr, sizeof ( mac.raw ) ); + ral0 = le32_to_cpu ( mac.reg.low ); + rah0 = ( le32_to_cpu ( mac.reg.high ) | INTELX_RAH0_AV ); + writel ( ral0, intel->regs + INTELX_RAL0 ); + writel ( rah0, intel->regs + INTELX_RAH0 ); + writel ( ral0, intel->regs + INTELX_RAL0_ALT ); + writel ( rah0, intel->regs + INTELX_RAH0_ALT ); + + /* Allocate interrupt vectors */ + writel ( ( INTELX_IVAR_RX0_DEFAULT | INTELX_IVAR_RX0_VALID | + INTELX_IVAR_TX0_DEFAULT | INTELX_IVAR_TX0_VALID ), + intel->regs + INTELX_IVAR ); + + /* Enable transmitter */ + dmatxctl = readl ( intel->regs + INTELX_DMATXCTL ); + dmatxctl |= INTELX_DMATXCTL_TE; + writel ( dmatxctl, intel->regs + INTELX_DMATXCTL ); + + /* Configure receive filter */ + fctrl = readl ( intel->regs + INTELX_FCTRL ); + fctrl |= ( INTELX_FCTRL_BAM | INTELX_FCTRL_UPE | INTELX_FCTRL_MPE ); + writel ( fctrl, intel->regs + INTELX_FCTRL ); + + /* Configure receive buffer sizes */ + srrctl = readl ( intel->regs + INTELX_SRRCTL ); + srrctl &= ~INTELX_SRRCTL_BSIZE_MASK; + srrctl |= INTELX_SRRCTL_BSIZE_DEFAULT; + writel ( srrctl, intel->regs + INTELX_SRRCTL ); + + /* Configure jumbo frames. Required to allow the extra 4-byte + * headroom for VLANs, since we don't use the hardware's + * native VLAN offload. + */ + hlreg0 = readl ( intel->regs + INTELX_HLREG0 ); + hlreg0 |= INTELX_HLREG0_JUMBOEN; + writel ( hlreg0, intel->regs + INTELX_HLREG0 ); + + /* Configure frame size */ + maxfrs = readl ( intel->regs + INTELX_MAXFRS ); + maxfrs &= ~INTELX_MAXFRS_MFS_MASK; + maxfrs |= INTELX_MAXFRS_MFS_DEFAULT; + writel ( maxfrs, intel->regs + INTELX_MAXFRS ); + + /* Configure receive DMA */ + rdrxctl = readl ( intel->regs + INTELX_RDRXCTL ); + rdrxctl |= INTELX_RDRXCTL_SECRC; + writel ( rdrxctl, intel->regs + INTELX_RDRXCTL ); + + /* Clear "must-be-zero" bit for direct cache access (DCA). We + * leave DCA disabled anyway, but if we do not clear this bit + * then the received packets contain garbage data. + */ + dca_rxctrl = readl ( intel->regs + INTELX_DCA_RXCTRL ); + dca_rxctrl &= ~INTELX_DCA_RXCTRL_MUST_BE_ZERO; + writel ( dca_rxctrl, intel->regs + INTELX_DCA_RXCTRL ); + + /* Enable receiver */ + rxctrl = readl ( intel->regs + INTELX_RXCTRL ); + rxctrl |= INTELX_RXCTRL_RXEN; + writel ( rxctrl, intel->regs + INTELX_RXCTRL ); + + /* Fill receive ring */ + intel_refill_rx ( intel ); + + /* Update link state */ + intelx_check_link ( netdev ); + + return 0; + + intel_destroy_ring ( intel, &intel->rx ); + err_create_rx: + intel_destroy_ring ( intel, &intel->tx ); + err_create_tx: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void intelx_close ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + uint32_t rxctrl; + uint32_t dmatxctl; + + /* Disable receiver */ + rxctrl = readl ( intel->regs + INTELX_RXCTRL ); + rxctrl &= ~INTELX_RXCTRL_RXEN; + writel ( rxctrl, intel->regs + INTELX_RXCTRL ); + + /* Disable transmitter */ + dmatxctl = readl ( intel->regs + INTELX_DMATXCTL ); + dmatxctl &= ~INTELX_DMATXCTL_TE; + writel ( dmatxctl, intel->regs + INTELX_DMATXCTL ); + + /* Destroy receive descriptor ring */ + intel_destroy_ring ( intel, &intel->rx ); + + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); + + /* Destroy transmit descriptor ring */ + intel_destroy_ring ( intel, &intel->tx ); + + /* Reset the NIC, to flush the transmit and receive FIFOs */ + intelx_reset ( intel ); +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void intelx_poll ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + uint32_t eicr; + + /* Check for and acknowledge interrupts */ + eicr = readl ( intel->regs + INTELX_EICR ); + if ( ! eicr ) + return; + + /* Poll for TX completions, if applicable */ + if ( eicr & INTELX_EIRQ_TX0 ) + intel_poll_tx ( netdev ); + + /* Poll for RX completions, if applicable */ + if ( eicr & ( INTELX_EIRQ_RX0 | INTELX_EIRQ_RXO ) ) + intel_poll_rx ( netdev ); + + /* Report receive overruns */ + if ( eicr & INTELX_EIRQ_RXO ) + netdev_rx_err ( netdev, NULL, -ENOBUFS ); + + /* Check link state, if applicable */ + if ( eicr & INTELX_EIRQ_LSC ) + intelx_check_link ( netdev ); + + /* Refill RX ring */ + intel_refill_rx ( intel ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void intelx_irq ( struct net_device *netdev, int enable ) { + struct intel_nic *intel = netdev->priv; + uint32_t mask; + + mask = ( INTELX_EIRQ_LSC | INTELX_EIRQ_RXO | INTELX_EIRQ_TX0 | + INTELX_EIRQ_RX0 ); + if ( enable ) { + writel ( mask, intel->regs + INTELX_EIMS ); + } else { + writel ( mask, intel->regs + INTELX_EIMC ); + } +} + +/** Network device operations */ +static struct net_device_operations intelx_operations = { + .open = intelx_open, + .close = intelx_close, + .transmit = intel_transmit, + .poll = intelx_poll, + .irq = intelx_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int intelx_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct intel_nic *intel; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *intel ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &intelx_operations ); + intel = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( intel, 0, sizeof ( *intel ) ); + intel->port = PCI_FUNC ( pci->busdevfn ); + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD ); + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE ); + + /* Reset the NIC */ + if ( ( rc = intelx_reset ( intel ) ) != 0 ) + goto err_reset; + + /* Fetch MAC address */ + if ( ( rc = intelx_fetch_mac ( intel, netdev->hw_addr ) ) != 0 ) + goto err_fetch_mac; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + intelx_check_link ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register_netdev: + err_fetch_mac: + intelx_reset ( intel ); + err_reset: + iounmap ( intel->regs ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void intelx_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct intel_nic *intel = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset the NIC */ + intelx_reset ( intel ); + + /* Free network device */ + iounmap ( intel->regs ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** PCI device IDs */ +static struct pci_device_id intelx_nics[] = { + PCI_ROM ( 0x8086, 0x10fb, "82599", "82599", 0 ), + PCI_ROM ( 0x8086, 0x1528, "x540at2", "X540-AT2", 0 ), + PCI_ROM ( 0x8086, 0x154d, "x520", "X520", 0 ), +}; + +/** PCI driver */ +struct pci_driver intelx_driver __pci_driver = { + .ids = intelx_nics, + .id_count = ( sizeof ( intelx_nics ) / sizeof ( intelx_nics[0] ) ), + .probe = intelx_probe, + .remove = intelx_remove, +}; diff --git a/roms/ipxe/src/drivers/net/intelx.h b/roms/ipxe/src/drivers/net/intelx.h new file mode 100644 index 000000000..60bb294d5 --- /dev/null +++ b/roms/ipxe/src/drivers/net/intelx.h @@ -0,0 +1,114 @@ +#ifndef _INTELX_H +#define _INTELX_H + +/** @file + * + * Intel 10 Gigabit Ethernet network card driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/if_ether.h> +#include "intel.h" + +/** Device Control Register */ +#define INTELX_CTRL 0x00000UL +#define INTELX_CTRL_LRST 0x00000008UL /**< Link reset */ +#define INTELX_CTRL_RST 0x04000000UL /**< Device reset */ + +/** Time to delay for device reset, in milliseconds */ +#define INTELX_RESET_DELAY_MS 20 + +/** Extended Interrupt Cause Read Register */ +#define INTELX_EICR 0x00800UL +#define INTELX_EIRQ_RX0 0x00000001UL /**< RX0 (via IVAR) */ +#define INTELX_EIRQ_TX0 0x00000002UL /**< RX0 (via IVAR) */ +#define INTELX_EIRQ_RXO 0x00020000UL /**< Receive overrun */ +#define INTELX_EIRQ_LSC 0x00100000UL /**< Link status change */ + +/** Interrupt Mask Set/Read Register */ +#define INTELX_EIMS 0x00880UL + +/** Interrupt Mask Clear Register */ +#define INTELX_EIMC 0x00888UL + +/** Interrupt Vector Allocation Register */ +#define INTELX_IVAR 0x00900UL +#define INTELX_IVAR_RX0(bit) ( (bit) << 0 ) /**< RX queue 0 allocation */ +#define INTELX_IVAR_RX0_DEFAULT INTELX_IVAR_RX0 ( 0x00 ) +#define INTELX_IVAR_RX0_MASK INTELX_IVAR_RX0 ( 0x3f ) +#define INTELX_IVAR_RX0_VALID 0x00000080UL /**< RX queue 0 valid */ +#define INTELX_IVAR_TX0(bit) ( (bit) << 8 ) /**< TX queue 0 allocation */ +#define INTELX_IVAR_TX0_DEFAULT INTELX_IVAR_TX0 ( 0x01 ) +#define INTELX_IVAR_TX0_MASK INTELX_IVAR_TX0 ( 0x3f ) +#define INTELX_IVAR_TX0_VALID 0x00008000UL /**< TX queue 0 valid */ + +/** Receive Filter Control Register */ +#define INTELX_FCTRL 0x05080UL +#define INTELX_FCTRL_MPE 0x00000100UL /**< Multicast promiscuous */ +#define INTELX_FCTRL_UPE 0x00000200UL /**< Unicast promiscuous mode */ +#define INTELX_FCTRL_BAM 0x00000400UL /**< Broadcast accept mode */ + +/** Receive Address Low + * + * The MAC address registers RAL0/RAH0 exist at address 0x05400 for + * the 82598 and 0x0a200 for the 82599, according to the datasheet. + * In practice, the 82599 seems to also provide a copy of these + * registers at 0x05400. To aim for maximum compatibility, we try + * both addresses when reading the initial MAC address, and set both + * addresses when setting the MAC address. + */ +#define INTELX_RAL0 0x05400UL +#define INTELX_RAL0_ALT 0x0a200UL + +/** Receive Address High */ +#define INTELX_RAH0 0x05404UL +#define INTELX_RAH0_ALT 0x0a204UL +#define INTELX_RAH0_AV 0x80000000UL /**< Address valid */ + +/** Receive Descriptor register block */ +#define INTELX_RD 0x01000UL + +/** Split Receive Control Register */ +#define INTELX_SRRCTL 0x02100UL +#define INTELX_SRRCTL_BSIZE(kb) ( (kb) << 0 ) /**< Receive buffer size */ +#define INTELX_SRRCTL_BSIZE_DEFAULT INTELX_SRRCTL_BSIZE ( 0x02 ) +#define INTELX_SRRCTL_BSIZE_MASK INTELX_SRRCTL_BSIZE ( 0x1f ) + +/** Receive DMA Control Register */ +#define INTELX_RDRXCTL 0x02f00UL +#define INTELX_RDRXCTL_SECRC 0x00000001UL /**< Strip CRC */ + +/** Receive Control Register */ +#define INTELX_RXCTRL 0x03000UL +#define INTELX_RXCTRL_RXEN 0x00000001UL /**< Receive enable */ + +/** Transmit DMA Control Register */ +#define INTELX_DMATXCTL 0x04a80UL +#define INTELX_DMATXCTL_TE 0x00000001UL /**< Transmit enable */ + +/** Transmit Descriptor register block */ +#define INTELX_TD 0x06000UL + +/** RX DCA Control Register */ +#define INTELX_DCA_RXCTRL 0x02200UL +#define INTELX_DCA_RXCTRL_MUST_BE_ZERO 0x00001000UL /**< Must be zero */ + +/** MAC Core Control 0 Register */ +#define INTELX_HLREG0 0x04240UL +#define INTELX_HLREG0_JUMBOEN 0x00000004UL /**< Jumbo frame enable */ + +/** Maximum Frame Size Register */ +#define INTELX_MAXFRS 0x04268UL +#define INTELX_MAXFRS_MFS(len) ( (len) << 16 ) /**< Maximum frame size */ +#define INTELX_MAXFRS_MFS_DEFAULT \ + INTELX_MAXFRS_MFS ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ ) +#define INTELX_MAXFRS_MFS_MASK INTELX_MAXFRS_MFS ( 0xffff ) + +/** Link Status Register */ +#define INTELX_LINKS 0x042a4UL +#define INTELX_LINKS_UP 0x40000000UL /**< Link up */ + +#endif /* _INTELX_H */ diff --git a/roms/ipxe/src/drivers/net/ipoib.c b/roms/ipxe/src/drivers/net/ipoib.c index c1b8cad9a..1b5391776 100644 --- a/roms/ipxe/src/drivers/net/ipoib.c +++ b/roms/ipxe/src/drivers/net/ipoib.c @@ -265,6 +265,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = { .ntoa = eth_ntoa, .mc_hash = eth_mc_hash, .eth_addr = eth_eth_addr, + .eui64 = eth_eui64, .flags = LL_NAME_ONLY, }; diff --git a/roms/ipxe/src/drivers/net/ns8390.c b/roms/ipxe/src/drivers/net/ns8390.c index a30f93616..0ffc6216b 100644 --- a/roms/ipxe/src/drivers/net/ns8390.c +++ b/roms/ipxe/src/drivers/net/ns8390.c @@ -895,7 +895,7 @@ static int eth_probe (struct dev *dev, unsigned short *probe_addrs __unused) #endif 0 }; /* if no addresses supplied, fall back on defaults */ - if (probe_addrs == 0 || probe_addrs[0] == 0) + if (probe_addrs == NULL || probe_addrs[0] == 0) probe_addrs = base; eth_bmem = 0; /* No shared memory */ for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) { diff --git a/roms/ipxe/src/drivers/net/p80211hdr.h b/roms/ipxe/src/drivers/net/p80211hdr.h index 110905c5f..6e427293a 100644 --- a/roms/ipxe/src/drivers/net/p80211hdr.h +++ b/roms/ipxe/src/drivers/net/p80211hdr.h @@ -39,7 +39,7 @@ * * -------------------------------------------------------------------- * -* Portions of the development of this software were funded by +* Portions of the development of this software were funded by * Intersil Corporation as part of PRISM(R) chipset product development. * * -------------------------------------------------------------------- @@ -47,7 +47,7 @@ * This file declares the constants and types used in the interface * between a wlan driver and the user mode utilities. * -* Note: +* Note: * - Constant values are always in HOST byte order. To assign * values to multi-byte fields they _must_ be converted to * ieee byte order. To retrieve multi-byte values from incoming @@ -117,7 +117,7 @@ FILE_LICENCE ( GPL2_ONLY ); #define WLAN_FSTYPE_ASSOCRESP 0x01 #define WLAN_FSTYPE_REASSOCREQ 0x02 #define WLAN_FSTYPE_REASSOCRESP 0x03 -#define WLAN_FSTYPE_PROBEREQ 0x04 +#define WLAN_FSTYPE_PROBEREQ 0x04 #define WLAN_FSTYPE_PROBERESP 0x05 #define WLAN_FSTYPE_BEACON 0x08 #define WLAN_FSTYPE_ATIM 0x09 @@ -168,29 +168,29 @@ FILE_LICENCE ( GPL2_ONLY ); /* SET_FC_FSTYPE(WLAN_FSTYPE_RTS) ); */ /*------------------------------------------------------------*/ -#define WLAN_GET_FC_PVER(n) (((UINT16)(n)) & (BIT0 | BIT1)) -#define WLAN_GET_FC_FTYPE(n) ((((UINT16)(n)) & (BIT2 | BIT3)) >> 2) -#define WLAN_GET_FC_FSTYPE(n) ((((UINT16)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4) -#define WLAN_GET_FC_TODS(n) ((((UINT16)(n)) & (BIT8)) >> 8) -#define WLAN_GET_FC_FROMDS(n) ((((UINT16)(n)) & (BIT9)) >> 9) -#define WLAN_GET_FC_MOREFRAG(n) ((((UINT16)(n)) & (BIT10)) >> 10) -#define WLAN_GET_FC_RETRY(n) ((((UINT16)(n)) & (BIT11)) >> 11) -#define WLAN_GET_FC_PWRMGT(n) ((((UINT16)(n)) & (BIT12)) >> 12) -#define WLAN_GET_FC_MOREDATA(n) ((((UINT16)(n)) & (BIT13)) >> 13) -#define WLAN_GET_FC_ISWEP(n) ((((UINT16)(n)) & (BIT14)) >> 14) -#define WLAN_GET_FC_ORDER(n) ((((UINT16)(n)) & (BIT15)) >> 15) - -#define WLAN_SET_FC_PVER(n) ((UINT16)(n)) -#define WLAN_SET_FC_FTYPE(n) (((UINT16)(n)) << 2) -#define WLAN_SET_FC_FSTYPE(n) (((UINT16)(n)) << 4) -#define WLAN_SET_FC_TODS(n) (((UINT16)(n)) << 8) -#define WLAN_SET_FC_FROMDS(n) (((UINT16)(n)) << 9) -#define WLAN_SET_FC_MOREFRAG(n) (((UINT16)(n)) << 10) -#define WLAN_SET_FC_RETRY(n) (((UINT16)(n)) << 11) -#define WLAN_SET_FC_PWRMGT(n) (((UINT16)(n)) << 12) -#define WLAN_SET_FC_MOREDATA(n) (((UINT16)(n)) << 13) -#define WLAN_SET_FC_ISWEP(n) (((UINT16)(n)) << 14) -#define WLAN_SET_FC_ORDER(n) (((UINT16)(n)) << 15) +#define WLAN_GET_FC_PVER(n) (((uint16_t)(n)) & (BIT0 | BIT1)) +#define WLAN_GET_FC_FTYPE(n) ((((uint16_t)(n)) & (BIT2 | BIT3)) >> 2) +#define WLAN_GET_FC_FSTYPE(n) ((((uint16_t)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4) +#define WLAN_GET_FC_TODS(n) ((((uint16_t)(n)) & (BIT8)) >> 8) +#define WLAN_GET_FC_FROMDS(n) ((((uint16_t)(n)) & (BIT9)) >> 9) +#define WLAN_GET_FC_MOREFRAG(n) ((((uint16_t)(n)) & (BIT10)) >> 10) +#define WLAN_GET_FC_RETRY(n) ((((uint16_t)(n)) & (BIT11)) >> 11) +#define WLAN_GET_FC_PWRMGT(n) ((((uint16_t)(n)) & (BIT12)) >> 12) +#define WLAN_GET_FC_MOREDATA(n) ((((uint16_t)(n)) & (BIT13)) >> 13) +#define WLAN_GET_FC_ISWEP(n) ((((uint16_t)(n)) & (BIT14)) >> 14) +#define WLAN_GET_FC_ORDER(n) ((((uint16_t)(n)) & (BIT15)) >> 15) + +#define WLAN_SET_FC_PVER(n) ((uint16_t)(n)) +#define WLAN_SET_FC_FTYPE(n) (((uint16_t)(n)) << 2) +#define WLAN_SET_FC_FSTYPE(n) (((uint16_t)(n)) << 4) +#define WLAN_SET_FC_TODS(n) (((uint16_t)(n)) << 8) +#define WLAN_SET_FC_FROMDS(n) (((uint16_t)(n)) << 9) +#define WLAN_SET_FC_MOREFRAG(n) (((uint16_t)(n)) << 10) +#define WLAN_SET_FC_RETRY(n) (((uint16_t)(n)) << 11) +#define WLAN_SET_FC_PWRMGT(n) (((uint16_t)(n)) << 12) +#define WLAN_SET_FC_MOREDATA(n) (((uint16_t)(n)) << 13) +#define WLAN_SET_FC_ISWEP(n) (((uint16_t)(n)) << 14) +#define WLAN_SET_FC_ORDER(n) (((uint16_t)(n)) << 15) /*--- Duration Macros ----------------------------------------*/ /* Macros to get/set the bitfields of the Duration Field */ @@ -203,45 +203,45 @@ FILE_LICENCE ( GPL2_ONLY ); /* Macros to get/set the bitfields of the Sequence Control */ /* Field. */ /*------------------------------------------------------------*/ -#define WLAN_GET_SEQ_FRGNUM(n) (((UINT16)(n)) & (BIT0|BIT1|BIT2|BIT3)) -#define WLAN_GET_SEQ_SEQNUM(n) ((((UINT16)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) +#define WLAN_GET_SEQ_FRGNUM(n) (((uint16_t)(n)) & (BIT0|BIT1|BIT2|BIT3)) +#define WLAN_GET_SEQ_SEQNUM(n) ((((uint16_t)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4) /*--- Data ptr macro -----------------------------------------*/ -/* Creates a UINT8* to the data portion of a frame */ +/* Creates a uint8_t* to the data portion of a frame */ /* Assumes you're passing in a ptr to the beginning of the hdr*/ /*------------------------------------------------------------*/ -#define WLAN_HDR_A3_DATAP(p) (((UINT8*)(p)) + WLAN_HDR_A3_LEN) -#define WLAN_HDR_A4_DATAP(p) (((UINT8*)(p)) + WLAN_HDR_A4_LEN) +#define WLAN_HDR_A3_DATAP(p) (((uint8_t*)(p)) + WLAN_HDR_A3_LEN) +#define WLAN_HDR_A4_DATAP(p) (((uint8_t*)(p)) + WLAN_HDR_A4_LEN) -#define DOT11_RATE5_ISBASIC_GET(r) (((UINT8)(r)) & BIT7) +#define DOT11_RATE5_ISBASIC_GET(r) (((uint8_t)(r)) & BIT7) /*================================================================*/ /* Types */ /* BSS Timestamp */ -typedef UINT8 wlan_bss_ts_t[WLAN_BSS_TS_LEN]; +typedef uint8_t wlan_bss_ts_t[WLAN_BSS_TS_LEN]; /* Generic 802.11 Header types */ typedef struct p80211_hdr_a3 { - UINT16 fc; - UINT16 dur; - UINT8 a1[WLAN_ADDR_LEN]; - UINT8 a2[WLAN_ADDR_LEN]; - UINT8 a3[WLAN_ADDR_LEN]; - UINT16 seq; + uint16_t fc; + uint16_t dur; + uint8_t a1[WLAN_ADDR_LEN]; + uint8_t a2[WLAN_ADDR_LEN]; + uint8_t a3[WLAN_ADDR_LEN]; + uint16_t seq; } __WLAN_ATTRIB_PACK__ p80211_hdr_a3_t; typedef struct p80211_hdr_a4 { - UINT16 fc; - UINT16 dur; - UINT8 a1[WLAN_ADDR_LEN]; - UINT8 a2[WLAN_ADDR_LEN]; - UINT8 a3[WLAN_ADDR_LEN]; - UINT16 seq; - UINT8 a4[WLAN_ADDR_LEN]; + uint16_t fc; + uint16_t dur; + uint8_t a1[WLAN_ADDR_LEN]; + uint8_t a2[WLAN_ADDR_LEN]; + uint8_t a3[WLAN_ADDR_LEN]; + uint16_t seq; + uint8_t a4[WLAN_ADDR_LEN]; } __WLAN_ATTRIB_PACK__ p80211_hdr_a4_t; typedef union p80211_hdr @@ -273,9 +273,9 @@ typedef union p80211_hdr #define WLAN_FCS_LEN 4 /* ftcl in HOST order */ -inline static UINT16 p80211_headerlen(UINT16 fctl) +inline static uint16_t p80211_headerlen(uint16_t fctl) { - UINT16 hdrlen = 0; + uint16_t hdrlen = 0; switch ( WLAN_GET_FC_FTYPE(fctl) ) { case WLAN_FTYPE_MGMT: @@ -288,13 +288,13 @@ inline static UINT16 p80211_headerlen(UINT16 fctl) } break; case WLAN_FTYPE_CTL: - hdrlen = WLAN_CTL_FRAMELEN(WLAN_GET_FC_FSTYPE(fctl)) - - WLAN_FCS_LEN; + hdrlen = WLAN_CTL_FRAMELEN(WLAN_GET_FC_FSTYPE(fctl)) - + WLAN_FCS_LEN; break; default: hdrlen = WLAN_HDR_A3_LEN; } - + return hdrlen; } diff --git a/roms/ipxe/src/drivers/net/phantom/phantom.c b/roms/ipxe/src/drivers/net/phantom/phantom.c index 1c798e04a..e70ded08c 100644 --- a/roms/ipxe/src/drivers/net/phantom/phantom.c +++ b/roms/ipxe/src/drivers/net/phantom/phantom.c @@ -1454,11 +1454,8 @@ static struct net_device_operations phantom_operations = { * */ -/** Phantom CLP settings tag magic */ -#define PHN_CLP_TAG_MAGIC 0xc19c1900UL - -/** Phantom CLP settings tag magic mask */ -#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL +/** Phantom CLP settings scope */ +static const struct settings_scope phantom_settings_scope; /** Phantom CLP data * @@ -1659,7 +1656,7 @@ static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port, /** A Phantom CLP setting */ struct phantom_clp_setting { /** iPXE setting */ - struct setting *setting; + const struct setting *setting; /** Setting number */ unsigned int clp_setting; }; @@ -1676,7 +1673,8 @@ static struct phantom_clp_setting clp_settings[] = { * @v clp_setting Setting number, or 0 if not found */ static unsigned int -phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) { +phantom_clp_setting ( struct phantom_nic *phantom, + const struct setting *setting ) { struct phantom_clp_setting *clp_setting; unsigned int i; @@ -1689,8 +1687,8 @@ phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) { } /* Allow for use of numbered settings */ - if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC ) - return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK ); + if ( setting->scope == &phantom_settings_scope ) + return setting->tag; DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n", phantom, setting->name ); @@ -1706,7 +1704,7 @@ phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) { * @ret applies Setting applies within this settings block */ static int phantom_setting_applies ( struct settings *settings, - struct setting *setting ) { + const struct setting *setting ) { struct phantom_nic *phantom = container_of ( settings, struct phantom_nic, settings ); unsigned int clp_setting; @@ -1726,7 +1724,7 @@ static int phantom_setting_applies ( struct settings *settings, * @ret rc Return status code */ static int phantom_store_setting ( struct settings *settings, - struct setting *setting, + const struct setting *setting, const void *data, size_t len ) { struct phantom_nic *phantom = container_of ( settings, struct phantom_nic, settings ); @@ -2075,7 +2073,7 @@ static int phantom_probe ( struct pci_device *pci ) { assert ( phantom->port < PHN_MAX_NUM_PORTS ); settings_init ( &phantom->settings, &phantom_settings_operations, - &netdev->refcnt, PHN_CLP_TAG_MAGIC ); + &netdev->refcnt, &phantom_settings_scope ); /* Fix up PCI device */ adjust_pci_device ( pci ); diff --git a/roms/ipxe/src/drivers/net/prism2.c b/roms/ipxe/src/drivers/net/prism2.c index d2160148f..ab974264c 100644 --- a/roms/ipxe/src/drivers/net/prism2.c +++ b/roms/ipxe/src/drivers/net/prism2.c @@ -69,10 +69,10 @@ static const char hardcoded_ssid[] = ""; #define __cpu_to_le16(x) (x) #define __cpu_to_le32(x) (x) -#define hfa384x2host_16(n) (__le16_to_cpu((UINT16)(n))) -#define hfa384x2host_32(n) (__le32_to_cpu((UINT32)(n))) -#define host2hfa384x_16(n) (__cpu_to_le16((UINT16)(n))) -#define host2hfa384x_32(n) (__cpu_to_le32((UINT32)(n))) +#define hfa384x2host_16(n) (__le16_to_cpu((uint16_t)(n))) +#define hfa384x2host_32(n) (__le32_to_cpu((uint32_t)(n))) +#define host2hfa384x_16(n) (__cpu_to_le16((uint16_t)(n))) +#define host2hfa384x_32(n) (__cpu_to_le32((uint32_t)(n))) /* * PLX9052 PCI register offsets @@ -119,20 +119,18 @@ static const char hardcoded_ssid[] = ""; typedef struct hfa384x { - UINT32 iobase; + uint32_t iobase; void *membase; - UINT16 lastcmd; - UINT16 status; /* in host order */ - UINT16 resp0; /* in host order */ - UINT16 resp1; /* in host order */ - UINT16 resp2; /* in host order */ - UINT8 bssid[WLAN_BSSID_LEN]; + uint16_t lastcmd; + uint16_t status; /* in host order */ + uint16_t resp0; /* in host order */ + uint16_t resp1; /* in host order */ + uint16_t resp2; /* in host order */ + uint8_t bssid[WLAN_BSSID_LEN]; } hfa384x_t; /* The global instance of the hardware (i.e. where we store iobase and membase, in the absence of anywhere better to put them */ -static hfa384x_t hw_global = { - 0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0} -}; +static hfa384x_t hw_global; /* * 802.11 headers in addition to those in hfa384x_tx_frame_t (LLC and SNAP) @@ -141,9 +139,9 @@ static hfa384x_t hw_global = { typedef struct wlan_llc { - UINT8 dsap; - UINT8 ssap; - UINT8 ctl; + uint8_t dsap; + uint8_t ssap; + uint8_t ctl; } wlan_llc_t; static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */ @@ -151,8 +149,8 @@ static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indi #define WLAN_IEEE_OUI_LEN 3 typedef struct wlan_snap { - UINT8 oui[WLAN_IEEE_OUI_LEN]; - UINT16 type; + uint8_t oui[WLAN_IEEE_OUI_LEN]; + uint16_t type; } wlan_snap_t; typedef struct wlan_80211hdr @@ -168,11 +166,11 @@ typedef struct wlan_80211hdr /* * Hardware-level hfa384x functions * These are based on the ones in hfa384x.h (which are ifdef'd out since __KERNEL__ is not defined). - * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions. + * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions. */ /* Retrieve the value of one of the MAC registers. */ -static inline UINT16 hfa384x_getreg( hfa384x_t *hw, UINT reg ) +static inline uint16_t hfa384x_getreg( hfa384x_t *hw, unsigned int reg ) { #if (WLAN_HOSTIF == WLAN_PLX) return inw ( hw->iobase + reg ); @@ -182,7 +180,7 @@ static inline UINT16 hfa384x_getreg( hfa384x_t *hw, UINT reg ) } /* Set the value of one of the MAC registers. */ -static inline void hfa384x_setreg( hfa384x_t *hw, UINT16 val, UINT reg ) +static inline void hfa384x_setreg( hfa384x_t *hw, uint16_t val, unsigned int reg ) { #if (WLAN_HOSTIF == WLAN_PLX) outw ( val, hw->iobase + reg ); @@ -192,15 +190,15 @@ static inline void hfa384x_setreg( hfa384x_t *hw, UINT16 val, UINT reg ) return; } -/* +/* * Noswap versions * Etherboot is i386 only, so swap and noswap are the same... */ -static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg ) +static inline uint16_t hfa384x_getreg_noswap( hfa384x_t *hw, unsigned int reg ) { return hfa384x_getreg ( hw, reg ); } -static inline void hfa384x_setreg_noswap( hfa384x_t *hw, UINT16 val, UINT reg ) +static inline void hfa384x_setreg_noswap( hfa384x_t *hw, uint16_t val, unsigned int reg ) { hfa384x_setreg ( hw, val, reg ); } @@ -227,12 +225,12 @@ static inline void hfa384x_setreg_noswap( hfa384x_t *hw, UINT16 val, UINT reg ) * >0 command indicated error, Status and Resp0-2 are * in hw structure. */ -static int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2) +static int hfa384x_docmd_wait( hfa384x_t *hw, uint16_t cmd, uint16_t parm0, uint16_t parm1, uint16_t parm2) { - UINT16 reg = 0; - UINT16 counter = 0; - - /* wait for the busy bit to clear */ + uint16_t reg = 0; + uint16_t counter = 0; + + /* wait for the busy bit to clear */ counter = 0; reg = hfa384x_getreg(hw, HFA384x_CMD); while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) { @@ -251,7 +249,7 @@ static int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 p hfa384x_setreg(hw, parm2, HFA384x_PARAM2); hw->lastcmd = cmd; hfa384x_setreg(hw, cmd, HFA384x_CMD); - + /* Now wait for completion */ counter = 0; reg = hfa384x_getreg(hw, HFA384x_EVSTAT); @@ -286,14 +284,14 @@ static int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 p * hw device structure * id FID or RID, destined for the select register (host order) * offset An _even_ offset into the buffer for the given FID/RID. - * Returns: + * Returns: * 0 success */ -static int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset) +static int hfa384x_prepare_bap(hfa384x_t *hw, uint16_t id, uint16_t offset) { int result = 0; - UINT16 reg; - UINT16 i; + uint16_t reg; + uint16_t i; /* Validate offset, buf, and len */ if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) { @@ -304,7 +302,7 @@ static int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset) udelay(10); hfa384x_setreg(hw, offset, HFA384x_OFFSET0); /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */ - i = 0; + i = 0; do { reg = hfa384x_getreg(hw, HFA384x_OFFSET0); if ( i > 0 ) udelay(2); @@ -330,28 +328,28 @@ static int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset) * offset An _even_ offset into the buffer for the given FID/RID. * buf ptr to array of bytes * len length of data to transfer in bytes - * Returns: + * Returns: * 0 success */ -static int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 id, UINT16 offset, - void *buf, UINT len) +static int hfa384x_copy_from_bap(hfa384x_t *hw, uint16_t id, uint16_t offset, + void *buf, unsigned int len) { int result = 0; - UINT8 *d = (UINT8*)buf; - UINT16 i; - UINT16 reg = 0; - + uint8_t *d = (uint8_t*)buf; + uint16_t i; + uint16_t reg = 0; + /* Prepare BAP */ result = hfa384x_prepare_bap ( hw, id, offset ); if ( result == 0 ) { /* Read even(len) buf contents from data reg */ for ( i = 0; i < (len & 0xfffe); i+=2 ) { - *(UINT16*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0); + *(uint16_t*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0); } /* If len odd, handle last byte */ if ( len % 2 ){ reg = hfa384x_getreg_noswap(hw, HFA384x_DATA0); - d[len-1] = ((UINT8*)(®))[0]; + d[len-1] = ((uint8_t*)(®))[0]; } } if (result) { @@ -369,30 +367,30 @@ static int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 id, UINT16 offset, * offset An _even_ offset into the buffer for the given FID/RID. * buf ptr to array of bytes * len length of data to transfer in bytes - * Returns: + * Returns: * 0 success */ -static int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 id, UINT16 offset, - void *buf, UINT len) +static int hfa384x_copy_to_bap(hfa384x_t *hw, uint16_t id, uint16_t offset, + void *buf, unsigned int len) { int result = 0; - UINT8 *d = (UINT8*)buf; - UINT16 i; - UINT16 savereg; + uint8_t *d = (uint8_t*)buf; + uint16_t i; + uint16_t savereg; /* Prepare BAP */ result = hfa384x_prepare_bap ( hw, id, offset ); if ( result == 0 ) { /* Write even(len) buf contents to data reg */ for ( i = 0; i < (len & 0xfffe); i+=2 ) { - hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), HFA384x_DATA0); + hfa384x_setreg_noswap(hw, *(uint16_t*)(&(d[i])), HFA384x_DATA0); } /* If len odd, handle last byte */ if ( len % 2 ){ savereg = hfa384x_getreg_noswap(hw, HFA384x_DATA0); result = hfa384x_prepare_bap ( hw, id, offset + (len & 0xfffe) ); if ( result == 0 ) { - ((UINT8*)(&savereg))[0] = d[len-1]; + ((uint8_t*)(&savereg))[0] = d[len-1]; hfa384x_setreg_noswap(hw, savereg, HFA384x_DATA0); } } @@ -412,10 +410,10 @@ static int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 id, UINT16 offset, * configuration record. (host order) * rid RID of the record to read/write. (host order) * - * Returns: + * Returns: * 0 success */ -static inline int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid) +static inline int hfa384x_cmd_access(hfa384x_t *hw, uint16_t write, uint16_t rid) { return hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) | HFA384x_CMD_WRITE_SET(write), rid, 0, 0); } @@ -427,14 +425,14 @@ static inline int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid) * hw device structure * rid config/info record id (host order) * buf host side record buffer. Upon return it will - * contain the body portion of the record (minus the + * contain the body portion of the record (minus the * RID and len). * len buffer length (in bytes, should match record length) * - * Returns: + * Returns: * 0 success */ -static int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len) +static int hfa384x_drvr_getconfig(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len) { int result = 0; hfa384x_rec_t rec; @@ -469,27 +467,27 @@ static int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 l * rid config/info record id (in host order) * val ptr to 16/32 bit buffer to receive value (in host order) * - * Returns: + * Returns: * 0 success */ #if 0 /* Not actually used anywhere */ -static int hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val) +static int hfa384x_drvr_getconfig16(hfa384x_t *hw, uint16_t rid, void *val) { int result = 0; - result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16)); + result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(uint16_t)); if ( result == 0 ) { - *((UINT16*)val) = hfa384x2host_16(*((UINT16*)val)); + *((uint16_t*)val) = hfa384x2host_16(*((uint16_t*)val)); } return result; } #endif #if 0 /* Not actually used anywhere */ -static int hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val) +static int hfa384x_drvr_getconfig32(hfa384x_t *hw, uint16_t rid, void *val) { int result = 0; - result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32)); + result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(uint32_t)); if ( result == 0 ) { - *((UINT32*)val) = hfa384x2host_32(*((UINT32*)val)); + *((uint32_t*)val) = hfa384x2host_32(*((uint32_t*)val)); } return result; } @@ -504,10 +502,10 @@ static int hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val) * buf host side record buffer * len buffer length (in bytes) * - * Returns: + * Returns: * 0 success */ -static int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len) +static int hfa384x_drvr_setconfig(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len) { int result = 0; hfa384x_rec_t rec; @@ -541,21 +539,21 @@ static int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 l * rid config/info record id (in host order) * val 16/32 bit value to store (in host order) * - * Returns: + * Returns: * 0 success */ -static int hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 *val) +static int hfa384x_drvr_setconfig16(hfa384x_t *hw, uint16_t rid, uint16_t *val) { - UINT16 value; + uint16_t value; value = host2hfa384x_16(*val); - return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT16)); + return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(uint16_t)); } #if 0 /* Not actually used anywhere */ -static int hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 *val) +static int hfa384x_drvr_setconfig32(hfa384x_t *hw, uint16_t rid, uint32_t *val) { - UINT32 value; + uint32_t value; value = host2hfa384x_32(*val); - return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT32)); + return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(uint32_t)); } #endif @@ -573,14 +571,14 @@ static int hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 *val) * descr Descriptive text string of what is being waited for * (will be printed out if a timeout happens) * - * Returns: - * value of EVSTAT register, or 0 on failure + * Returns: + * value of EVSTAT register, or 0 on failure */ -static int hfa384x_wait_for_event(hfa384x_t *hw, UINT16 event_mask, UINT16 event_ack, int wait, int timeout, const char *descr) +static int hfa384x_wait_for_event(hfa384x_t *hw, uint16_t event_mask, uint16_t event_ack, int wait, int timeout, const char *descr) { - UINT16 reg; + uint16_t reg; int count = 0; - + do { reg = hfa384x_getreg(hw, HFA384x_EVSTAT); if ( count > 0 ) udelay(wait); @@ -600,12 +598,12 @@ POLL - Wait for a frame ***************************************************************************/ static int prism2_poll(struct nic *nic, int retrieve) { - UINT16 reg; - UINT16 rxfid; - UINT16 result; + uint16_t reg; + uint16_t rxfid; + uint16_t result; hfa384x_rx_frame_t rxdesc; hfa384x_t *hw = &hw_global; - + /* Check for received packet */ reg = hfa384x_getreg(hw, HFA384x_EVSTAT); if ( ! HFA384x_EVSTAT_ISRX(reg) ) { @@ -617,7 +615,7 @@ static int prism2_poll(struct nic *nic, int retrieve) /* Acknowledge RX event */ hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), HFA384x_EVACK); - /* Get RX FID */ + /* Get RX FID */ rxfid = hfa384x_getreg(hw, HFA384x_RXFID); /* Get the descriptor (including headers) */ result = hfa384x_copy_from_bap(hw, rxfid, 0, &rxdesc, sizeof(rxdesc)); @@ -660,8 +658,8 @@ static void prism2_transmit( hfa384x_t *hw = &hw_global; hfa384x_tx_frame_t txdesc; wlan_80211hdr_t p80211hdr = { wlan_llc_snap, {{0,0,0},0} }; - UINT16 fid; - UINT16 status; + uint16_t fid; + uint16_t status; int result; // Request FID allocation @@ -675,7 +673,7 @@ static void prism2_transmit( /* Build Tx frame structure */ memset(&txdesc, 0, sizeof(txdesc)); - txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | + txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1) ); txdesc.frame_control = host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) | WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY) | @@ -687,13 +685,13 @@ static void prism2_transmit( /* Set up SNAP header */ /* Let OUI default to RFC1042 (0x000000) */ p80211hdr.snap.type = htons(t); - + /* Copy txdesc, p80211hdr and payload parts to FID */ result = hfa384x_copy_to_bap(hw, fid, 0, &txdesc, sizeof(txdesc)); if ( result ) return; /* fail */ result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc), &p80211hdr, sizeof(p80211hdr) ); if ( result ) return; /* fail */ - result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (UINT8*)p, s ); + result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (uint8_t*)p, s ); if ( result ) return; /* fail */ /* Issue Tx command */ @@ -702,7 +700,7 @@ static void prism2_transmit( printf("hfa384x: Transmit failed with result %#hx.\n", result); return; } - + /* Wait for transmit completion (or exception) */ result = hfa384x_wait_for_event(hw, HFA384x_EVSTAT_TXEXC | HFA384x_EVSTAT_TX, HFA384x_EVACK_INFO, 200, 500, "Tx to complete\n" ); @@ -760,8 +758,8 @@ You should omit the last argument struct pci_device * for a non-PCI NIC ***************************************************************************/ static int prism2_probe ( struct nic *nic, hfa384x_t *hw ) { int result; - UINT16 tmp16 = 0; - UINT16 infofid; + uint16_t tmp16 = 0; + uint16_t infofid; hfa384x_InfFrame_t inf; char ssid[HFA384x_RID_CNFDESIREDSSID_LEN]; int info_count = 0; @@ -820,17 +818,17 @@ static int prism2_probe ( struct nic *nic, hfa384x_t *hw ) { } else { printf ( "Attempting to autojoin to SSID %s (attempt %d)...", &ssid[2], info_count ); } - + if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_INFO, 0, 1000, 2000, "Info event" ) ) return 0; printf("done\n"); infofid = hfa384x_getreg(hw, HFA384x_INFOFID); /* Retrieve the length */ - result = hfa384x_copy_from_bap( hw, infofid, 0, &inf.framelen, sizeof(UINT16)); + result = hfa384x_copy_from_bap( hw, infofid, 0, &inf.framelen, sizeof(uint16_t)); if ( result ) return 0; /* fail */ inf.framelen = hfa384x2host_16(inf.framelen); /* Retrieve the rest */ - result = hfa384x_copy_from_bap( hw, infofid, sizeof(UINT16), - &(inf.infotype), inf.framelen * sizeof(UINT16)); + result = hfa384x_copy_from_bap( hw, infofid, sizeof(uint16_t), + &(inf.infotype), inf.framelen * sizeof(uint16_t)); if ( result ) return 0; /* fail */ if ( inf.infotype != HFA384x_IT_LINKSTATUS ) { /* Not a Link Status info frame: die */ @@ -843,13 +841,13 @@ static int prism2_probe ( struct nic *nic, hfa384x_t *hw ) { printf ( "Link not connected (status %#hx)\n", inf.info.linkstatus.linkstatus ); } } while ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED ); - + /* Retrieve BSSID and print Connected message */ result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CURRENTBSSID, hw->bssid, WLAN_BSSID_LEN); DBG ( "Link connected (BSSID %s - ", eth_ntoa ( hw->bssid ) ); DBG ( " MAC address %s)\n", eth_ntoa (nic->node_addr ) ); - + /* point to NIC specific routines */ nic->nic_op = &prism2_operations; return 1; diff --git a/roms/ipxe/src/drivers/net/realtek.c b/roms/ipxe/src/drivers/net/realtek.c index 76fa47bbc..7964475a2 100644 --- a/roms/ipxe/src/drivers/net/realtek.c +++ b/roms/ipxe/src/drivers/net/realtek.c @@ -50,6 +50,33 @@ FILE_LICENCE ( GPL2_OR_LATER ); /****************************************************************************** * + * Debugging + * + ****************************************************************************** + */ + +/** + * Dump all registers (for debugging) + * + * @v rtl Realtek device + */ +static __attribute__ (( unused )) void realtek_dump ( struct realtek_nic *rtl ){ + uint8_t regs[256]; + unsigned int i; + + /* Do nothing unless debug output is enabled */ + if ( ! DBG_LOG ) + return; + + /* Dump registers (via byte accesses; may not work for all registers) */ + for ( i = 0 ; i < sizeof ( regs ) ; i++ ) + regs[i] = readb ( rtl->regs + i ); + DBGC ( rtl, "REALTEK %p register dump:\n", rtl ); + DBGC_HDA ( rtl, 0, regs, sizeof ( regs ) ); +} + +/****************************************************************************** + * * EEPROM interface * ****************************************************************************** @@ -74,6 +101,7 @@ static void realtek_spi_open_bit ( struct bit_basher *basher ) { /* Enable EEPROM access */ writeb ( RTL_9346CR_EEM_EEPROM, rtl->regs + RTL_9346CR ); + readb ( rtl->regs + RTL_9346CR ); /* Ensure write reaches chip */ } /** @@ -87,6 +115,7 @@ static void realtek_spi_close_bit ( struct bit_basher *basher ) { /* Disable EEPROM access */ writeb ( RTL_9346CR_EEM_NORMAL, rtl->regs + RTL_9346CR ); + readb ( rtl->regs + RTL_9346CR ); /* Ensure write reaches chip */ } /** @@ -129,6 +158,7 @@ static void realtek_spi_write_bit ( struct bit_basher *basher, reg &= ~mask; reg |= ( data & mask ); writeb ( reg, rtl->regs + RTL_9346CR ); + readb ( rtl->regs + RTL_9346CR ); /* Ensure write reaches chip */ DBG_ENABLE ( DBGLVL_IO ); } @@ -144,9 +174,12 @@ static struct bit_basher_operations realtek_basher_ops = { * Initialise EEPROM * * @v netdev Network device + * @ret rc Return status code */ -static void realtek_init_eeprom ( struct net_device *netdev ) { +static int realtek_init_eeprom ( struct net_device *netdev ) { struct realtek_nic *rtl = netdev->priv; + uint16_t id; + int rc; /* Initialise SPI bit-bashing interface */ rtl->spibit.basher.op = &realtek_basher_ops; @@ -163,6 +196,22 @@ static void realtek_init_eeprom ( struct net_device *netdev ) { } rtl->eeprom.bus = &rtl->spibit.bus; + /* Check for EEPROM presence. Some onboard NICs will have no + * EEPROM connected, with the BIOS being responsible for + * programming the initial register values. + */ + if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_ID, + &id, sizeof ( id ) ) ) != 0 ) { + DBGC ( rtl, "REALTEK %p could not read EEPROM ID: %s\n", + rtl, strerror ( rc ) ); + return rc; + } + if ( id != cpu_to_le16 ( RTL_EEPROM_ID_MAGIC ) ) { + DBGC ( rtl, "REALTEK %p EEPROM ID incorrect (%#04x); assuming " + "no EEPROM\n", rtl, le16_to_cpu ( id ) ); + return -ENODEV; + } + /* Initialise space for non-volatile options, if available * * We use offset 0x40 (i.e. address 0x20), length 0x40. This @@ -176,6 +225,8 @@ static void realtek_init_eeprom ( struct net_device *netdev ) { nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD, RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt ); } + + return 0; } /****************************************************************************** @@ -389,13 +440,38 @@ static void realtek_check_link ( struct net_device *netdev ) { /* Determine link state */ if ( rtl->have_phy_regs ) { + mii_dump ( &rtl->mii ); phystatus = readb ( rtl->regs + RTL_PHYSTATUS ); link_up = ( phystatus & RTL_PHYSTATUS_LINKSTS ); - DBGC ( rtl, "REALTEK %p PHY status is %02x\n", rtl, phystatus ); + DBGC ( rtl, "REALTEK %p PHY status is %02x (%s%s%s%s%s%s, " + "Link%s, %sDuplex)\n", rtl, phystatus, + ( ( phystatus & RTL_PHYSTATUS_ENTBI ) ? "TBI" : "GMII" ), + ( ( phystatus & RTL_PHYSTATUS_TXFLOW ) ? + ", TxFlow" : "" ), + ( ( phystatus & RTL_PHYSTATUS_RXFLOW ) ? + ", RxFlow" : "" ), + ( ( phystatus & RTL_PHYSTATUS_1000MF ) ? + ", 1000Mbps" : "" ), + ( ( phystatus & RTL_PHYSTATUS_100M ) ? + ", 100Mbps" : "" ), + ( ( phystatus & RTL_PHYSTATUS_10M ) ? + ", 10Mbps" : "" ), + ( ( phystatus & RTL_PHYSTATUS_LINKSTS ) ? + "Up" : "Down" ), + ( ( phystatus & RTL_PHYSTATUS_FULLDUP ) ? + "Full" : "Half" ) ); } else { msr = readb ( rtl->regs + RTL_MSR ); link_up = ( ! ( msr & RTL_MSR_LINKB ) ); - DBGC ( rtl, "REALTEK %p media status is %02x\n", rtl, msr ); + DBGC ( rtl, "REALTEK %p media status is %02x (Link%s, " + "%dMbps%s%s%s%s%s)\n", rtl, msr, + ( ( msr & RTL_MSR_LINKB ) ? "Down" : "Up" ), + ( ( msr & RTL_MSR_SPEED_10 ) ? 10 : 100 ), + ( ( msr & RTL_MSR_TXFCE ) ? ", TxFlow" : "" ), + ( ( msr & RTL_MSR_RXFCE ) ? ", RxFlow" : "" ), + ( ( msr & RTL_MSR_AUX_STATUS ) ? ", AuxPwr" : "" ), + ( ( msr & RTL_MSR_TXPF ) ? ", TxPause" : "" ), + ( ( msr & RTL_MSR_RXPF ) ? ", RxPause" : "" ) ); } /* Report link state */ @@ -525,7 +601,11 @@ static int realtek_create_ring ( struct realtek_nic *rtl, static void realtek_destroy_ring ( struct realtek_nic *rtl, struct realtek_ring *ring ) { - /* Do nothing in legacy mode */ + /* Reset producer and consumer counters */ + ring->prod = 0; + ring->cons = 0; + + /* Do nothing more if in legacy mode */ if ( rtl->legacy ) return; @@ -536,8 +616,6 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, /* Free descriptor ring */ free_dma ( ring->desc, ring->len ); ring->desc = NULL; - ring->prod = 0; - ring->cons = 0; } /** @@ -630,8 +708,8 @@ static int realtek_open ( struct net_device *netdev ) { /* Configure receiver */ rcr = readl ( rtl->regs + RTL_RCR ); - rcr &= ~( RTL_RCR_RXFTH_MASK | RTL_RCR_RBLEN_MASK | - RTL_RCR_MXDMA_MASK ); + rcr &= ~( RTL_RCR_STOP_WORKING | RTL_RCR_RXFTH_MASK | + RTL_RCR_RBLEN_MASK | RTL_RCR_MXDMA_MASK ); rcr |= ( RTL_RCR_RXFTH_DEFAULT | RTL_RCR_RBLEN_DEFAULT | RTL_RCR_MXDMA_DEFAULT | RTL_RCR_WRAP | RTL_RCR_AB | RTL_RCR_AM | RTL_RCR_APM | RTL_RCR_AAP ); @@ -700,8 +778,8 @@ static int realtek_transmit ( struct net_device *netdev, /* Get next transmit descriptor */ if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) { - DBGC ( rtl, "REALTEK %p out of transmit descriptors\n", rtl ); - return -ENOBUFS; + netdev_tx_defer ( netdev, iobuf ); + return 0; } tx_idx = ( rtl->tx.prod++ % RTL_NUM_TX_DESC ); @@ -785,8 +863,8 @@ static void realtek_poll_tx ( struct net_device *netdev ) { DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); /* Complete TX descriptor */ - netdev_tx_complete_next ( netdev ); rtl->tx.cons++; + netdev_tx_complete_next ( netdev ); } } @@ -840,6 +918,9 @@ static void realtek_legacy_poll_rx ( struct net_device *netdev ) { rtl->rx_offset = ( ( rtl->rx_offset + 3 ) & ~3 ); rtl->rx_offset = ( rtl->rx_offset % RTL_RXBUF_LEN ); writew ( ( rtl->rx_offset - 16 ), rtl->regs + RTL_CAPR ); + + /* Give chip time to react before rechecking RTL_CR */ + readw ( rtl->regs + RTL_CAPR ); } } @@ -878,13 +959,15 @@ static void realtek_poll_rx ( struct net_device *netdev ) { len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK ); iob_put ( iobuf, ( len - 4 /* strip CRC */ ) ); - DBGC2 ( rtl, "REALTEK %p RX %d complete (length %zd)\n", - rtl, rx_idx, len ); - /* Hand off to network stack */ if ( rx->flags & cpu_to_le16 ( RTL_DESC_RES ) ) { + DBGC ( rtl, "REALTEK %p RX %d error (length %zd, " + "flags %04x)\n", rtl, rx_idx, len, + le16_to_cpu ( rx->flags ) ); netdev_rx_err ( netdev, iobuf, -EIO ); } else { + DBGC2 ( rtl, "REALTEK %p RX %d complete (length " + "%zd)\n", rtl, rx_idx, len ); netdev_rx ( netdev, iobuf ); } rtl->rx.cons++; @@ -1045,22 +1128,22 @@ static int realtek_probe ( struct pci_device *pci ) { realtek_detect ( rtl ); /* Initialise EEPROM */ - realtek_init_eeprom ( netdev ); + if ( ( rc = realtek_init_eeprom ( netdev ) ) == 0 ) { + + /* Read MAC address from EEPROM */ + if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC, + netdev->hw_addr, ETH_ALEN ) ) != 0 ) { + DBGC ( rtl, "REALTEK %p could not read MAC address: " + "%s\n", rtl, strerror ( rc ) ); + goto err_nvs_read; + } - /* Read MAC address from EEPROM */ - if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC, - netdev->hw_addr, ETH_ALEN ) ) != 0 ) { - DBGC ( rtl, "REALTEK %p could not read MAC address: %s\n", - rtl, strerror ( rc ) ); - goto err_nvs_read; - } + } else { - /* The EEPROM may not be present for onboard NICs. Fall back - * to reading the current ID register value, which will - * hopefully have been programmed by the platform firmware. - */ - if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) { - DBGC ( rtl, "REALTEK %p seems to have no EEPROM\n", rtl ); + /* EEPROM not present. Fall back to reading the + * current ID register value, which will hopefully + * have been programmed by the platform firmware. + */ for ( i = 0 ; i < ETH_ALEN ; i++ ) netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i ); } diff --git a/roms/ipxe/src/drivers/net/realtek.h b/roms/ipxe/src/drivers/net/realtek.h index 6a7b10a93..ac33405e8 100644 --- a/roms/ipxe/src/drivers/net/realtek.h +++ b/roms/ipxe/src/drivers/net/realtek.h @@ -140,6 +140,7 @@ enum realtek_legacy_status { /** Receive (Rx) Configuration Register (dword) */ #define RTL_RCR 0x44 +#define RTL_RCR_STOP_WORKING 0x01000000UL /**< Here be dragons */ #define RTL_RCR_RXFTH(x) ( (x) << 13 ) /**< Receive FIFO threshold */ #define RTL_RCR_RXFTH_MASK RTL_RCR_RXFTH ( 0x7 ) #define RTL_RCR_RXFTH_DEFAULT RTL_RCR_RXFTH ( 0x7 /* Whole packet */ ) @@ -166,6 +167,12 @@ enum realtek_legacy_status { #define RTL_9346CR_EEDI 0x02 /**< Data in */ #define RTL_9346CR_EEDO 0x01 /**< Data out */ +/** Word offset of ID code word within EEPROM */ +#define RTL_EEPROM_ID ( 0x00 / 2 ) + +/** EEPROM code word magic value */ +#define RTL_EEPROM_ID_MAGIC 0x8129 + /** Word offset of MAC address within EEPROM */ #define RTL_EEPROM_MAC ( 0x0e / 2 ) @@ -181,7 +188,13 @@ enum realtek_legacy_status { /** Media Status Register (byte, 8139 only) */ #define RTL_MSR 0x58 +#define RTL_MSR_TXFCE 0x80 /**< TX flow control enabled */ +#define RTL_MSR_RXFCE 0x40 /**< RX flow control enabled */ +#define RTL_MSR_AUX_STATUS 0x10 /**< Aux power present */ +#define RTL_MSR_SPEED_10 0x08 /**< 10Mbps */ #define RTL_MSR_LINKB 0x04 /**< Inverse of link status */ +#define RTL_MSR_TXPF 0x02 /**< TX pause flag */ +#define RTL_MSR_RXPF 0x01 /**< RX pause flag */ /** PHY Access Register (dword, 8169 only) */ #define RTL_PHYAR 0x60 @@ -198,7 +211,14 @@ enum realtek_legacy_status { /** PHY (GMII, MII, or TBI) Status Register (byte, 8169 only) */ #define RTL_PHYSTATUS 0x6c +#define RTL_PHYSTATUS_ENTBI 0x80 /**< TBI / GMII mode */ +#define RTL_PHYSTATUS_TXFLOW 0x40 /**< TX flow control enabled */ +#define RTL_PHYSTATUS_RXFLOW 0x20 /**< RX flow control enabled */ +#define RTL_PHYSTATUS_1000MF 0x10 /**< 1000Mbps full-duplex */ +#define RTL_PHYSTATUS_100M 0x08 /**< 100Mbps */ +#define RTL_PHYSTATUS_10M 0x04 /**< 10Mbps */ #define RTL_PHYSTATUS_LINKSTS 0x02 /**< Link ok */ +#define RTL_PHYSTATUS_FULLDUP 0x01 /**< Full duplex */ /** Transmit Priority Polling Register (byte, 8139C+ only) */ #define RTL_TPPOLL_8139CP 0xd9 @@ -220,7 +240,8 @@ enum realtek_legacy_status { #define RTL_NUM_RX_DESC 4 /** Receive buffer length */ -#define RTL_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ ) +#define RTL_RX_MAX_LEN \ + ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ + 4 /* extra space */ ) /** A Realtek descriptor ring */ struct realtek_ring { diff --git a/roms/ipxe/src/drivers/net/rhine.c b/roms/ipxe/src/drivers/net/rhine.c new file mode 100644 index 000000000..42bc124e0 --- /dev/null +++ b/roms/ipxe/src/drivers/net/rhine.c @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2012 Adrian Jamroz <adrian.jamroz@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> +#include <ipxe/iobuf.h> +#include <ipxe/malloc.h> +#include <ipxe/pci.h> +#include <ipxe/mii.h> +#include "rhine.h" + +/** @file + * + * VIA Rhine network driver + * + */ + +/****************************************************************************** + * + * MII interface + * + ****************************************************************************** + */ + +/** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret value Data read, or negative error + */ +static int rhine_mii_read ( struct mii_interface *mii, unsigned int reg ) { + struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t cr; + + DBGC2 ( rhn, "RHINE %p MII read reg %d\n", rhn, reg ); + + /* Initiate read */ + writeb ( reg, rhn->regs + RHINE_MII_ADDR ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + writeb ( ( cr | RHINE_MII_CR_RDEN ), rhn->regs + RHINE_MII_CR ); + + /* Wait for read to complete */ + while ( timeout-- ) { + udelay ( 1 ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + if ( ! ( cr & RHINE_MII_CR_RDEN ) ) + return readw ( rhn->regs + RHINE_MII_RDWR ); + } + + DBGC ( rhn, "RHINE %p MII read timeout\n", rhn ); + return -ETIMEDOUT; +} + +/** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ +static int rhine_mii_write ( struct mii_interface *mii, unsigned int reg, + unsigned int data ) { + struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t cr; + + DBGC2 ( rhn, "RHINE %p MII write reg %d data 0x%04x\n", + rhn, reg, data ); + + /* Initiate write */ + writeb ( reg, rhn->regs + RHINE_MII_ADDR ); + writew ( data, rhn->regs + RHINE_MII_RDWR ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + writeb ( ( cr | RHINE_MII_CR_WREN ), rhn->regs + RHINE_MII_CR ); + + /* Wait for write to complete */ + while ( timeout-- ) { + udelay ( 1 ); + cr = readb ( rhn->regs + RHINE_MII_CR ); + if ( ! ( cr & RHINE_MII_CR_WREN ) ) + return 0; + } + + DBGC ( rhn, "RHINE %p MII write timeout\n", rhn ); + return -ETIMEDOUT; +} + +/** Rhine MII operations */ +static struct mii_operations rhine_mii_operations = { + .read = rhine_mii_read, + .write = rhine_mii_write, +}; + +/** + * Enable auto-polling + * + * @v rhn Rhine device + * @ret rc Return status code + * + * This is voodoo. There seems to be no documentation on exactly what + * we are waiting for, or why we have to do anything other than simply + * turn the feature on. + */ +static int rhine_mii_autopoll ( struct rhine_nic *rhn ) { + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t addr; + + /* Initiate auto-polling */ + writeb ( MII_BMSR, rhn->regs + RHINE_MII_ADDR ); + writeb ( RHINE_MII_CR_AUTOPOLL, rhn->regs + RHINE_MII_CR ); + + /* Wait for auto-polling to complete */ + while ( timeout-- ) { + udelay ( 1 ); + addr = readb ( rhn->regs + RHINE_MII_ADDR ); + if ( ! ( addr & RHINE_MII_ADDR_MDONE ) ) { + writeb ( ( MII_BMSR | RHINE_MII_ADDR_MSRCEN ), + rhn->regs + RHINE_MII_ADDR ); + return 0; + } + } + + DBGC ( rhn, "RHINE %p MII auto-poll timeout\n", rhn ); + return -ETIMEDOUT; +} + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset hardware + * + * @v rhn Rhine device + * @ret rc Return status code + * + * We're using PIO because this might reset the MMIO enable bit. + */ +static int rhine_reset ( struct rhine_nic *rhn ) { + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t cr1; + + DBGC ( rhn, "RHINE %p reset\n", rhn ); + + /* Initiate reset */ + outb ( RHINE_CR1_RESET, rhn->ioaddr + RHINE_CR1 ); + + /* Wait for reset to complete */ + while ( timeout-- ) { + udelay ( 1 ); + cr1 = inb ( rhn->ioaddr + RHINE_CR1 ); + if ( ! ( cr1 & RHINE_CR1_RESET ) ) + return 0; + } + + DBGC ( rhn, "RHINE %p reset timeout\n", rhn ); + return -ETIMEDOUT; +} + +/** + * Enable MMIO register access + * + * @v rhn Rhine device + * @v revision Card revision + */ +static void rhine_enable_mmio ( struct rhine_nic *rhn, int revision ) { + uint8_t conf; + + if ( revision < RHINE_REVISION_OLD ) { + conf = inb ( rhn->ioaddr + RHINE_CHIPCFG_A ); + outb ( ( conf | RHINE_CHIPCFG_A_MMIO ), + rhn->ioaddr + RHINE_CHIPCFG_A ); + } else { + conf = inb ( rhn->ioaddr + RHINE_CHIPCFG_D ); + outb ( ( conf | RHINE_CHIPCFG_D_MMIO ), + rhn->ioaddr + RHINE_CHIPCFG_D ); + } +} + +/** + * Reload EEPROM contents + * + * @v rhn Rhine device + * @ret rc Return status code + * + * We're using PIO because this might reset the MMIO enable bit. + */ +static int rhine_reload_eeprom ( struct rhine_nic *rhn ) { + unsigned int timeout = RHINE_TIMEOUT_US; + uint8_t eeprom; + + /* Initiate reload */ + eeprom = inb ( rhn->ioaddr + RHINE_EEPROM_CTRL ); + outb ( ( eeprom | RHINE_EEPROM_CTRL_RELOAD ), + rhn->ioaddr + RHINE_EEPROM_CTRL ); + + /* Wait for reload to complete */ + while ( timeout-- ) { + udelay ( 1 ); + eeprom = inb ( rhn->ioaddr + RHINE_EEPROM_CTRL ); + if ( ! ( eeprom & RHINE_EEPROM_CTRL_RELOAD ) ) + return 0; + } + + DBGC ( rhn, "RHINE %p EEPROM reload timeout\n", rhn ); + return -ETIMEDOUT; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void rhine_check_link ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + uint8_t mii_sr; + + /* Read MII status register */ + mii_sr = readb ( rhn->regs + RHINE_MII_SR ); + DBGC ( rhn, "RHINE %p link status %02x\n", rhn, mii_sr ); + + /* Report link state */ + if ( ! ( mii_sr & RHINE_MII_SR_LINKPOLL ) ) { + netdev_link_up ( netdev ); + } else if ( mii_sr & RHINE_MII_SR_PHYERR ) { + netdev_link_err ( netdev, -EIO ); + } else { + netdev_link_down ( netdev ); + } +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Create descriptor ring + * + * @v rhn Rhine device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int rhine_create_ring ( struct rhine_nic *rhn, + struct rhine_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + struct rhine_descriptor *next; + physaddr_t address; + unsigned int i; + + /* Allocate descriptors */ + ring->desc = malloc_dma ( len, RHINE_RING_ALIGN ); + if ( ! ring->desc ) + return -ENOMEM; + + /* Initialise descriptor ring */ + memset ( ring->desc, 0, len ); + for ( i = 0 ; i < ring->count ; i++ ) { + next = &ring->desc[ ( i + 1 ) % ring->count ]; + ring->desc[i].next = cpu_to_le32 ( virt_to_bus ( next ) ); + } + + /* Program ring address */ + address = virt_to_bus ( ring->desc ); + writel ( address, rhn->regs + ring->reg ); + + DBGC ( rhn, "RHINE %p ring %02x is at [%08llx,%08llx)\n", + rhn, ring->reg, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + len ) ); + + return 0; +} + +/** + * Destroy descriptor ring + * + * @v rhn Rhine device + * @v ring Descriptor ring + */ +static void rhine_destroy_ring ( struct rhine_nic *rhn, + struct rhine_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + + /* Clear ring address */ + writel ( 0, rhn->regs + ring->reg ); + + /* Free descriptor ring */ + free_dma ( ring->desc, len ); + ring->desc = NULL; + ring->prod = 0; + ring->cons = 0; +} + +/** + * Refill RX descriptor ring + * + * @v rhn Rhine device + */ +static void rhine_refill_rx ( struct rhine_nic *rhn ) { + struct rhine_descriptor *desc; + struct io_buffer *iobuf; + unsigned int rx_idx; + physaddr_t address; + + while ( ( rhn->rx.prod - rhn->rx.cons ) < RHINE_RXDESC_NUM ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( RHINE_RX_MAX_LEN ); + if ( ! iobuf ) { + /* Wait for next refill */ + return; + } + + /* Populate next receive descriptor */ + rx_idx = ( rhn->rx.prod++ % RHINE_RXDESC_NUM ); + desc = &rhn->rx.desc[rx_idx]; + address = virt_to_bus ( iobuf->data ); + desc->buffer = cpu_to_le32 ( address ); + desc->des1 = + cpu_to_le32 ( RHINE_DES1_SIZE ( RHINE_RX_MAX_LEN - 1) | + RHINE_DES1_CHAIN | RHINE_DES1_IC ); + wmb(); + desc->des0 = cpu_to_le32 ( RHINE_DES0_OWN ); + + /* Record I/O buffer */ + rhn->rx_iobuf[rx_idx] = iobuf; + + DBGC2 ( rhn, "RHINE %p RX %d is [%llx,%llx)\n", rhn, rx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + RHINE_RX_MAX_LEN ) ); + } +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int rhine_open ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + int rc; + + /* Create transmit ring */ + if ( ( rc = rhine_create_ring ( rhn, &rhn->tx ) ) != 0 ) + goto err_create_tx; + + /* Create receive ring */ + if ( ( rc = rhine_create_ring ( rhn, &rhn->rx ) ) != 0 ) + goto err_create_rx; + + /* Set receive configuration */ + writeb ( ( RHINE_RCR_PHYS_ACCEPT | RHINE_RCR_BCAST_ACCEPT | + RHINE_RCR_RUNT_ACCEPT ), rhn->regs + RHINE_RCR ); + + /* Enable link status monitoring */ + if ( ( rc = rhine_mii_autopoll ( rhn ) ) != 0 ) + goto err_mii_autopoll; + + /* Some cards need an extra delay(observed with VT6102) */ + mdelay ( 10 ); + + /* Enable RX/TX of packets */ + writeb ( ( RHINE_CR0_STARTNIC | RHINE_CR0_RXEN | RHINE_CR0_TXEN ), + rhn->regs + RHINE_CR0 ); + + /* Enable auto polling and full duplex operation */ + rhn->cr1 = RHINE_CR1_FDX; + writeb ( rhn->cr1, rhn->regs + RHINE_CR1 ); + + /* Refill RX ring */ + rhine_refill_rx ( rhn ); + + /* Update link state */ + rhine_check_link ( netdev ); + + return 0; + + err_mii_autopoll: + rhine_destroy_ring ( rhn, &rhn->rx ); + err_create_rx: + rhine_destroy_ring ( rhn, &rhn->tx ); + err_create_tx: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void rhine_close ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + unsigned int i; + + /* Disable interrupts */ + writeb ( 0, RHINE_IMR0 ); + writeb ( 0, RHINE_IMR1 ); + + /* Stop card, clear RXON and TXON bits */ + writeb ( RHINE_CR0_STOPNIC, rhn->regs + RHINE_CR0 ); + + /* Destroy receive ring */ + rhine_destroy_ring ( rhn, &rhn->rx ); + + /* Discard any unused receive buffers */ + for ( i = 0 ; i < RHINE_RXDESC_NUM ; i++ ) { + if ( rhn->rx_iobuf[i] ) + free_iob ( rhn->rx_iobuf[i] ); + rhn->rx_iobuf[i] = NULL; + } + + /* Destroy transmit ring */ + rhine_destroy_ring ( rhn, &rhn->tx ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int rhine_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct rhine_nic *rhn = netdev->priv; + struct rhine_descriptor *desc; + physaddr_t address; + unsigned int tx_idx; + + /* Get next transmit descriptor */ + if ( ( rhn->tx.prod - rhn->tx.cons ) >= RHINE_TXDESC_NUM ) + return -ENOBUFS; + tx_idx = ( rhn->tx.prod++ % RHINE_TXDESC_NUM ); + desc = &rhn->tx.desc[tx_idx]; + + /* Pad and align packet */ + iob_pad ( iobuf, ETH_ZLEN ); + address = virt_to_bus ( iobuf->data ); + + /* Populate transmit descriptor */ + desc->buffer = cpu_to_le32 ( address ); + desc->des1 = cpu_to_le32 ( RHINE_DES1_IC | RHINE_TDES1_STP | + RHINE_TDES1_EDP | RHINE_DES1_CHAIN | + RHINE_DES1_SIZE ( iob_len ( iobuf ) ) ); + wmb(); + desc->des0 = cpu_to_le32 ( RHINE_DES0_OWN ); + wmb(); + + /* Notify card that there are packets ready to transmit */ + writeb ( ( rhn->cr1 | RHINE_CR1_TXPOLL ), rhn->regs + RHINE_CR1 ); + + DBGC2 ( rhn, "RHINE %p TX %d is [%llx,%llx)\n", rhn, tx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void rhine_poll_tx ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + struct rhine_descriptor *desc; + unsigned int tx_idx; + uint32_t des0; + + /* Check for completed packets */ + while ( rhn->tx.cons != rhn->tx.prod ) { + + /* Get next transmit descriptor */ + tx_idx = ( rhn->tx.cons % RHINE_TXDESC_NUM ); + desc = &rhn->tx.desc[tx_idx]; + + /* Stop if descriptor is still in use */ + if ( desc->des0 & cpu_to_le32 ( RHINE_DES0_OWN ) ) + return; + + /* Complete TX descriptor */ + des0 = le32_to_cpu ( desc->des0 ); + if ( des0 & RHINE_TDES0_TERR ) { + DBGC ( rhn, "RHINE %p TX %d error (DES0 %08x)\n", + rhn, tx_idx, des0 ); + netdev_tx_complete_next_err ( netdev, -EIO ); + } else { + DBGC2 ( rhn, "RHINE %p TX %d complete\n", rhn, tx_idx ); + netdev_tx_complete_next ( netdev ); + } + rhn->tx.cons++; + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void rhine_poll_rx ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + struct rhine_descriptor *desc; + struct io_buffer *iobuf; + unsigned int rx_idx; + uint32_t des0; + size_t len; + + /* Check for received packets */ + while ( rhn->rx.cons != rhn->rx.prod ) { + + /* Get next receive descriptor */ + rx_idx = ( rhn->rx.cons % RHINE_RXDESC_NUM ); + desc = &rhn->rx.desc[rx_idx]; + + /* Stop if descriptor is still in use */ + if ( desc->des0 & cpu_to_le32 ( RHINE_DES0_OWN ) ) + return; + + /* Populate I/O buffer */ + iobuf = rhn->rx_iobuf[rx_idx]; + rhn->rx_iobuf[rx_idx] = NULL; + des0 = le32_to_cpu ( desc->des0 ); + len = ( RHINE_DES0_GETSIZE ( des0 ) - 4 /* strip CRC */ ); + iob_put ( iobuf, len ); + + /* Hand off to network stack */ + if ( des0 & RHINE_RDES0_RXOK ) { + DBGC2 ( rhn, "RHINE %p RX %d complete (length %zd)\n", + rhn, rx_idx, len ); + netdev_rx ( netdev, iobuf ); + } else { + DBGC ( rhn, "RHINE %p RX %d error (length %zd, DES0 " + "%08x)\n", rhn, rx_idx, len, des0 ); + netdev_rx_err ( netdev, iobuf, -EIO ); + } + rhn->rx.cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void rhine_poll ( struct net_device *netdev ) { + struct rhine_nic *rhn = netdev->priv; + uint8_t isr0; + uint8_t isr1; + + /* Read and acknowledge interrupts */ + isr0 = readb ( rhn->regs + RHINE_ISR0 ); + isr1 = readb ( rhn->regs + RHINE_ISR1 ); + if ( isr0 ) + writeb ( isr0, rhn->regs + RHINE_ISR0 ); + if ( isr1 ) + writeb ( isr1, rhn->regs + RHINE_ISR1 ); + + /* Report unexpected errors */ + if ( ( isr0 & ( RHINE_ISR0_MIBOVFL | RHINE_ISR0_PCIERR | + RHINE_ISR0_RXRINGERR | RHINE_ISR0_TXRINGERR ) ) || + ( isr1 & ( RHINE_ISR1_GPI | RHINE_ISR1_TXABORT | + RHINE_ISR1_RXFIFOOVFL | RHINE_ISR1_RXFIFOUNFL | + RHINE_ISR1_TXFIFOUNFL ) ) ) { + DBGC ( rhn, "RHINE %p unexpected ISR0 %02x ISR1 %02x\n", + rhn, isr0, isr1 ); + /* Report as a TX error */ + netdev_tx_err ( netdev, NULL, -EIO ); + } + + /* Poll for TX completions, if applicable */ + if ( isr0 & ( RHINE_ISR0_TXDONE | RHINE_ISR0_TXERR ) ) + rhine_poll_tx ( netdev ); + + /* Poll for RX completions, if applicable */ + if ( isr0 & ( RHINE_ISR0_RXDONE | RHINE_ISR0_RXERR ) ) + rhine_poll_rx ( netdev ); + + /* Handle RX buffer exhaustion */ + if ( isr1 & RHINE_ISR1_RXNOBUF ) { + rhine_poll_rx ( netdev ); + netdev_rx_err ( netdev, NULL, -ENOBUFS ); + } + + /* Check link state, if applicable */ + if ( isr1 & RHINE_ISR1_PORTSTATE ) + rhine_check_link ( netdev ); + + /* Refill RX ring */ + rhine_refill_rx ( rhn ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void rhine_irq ( struct net_device *netdev, int enable ) { + struct rhine_nic *nic = netdev->priv; + + if ( enable ) { + /* Enable interrupts */ + writeb ( 0xff, nic->regs + RHINE_IMR0 ); + writeb ( 0xff, nic->regs + RHINE_IMR1 ); + } else { + /* Disable interrupts */ + writeb ( 0, nic->regs + RHINE_IMR0 ); + writeb ( 0, nic->regs + RHINE_IMR1 ); + } +} + +/** Rhine network device operations */ +static struct net_device_operations rhine_operations = { + .open = rhine_open, + .close = rhine_close, + .transmit = rhine_transmit, + .poll = rhine_poll, + .irq = rhine_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int rhine_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct rhine_nic *rhn; + uint8_t revision; + unsigned int i; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *rhn ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &rhine_operations ); + rhn = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( rhn, 0, sizeof ( *rhn ) ); + rhine_init_ring ( &rhn->tx, RHINE_TXDESC_NUM, RHINE_TXQUEUE_BASE ); + rhine_init_ring ( &rhn->rx, RHINE_RXDESC_NUM, RHINE_RXQUEUE_BASE ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + rhn->regs = ioremap ( pci->membase, RHINE_BAR_SIZE ); + rhn->ioaddr = pci->ioaddr; + DBGC ( rhn, "RHINE %p regs at %08lx, I/O at %04lx\n", rhn, + pci->membase, pci->ioaddr ); + + /* Reset the NIC */ + if ( ( rc = rhine_reset ( rhn ) ) != 0 ) + goto err_reset; + + /* Reload EEPROM */ + if ( ( rc = rhine_reload_eeprom ( rhn ) ) != 0 ) + goto err_reload_eeprom; + + /* Read card revision and enable MMIO */ + pci_read_config_byte ( pci, PCI_REVISION, &revision ); + DBGC ( rhn, "RHINE %p revision %#02x detected\n", rhn, revision ); + rhine_enable_mmio ( rhn, revision ); + + /* Read MAC address */ + for ( i = 0 ; i < ETH_ALEN ; i++ ) + netdev->hw_addr[i] = readb ( rhn->regs + RHINE_MAC + i ); + + /* Initialise and reset MII interface */ + mii_init ( &rhn->mii, &rhine_mii_operations ); + if ( ( rc = mii_reset ( &rhn->mii ) ) != 0 ) { + DBGC ( rhn, "RHINE %p could not reset MII: %s\n", + rhn, strerror ( rc ) ); + goto err_mii_reset; + } + DBGC ( rhn, "RHINE PHY vendor %04x device %04x\n", + rhine_mii_read ( &rhn->mii, 0x02 ), + rhine_mii_read ( &rhn->mii, 0x03 ) ); + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + rhine_check_link ( netdev ); + + return 0; + + err_register_netdev: + err_mii_reset: + err_reload_eeprom: + rhine_reset ( rhn ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void rhine_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct rhine_nic *nic = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + rhine_reset ( nic ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Rhine PCI device IDs */ +static struct pci_device_id rhine_nics[] = { + PCI_ROM ( 0x1106, 0x3065, "dlink-530tx", "VIA VT6102", 0 ), + PCI_ROM ( 0x1106, 0x3106, "vt6105", "VIA VT6105", 0 ), + PCI_ROM ( 0x1106, 0x3043, "dlink-530tx-old", "VIA VT3043", 0 ), + PCI_ROM ( 0x1106, 0x3053, "vt6105m", "VIA VT6105M", 0 ), + PCI_ROM ( 0x1106, 0x6100, "via-rhine-old", "VIA 86C100A", 0 ) +}; + +/** Rhine PCI driver */ +struct pci_driver rhine_driver __pci_driver = { + .ids = rhine_nics, + .id_count = ( sizeof ( rhine_nics ) / sizeof ( rhine_nics[0] ) ), + .probe = rhine_probe, + .remove = rhine_remove, +}; diff --git a/roms/ipxe/src/drivers/net/rhine.h b/roms/ipxe/src/drivers/net/rhine.h new file mode 100644 index 000000000..b26f9ae78 --- /dev/null +++ b/roms/ipxe/src/drivers/net/rhine.h @@ -0,0 +1,250 @@ +#ifndef _RHINE_H +#define _RHINE_H + +/** @file + * + * VIA Rhine network driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** Rhine BAR size */ +#define RHINE_BAR_SIZE 256 + +/** Default timeout */ +#define RHINE_TIMEOUT_US 10000 + +/** Rhine descriptor format */ +struct rhine_descriptor { + uint32_t des0; + uint32_t des1; + uint32_t buffer; + uint32_t next; +} __attribute__ (( packed )); + +#define RHINE_DES0_OWN (1 << 31) /*< Owned descriptor */ +#define RHINE_DES1_IC (1 << 23) /*< Generate interrupt */ +#define RHINE_TDES1_EDP (1 << 22) /*< End of packet */ +#define RHINE_TDES1_STP (1 << 21) /*< Start of packet */ +#define RHINE_TDES1_TCPCK (1 << 20) /*< HW TCP checksum */ +#define RHINE_TDES1_UDPCK (1 << 19) /*< HW UDP checksum */ +#define RHINE_TDES1_IPCK (1 << 18) /*< HW IP checksum */ +#define RHINE_TDES1_TAG (1 << 17) /*< Tagged frame */ +#define RHINE_TDES1_CRC (1 << 16) /*< No CRC */ +#define RHINE_DES1_CHAIN (1 << 15) /*< Chained descriptor */ +#define RHINE_DES1_SIZE(_x) ((_x) & 0x7ff) /*< Frame size */ +#define RHINE_DES0_GETSIZE(_x) (((_x) >> 16) & 0x7ff) + +#define RHINE_RDES0_RXOK (1 << 15) +#define RHINE_RDES0_VIDHIT (1 << 14) +#define RHINE_RDES0_MAR (1 << 13) +#define RHINE_RDES0_BAR (1 << 12) +#define RHINE_RDES0_PHY (1 << 11) +#define RHINE_RDES0_CHN (1 << 10) +#define RHINE_RDES0_STP (1 << 9) +#define RHINE_RDES0_EDP (1 << 8) +#define RHINE_RDES0_BUFF (1 << 7) +#define RHINE_RDES0_FRAG (1 << 6) +#define RHINE_RDES0_RUNT (1 << 5) +#define RHINE_RDES0_LONG (1 << 4) +#define RHINE_RDES0_FOV (1 << 3) +#define RHINE_RDES0_FAE (1 << 2) +#define RHINE_RDES0_CRCE (1 << 1) +#define RHINE_RDES0_RERR (1 << 0) + +#define RHINE_TDES0_TERR (1 << 15) +#define RHINE_TDES0_UDF (1 << 11) +#define RHINE_TDES0_CRS (1 << 10) +#define RHINE_TDES0_OWC (1 << 9) +#define RHINE_TDES0_ABT (1 << 8) +#define RHINE_TDES0_CDH (1 << 7) +#define RHINE_TDES0_COLS (1 << 4) +#define RHINE_TDES0_NCR(_x) ((_x) & 0xf) + +#define RHINE_RING_ALIGN 4 + +/** Rhine descriptor rings sizes */ +#define RHINE_RXDESC_NUM 4 +#define RHINE_TXDESC_NUM 8 +#define RHINE_RX_MAX_LEN 1536 + +/** Rhine MAC address registers */ +#define RHINE_MAC 0x00 + +/** Receive control register */ +#define RHINE_RCR 0x06 +#define RHINE_RCR_FIFO_TRSH(_x) (((_x) & 0x7) << 5) /*< RX FIFO threshold */ +#define RHINE_RCR_PHYS_ACCEPT (1 << 4) /*< Accept matching PA */ +#define RHINE_RCR_BCAST_ACCEPT (1 << 3) /*< Accept broadcast */ +#define RHINE_RCR_MCAST_ACCEPT (1 << 2) /*< Accept multicast */ +#define RHINE_RCR_RUNT_ACCEPT (1 << 1) /*< Accept runt frames */ +#define RHINE_RCR_ERR_ACCEPT (1 << 0) /*< Accept erroneous frames */ + +/** Transmit control register */ +#define RHINE_TCR 0x07 +#define RHINE_TCR_LOOPBACK(_x) (((_x) & 0x3) << 1) /*< Transmit loop mode */ +#define RHINE_TCR_TAGGING (1 << 0) /*< 802.1P/Q packet tagging */ + +/** Command 0 register */ +#define RHINE_CR0 0x08 +#define RHINE_CR0_RXSTART (1 << 6) +#define RHINE_CR0_TXSTART (1 << 5) +#define RHINE_CR0_TXEN (1 << 4) /*< Transmit enable */ +#define RHINE_CR0_RXEN (1 << 3) /*< Receive enable */ +#define RHINE_CR0_STOPNIC (1 << 2) /*< Stop NIC */ +#define RHINE_CR0_STARTNIC (1 << 1) /*< Start NIC */ + +/** Command 1 register */ +#define RHINE_CR1 0x09 +#define RHINE_CR1_RESET (1 << 7) /*< Software reset */ +#define RHINE_CR1_RXPOLL (1 << 6) /*< Receive poll demand */ +#define RHINE_CR1_TXPOLL (1 << 5) /*< Xmit poll demand */ +#define RHINE_CR1_AUTOPOLL (1 << 3) /*< Disable autopoll */ +#define RHINE_CR1_FDX (1 << 2) /*< Full duplex */ +#define RIHNE_CR1_ACCUNI (1 << 1) /*< Disable accept unicast */ + +/** Transmit queue wake register */ +#define RHINE_TXQUEUE_WAKE 0x0a + +/** Interrupt service 0 */ +#define RHINE_ISR0 0x0c +#define RHINE_ISR0_MIBOVFL (1 << 7) +#define RHINE_ISR0_PCIERR (1 << 6) +#define RHINE_ISR0_RXRINGERR (1 << 5) +#define RHINE_ISR0_TXRINGERR (1 << 4) +#define RHINE_ISR0_TXERR (1 << 3) +#define RHINE_ISR0_RXERR (1 << 2) +#define RHINE_ISR0_TXDONE (1 << 1) +#define RHINE_ISR0_RXDONE (1 << 0) + +/** Interrupt service 1 */ +#define RHINE_ISR1 0x0d +#define RHINE_ISR1_GPI (1 << 7) +#define RHINE_ISR1_PORTSTATE (1 << 6) +#define RHINE_ISR1_TXABORT (1 << 5) +#define RHINE_ISR1_RXNOBUF (1 << 4) +#define RHINE_ISR1_RXFIFOOVFL (1 << 3) +#define RHINE_ISR1_RXFIFOUNFL (1 << 2) +#define RHINE_ISR1_TXFIFOUNFL (1 << 1) +#define RHINE_ISR1_EARLYRX (1 << 0) + +/** Interrupt enable mask register 0 */ +#define RHINE_IMR0 0x0e + +/** Interrupt enable mask register 1 */ +#define RHINE_IMR1 0x0f + +/** RX queue descriptor base address */ +#define RHINE_RXQUEUE_BASE 0x18 + +/** TX queue 0 descriptor base address */ +#define RHINE_TXQUEUE_BASE 0x1c + +/** MII configuration */ +#define RHINE_MII_CFG 0x6c + +/** MII status register */ +#define RHINE_MII_SR 0x6d +#define RHINE_MII_SR_PHYRST (1 << 7) /*< PHY reset */ +#define RHINE_MII_SR_LINKNWAY (1 << 4) /*< Link status after N-Way */ +#define RHINE_MII_SR_PHYERR (1 << 3) /*< PHY device error */ +#define RHINE_MII_SR_DUPLEX (1 << 2) /*< Duplex mode after N-Way */ +#define RHINE_MII_SR_LINKPOLL (1 << 1) /*< Link status after poll */ +#define RHINE_MII_SR_LINKSPD (1 << 0) /*< Link speed after N-Way */ + +/** MII bus control 0 register */ +#define RHINE_MII_BCR0 0x6e + +/** MII bus control 1 register */ +#define RHINE_MII_BCR1 0x6f + +/** MII control register */ +#define RHINE_MII_CR 0x70 +#define RHINE_MII_CR_AUTOPOLL (1 << 7) /*< MII auto polling */ +#define RHINE_MII_CR_RDEN (1 << 6) /*< PHY read enable */ +#define RHINE_MII_CR_WREN (1 << 5) /*< PHY write enable */ +#define RHINE_MII_CR_DIRECT (1 << 4) /*< Direct programming mode */ +#define RHINE_MII_CR_MDIOOUT (1 << 3) /*< MDIO output enable */ + +/** MII port address */ +#define RHINE_MII_ADDR 0x71 +#define RHINE_MII_ADDR_MSRCEN (1 << 6) +#define RHINE_MII_ADDR_MDONE (1 << 5) + +/** MII read/write data */ +#define RHINE_MII_RDWR 0x72 + +/** EERPOM control/status register */ +#define RHINE_EEPROM_CTRL 0x74 +#define RHINE_EEPROM_CTRL_STATUS (1 << 7) /*< EEPROM status */ +#define RHINE_EEPROM_CTRL_RELOAD (1 << 5) /*< EEPROM reload */ + +/** Chip configuration A */ +#define RHINE_CHIPCFG_A 0x78 +/* MMIO enable. Only valid for Rhine I. Reserved on later boards */ +#define RHINE_CHIPCFG_A_MMIO (1 << 5) + +/** Chip configuration B */ +#define RHINE_CHIPCFG_B 0x79 + +/** Chip configuation C */ +#define RHINE_CHIPCFG_C 0x7a + +/** Chip configuration D */ +#define RHINE_CHIPCFG_D 0x7b +/* MMIO enable. Only valid on Rhine II and later. GPIOEN on Rhine I */ +#define RHINE_CHIPCFG_D_MMIO (1 << 7) + +#define RHINE_REVISION_OLD 0x20 + +/** A VIA Rhine descriptor ring */ +struct rhine_ring { + /** Descriptors */ + struct rhine_descriptor *desc; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; + + /** Number of descriptors */ + unsigned int count; + /** Register address */ + unsigned int reg; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v count Number of descriptors (must be a power of 2) + * @v reg Register address + */ +static inline __attribute__ (( always_inline)) void +rhine_init_ring ( struct rhine_ring *ring, unsigned int count, + unsigned int reg ) { + ring->count = count; + ring->reg = reg; +} + +/** A VIA Rhine network card */ +struct rhine_nic { + /** I/O address (some PIO access is always required) */ + unsigned long ioaddr; + /** Registers */ + void *regs; + /** Cached value of CR1 (to avoid read-modify-write on fast path) */ + uint8_t cr1; + + /** MII interface */ + struct mii_interface mii; + + /** Transmit descriptor ring */ + struct rhine_ring tx; + /** Receive descriptor ring */ + struct rhine_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[RHINE_RXDESC_NUM]; +}; + +#endif /* _RHINE_H */ diff --git a/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c b/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c index 50cc84add..ae92531ce 100644 --- a/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c +++ b/roms/ipxe/src/drivers/net/rtl818x/rtl8185_rtl8225.c @@ -71,7 +71,7 @@ static void rtl8225_write(struct net80211_device *dev, u8 addr, u16 data) udelay(10); for (i = 15; i >= 0; i--) { - u16 reg = reg80 | !!(bangdata & (1 << i)); + u16 reg = ( reg80 | ( ( bangdata >> i ) & 1 ) ); if (i & 1) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); diff --git a/roms/ipxe/src/drivers/net/sis900.c b/roms/ipxe/src/drivers/net/sis900.c index 75e9ef962..724515672 100644 --- a/roms/ipxe/src/drivers/net/sis900.c +++ b/roms/ipxe/src/drivers/net/sis900.c @@ -111,7 +111,7 @@ static struct mii_chip_info { // {"NS 83851 PHY",0x2000, 0x5C20, MIX }, {"RTL 8201 10/100Mbps Phyceiver" , 0x0000, 0x8200,rtl8201_read_mode}, {"VIA 6103 10/100Mbps Phyceiver", 0x0101, 0x8f20,vt6103_read_mode}, - {0,0,0,0} + {NULL,0,0,NULL} }; static struct mii_phy { diff --git a/roms/ipxe/src/drivers/net/tg3/tg3.h b/roms/ipxe/src/drivers/net/tg3/tg3.h index e84eed879..660368394 100644 --- a/roms/ipxe/src/drivers/net/tg3/tg3.h +++ b/roms/ipxe/src/drivers/net/tg3/tg3.h @@ -298,6 +298,7 @@ #define ASIC_REV_57780 0x57780 #define ASIC_REV_5717 0x5717 #define ASIC_REV_57765 0x57785 +#define ASIC_REV_57766 0x57766 #define ASIC_REV_5719 0x5719 #define ASIC_REV_5720 0x5720 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) @@ -1215,6 +1216,8 @@ #define TG3_CPMU_LNK_AWARE_PWRMD 0x00003610 #define CPMU_LNK_AWARE_MACCLK_MASK 0x001f0000 #define CPMU_LNK_AWARE_MACCLK_6_25 0x00130000 + +#define TG3_CPMU_D0_CLCK_POLICY 0x00003614 /* 0x3614 --> 0x361c unused */ #define TG3_CPMU_HST_ACC 0x0000361c @@ -1225,6 +1228,9 @@ #define TG3_CPMU_CLCK_ORIDE 0x00003624 #define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 +#define TG3_CPMU_CLCK_ORIDE_EN 0x00003628 +#define CPMU_CLCK_ORIDE_MAC_CLCK_ORIDE_EN 0x00002000 + #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 diff --git a/roms/ipxe/src/drivers/net/tg3/tg3_hw.c b/roms/ipxe/src/drivers/net/tg3/tg3_hw.c index 9ae007c2f..3a481aba3 100644 --- a/roms/ipxe/src/drivers/net/tg3/tg3_hw.c +++ b/roms/ipxe/src/drivers/net/tg3/tg3_hw.c @@ -322,7 +322,7 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp) } if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) && - tg3_flag(tp, 5750_PLUS)) + tg3_flag(tp, ENABLE_ASF)) tg3_flag_set(tp, ENABLE_APE); if (cfg2 & (1 << 17)) @@ -466,6 +466,7 @@ int tg3_get_invariants(struct tg3 *tp) tg3_flag_set(tp, 5717_PLUS); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766 || tg3_flag(tp, 5717_PLUS)) tg3_flag_set(tp, 57765_PLUS); @@ -1465,6 +1466,13 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN); } + if (tg3_flag(tp, CPMU_PRESENT)) { + tw32(TG3_CPMU_D0_CLCK_POLICY, 0); + val = tr32(TG3_CPMU_CLCK_ORIDE_EN); + tw32(TG3_CPMU_CLCK_ORIDE_EN, + val | CPMU_CLCK_ORIDE_MAC_CLCK_ORIDE_EN); + } + return 0; } diff --git a/roms/ipxe/src/drivers/net/tlan.c b/roms/ipxe/src/drivers/net/tlan.c index 74398df42..7742f6d80 100644 --- a/roms/ipxe/src/drivers/net/tlan.c +++ b/roms/ipxe/src/drivers/net/tlan.c @@ -94,7 +94,7 @@ static void TLan_MiiWriteReg(struct nic *nic __unused, u16, u16, u16); static const char *media[] = { "10BaseT-HD ", "10BaseT-FD ", "100baseTx-HD ", - "100baseTx-FD", "100baseT4", 0 + "100baseTx-FD", "100baseT4", NULL }; /* This much match tlan_pci_tbl[]! */ @@ -164,7 +164,7 @@ static const struct pci_id_info tlan_pci_tbl[] = { {"Compaq NetFlex-3/E", 0, /* EISA card */ {0, 0, 0, 0, 0, 0}, TLAN_ADAPTER_ACTIVITY_LED, 0x83}, - {0, 0, + {NULL, 0, {0, 0, 0, 0, 0, 0}, 0, 0}, }; diff --git a/roms/ipxe/src/drivers/net/tulip.c b/roms/ipxe/src/drivers/net/tulip.c index 7a23b7e9e..e4e6ffa87 100644 --- a/roms/ipxe/src/drivers/net/tulip.c +++ b/roms/ipxe/src/drivers/net/tulip.c @@ -228,7 +228,7 @@ static const struct pci_id_info pci_id_tbl[] = { TULIP_IOTYPE, TULIP_SIZE, COMET }, { "SG Thomson STE10/100A", { 0x2774104a, 0xffffffff, 0, 0, 0, 0 }, TULIP_IOTYPE, 256, COMET }, /*Ramesh Chander*/ - { 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 }, + { NULL, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 }, }; enum tbl_flag { @@ -264,7 +264,7 @@ static struct tulip_chip_table { { "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY }, { "SGThomson STE10/100A", HAS_MII | MC_HASH_ONLY }, /*Ramesh Chander*/ - { 0, 0 }, + { NULL, 0 }, }; /* A full-duplex map for media types. */ @@ -475,7 +475,7 @@ static struct fixups { 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ }}, - {0, 0, 0, 0, {}}}; + {NULL, 0, 0, 0, {}}}; static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; @@ -720,7 +720,7 @@ static void parse_eeprom(struct nic *nic) whereami("parse_eeprom\n"); - tp->mtable = 0; + tp->mtable = NULL; /* Detect an old-style (SA only) EEPROM layout: memcmp(ee_data, ee_data+16, 8). */ for (i = 0; i < 8; i ++) diff --git a/roms/ipxe/src/drivers/net/velocity.c b/roms/ipxe/src/drivers/net/velocity.c new file mode 100644 index 000000000..6d5185209 --- /dev/null +++ b/roms/ipxe/src/drivers/net/velocity.c @@ -0,0 +1,807 @@ +/* + * Copyright (C) 2012 Adrian Jamróz <adrian.jamroz@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/netdevice.h> +#include <ipxe/ethernet.h> +#include <ipxe/if_ether.h> +#include <ipxe/iobuf.h> +#include <ipxe/malloc.h> +#include <ipxe/pci.h> +#include <ipxe/mii.h> +#include "velocity.h" + +#define velocity_setbit(_reg, _mask) writeb ( readb ( _reg ) | _mask, _reg ) +#define virt_to_le32bus(x) ( cpu_to_le32 ( virt_to_bus ( x ) ) ) + +/** @file + * + * VIA Velocity network driver + * + */ + +/****************************************************************************** + * + * MII interface + * + ****************************************************************************** + */ + +/** + * Stop MII auto-polling + * + * @v vlc Velocity device + * @ret rc Return status code + */ +static int velocity_autopoll_stop ( struct velocity_nic *vlc ) { + int timeout = VELOCITY_TIMEOUT_US; + + /* Disable MII auto polling */ + writeb ( 0, vlc->regs + VELOCITY_MIICR ); + + /* Wait for disabling to take effect */ + while ( timeout-- ) { + udelay ( 1 ); + if ( readb ( vlc->regs + VELOCITY_MIISR ) & + VELOCITY_MIISR_IDLE ) + return 0; + } + + DBGC ( vlc, "MII autopoll stop timeout\n" ); + return -ETIMEDOUT; +} + +/** + * Start MII auto-polling + * + * @v vlc Velocity device + * @ret rc Return status code + */ +static int velocity_autopoll_start ( struct velocity_nic *vlc ) { + int timeout = VELOCITY_TIMEOUT_US; + + /* Enable MII auto polling */ + writeb ( VELOCITY_MIICR_MAUTO, vlc->regs + VELOCITY_MIICR ); + + /* Wait for enabling to take effect */ + while ( timeout-- ) { + udelay ( 1 ); + if ( ( readb ( vlc->regs + VELOCITY_MIISR ) & + VELOCITY_MIISR_IDLE ) == 0 ) + return 0; + } + + DBGC ( vlc, "MII autopoll start timeout\n" ); + return -ETIMEDOUT; +} + +/** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret value Data read, or negative error + */ +static int velocity_mii_read ( struct mii_interface *mii, unsigned int reg ) { + struct velocity_nic *vlc = + container_of ( mii, struct velocity_nic, mii ); + int timeout = VELOCITY_TIMEOUT_US; + int result; + + DBGC2 ( vlc, "VELOCITY %p MII read reg %d\n", vlc, reg ); + + /* Disable autopolling before we can access MII */ + velocity_autopoll_stop ( vlc ); + + /* Send read command and address */ + writeb ( reg, vlc->regs + VELOCITY_MIIADDR ); + velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_RCMD ); + + /* Wait for read to complete */ + while ( timeout-- ) { + udelay ( 1 ); + if ( ( readb ( vlc->regs + VELOCITY_MIICR ) & + VELOCITY_MIICR_RCMD ) == 0 ) { + result = readw ( vlc->regs + VELOCITY_MIIDATA ); + velocity_autopoll_start ( vlc ); + return result; + } + } + + /* Restart autopolling */ + velocity_autopoll_start ( vlc ); + + DBGC ( vlc, "MII read timeout\n" ); + return -ETIMEDOUT; +} + +/** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ +static int velocity_mii_write ( struct mii_interface *mii, unsigned int reg, + unsigned int data) { + struct velocity_nic *vlc = + container_of ( mii, struct velocity_nic, mii ); + int timeout = VELOCITY_TIMEOUT_US; + + DBGC2 ( vlc, "VELOCITY %p MII write reg %d data 0x%04x\n", + vlc, reg, data ); + + /* Disable autopolling before we can access MII */ + velocity_autopoll_stop ( vlc ); + + /* Send write command, data and destination register */ + writeb ( reg, vlc->regs + VELOCITY_MIIADDR ); + writew ( data, vlc->regs + VELOCITY_MIIDATA ); + velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_WCMD ); + + /* Wait for write to complete */ + while ( timeout-- ) { + udelay ( 1 ); + if ( ( readb ( vlc->regs + VELOCITY_MIICR ) & + VELOCITY_MIICR_WCMD ) == 0 ) { + velocity_autopoll_start ( vlc ); + return 0; + } + } + + /* Restart autopolling */ + velocity_autopoll_start ( vlc ); + + DBGC ( vlc, "MII write timeout\n" ); + return -ETIMEDOUT; +} + +/** Velocity MII operations */ +static struct mii_operations velocity_mii_operations = { + .read = velocity_mii_read, + .write = velocity_mii_write, +}; + +/** + * Set Link speed + * + * @v vlc Velocity device + */ +static void velocity_set_link ( struct velocity_nic *vlc ) { + int tmp; + + /* Advertise 1000MBit */ + tmp = velocity_mii_read ( &vlc->mii, MII_CTRL1000 ); + tmp |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; + velocity_mii_write ( &vlc->mii, MII_CTRL1000, tmp ); + + /* Enable GBit operation in MII Control Register */ + tmp = velocity_mii_read ( &vlc->mii, MII_BMCR ); + tmp |= BMCR_SPEED1000; + velocity_mii_write ( &vlc->mii, MII_BMCR, tmp ); +} + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reload eeprom contents + * + * @v vlc Velocity device + */ +static int velocity_reload_eeprom ( struct velocity_nic *vlc ) { + int timeout = VELOCITY_TIMEOUT_US; + + /* Initiate reload */ + velocity_setbit ( vlc->regs + VELOCITY_EECSR, VELOCITY_EECSR_RELOAD ); + + /* Wait for reload to complete */ + while ( timeout-- ) { + udelay ( 1 ); + if ( ( readb ( vlc->regs + VELOCITY_EECSR ) & + VELOCITY_EECSR_RELOAD ) == 0 ) + return 0; + } + + DBGC ( vlc, "VELOCITY %p EEPROM reload timeout\n", vlc ); + return -ETIMEDOUT; +} + +/** + * Reset hardware + * + * @v vlc Velocity device + * @ret rc Return status code + */ +static int velocity_reset ( struct velocity_nic *vlc ) { + int timeout = VELOCITY_TIMEOUT_US; + uint8_t tmp; + + DBGC ( vlc, "VELOCITY %p reset\n", vlc ); + + /* clear sticky Power state bits */ + tmp = readb ( vlc->regs + VELOCITY_STICKY ); + tmp &= ~( VELOCITY_STICKY_DS0 | VELOCITY_STICKY_DS1 ); + writeb ( tmp, vlc->regs + VELOCITY_STICKY ); + + /* clear PACPI, which might have been enabled by the EEPROM reload */ + tmp = readb ( vlc->regs + VELOCITY_CFGA ); + tmp &= ~VELOCITY_CFGA_PACPI; + writeb ( tmp, vlc->regs + VELOCITY_CFGA ); + + velocity_setbit ( vlc->regs + VELOCITY_CRS1, VELOCITY_CR1_SFRST ); + + /* Wait for reset to complete */ + while ( timeout-- ) { + udelay ( 1 ); + if ( ( readb ( vlc->regs + VELOCITY_CRS1 ) & + VELOCITY_CR1_SFRST ) == 0 ) + return 0; + } + + return -EINVAL; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void velocity_check_link ( struct net_device *netdev ) { + struct velocity_nic *vlc = netdev->priv; + + if ( readb ( vlc->regs + VELOCITY_PHYSTS0 ) & VELOCITY_PHYSTS0_LINK ) { + netdev_link_up ( netdev ); + DBGC ( vlc, "VELOCITY %p link up\n", vlc ); + } else { + netdev_link_down ( netdev ); + DBGC ( vlc, "VELOCITY %p link down\n", vlc ); + } + + /* The card disables auto-poll after a link change */ + velocity_autopoll_start ( vlc ); +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Allocate descriptor rings + * + * @v vlc Velocity device + * @ret rc Return status code + */ +static int velocity_alloc_rings ( struct velocity_nic *vlc ) { + int rc = 0; + + /* Allocate RX descriptor ring */ + vlc->rx_prod = 0; + vlc->rx_cons = 0; + vlc->rx_commit = 0; + vlc->rx_ring = malloc_dma ( VELOCITY_RXDESC_SIZE, VELOCITY_RING_ALIGN ); + if ( ! vlc->rx_ring ) + return -ENOMEM; + + memset ( vlc->rx_ring, 0, VELOCITY_RXDESC_SIZE ); + + DBGC2 ( vlc, "VELOCITY %p RX ring start address: %p(phys: %#08lx)\n", + vlc, vlc->rx_ring, virt_to_bus ( vlc->rx_ring ) ); + + /* Allocate TX descriptor ring */ + vlc->tx_prod = 0; + vlc->tx_cons = 0; + vlc->tx_ring = malloc_dma ( VELOCITY_TXDESC_SIZE, VELOCITY_RING_ALIGN ); + if ( ! vlc->tx_ring ) { + rc = -ENOMEM; + goto err_tx_alloc; + } + + memset ( vlc->tx_ring, 0, VELOCITY_TXDESC_SIZE ); + + /* Send RX ring to the card */ + writel ( virt_to_bus ( vlc->rx_ring ), + vlc->regs + VELOCITY_RXDESC_ADDR_LO ); + writew ( VELOCITY_RXDESC_NUM - 1, vlc->regs + VELOCITY_RXDESCNUM ); + + /* Send TX ring to the card */ + writel ( virt_to_bus ( vlc->tx_ring ), + vlc->regs + VELOCITY_TXDESC_ADDR_LO0 ); + writew ( VELOCITY_TXDESC_NUM - 1, vlc->regs + VELOCITY_TXDESCNUM ); + + DBGC2 ( vlc, "VELOCITY %p TX ring start address: %p(phys: %#08lx)\n", + vlc, vlc->tx_ring, virt_to_bus ( vlc->tx_ring ) ); + + return 0; + +err_tx_alloc: + free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); + return rc; +} + +/** + * Refill receive descriptor ring + * + * @v vlc Velocity device + */ +static void velocity_refill_rx ( struct velocity_nic *vlc ) { + struct velocity_rx_descriptor *desc; + struct io_buffer *iobuf; + int rx_idx, i = 0; + + /* Check for new packets */ + while ( ( vlc->rx_prod - vlc->rx_cons ) < VELOCITY_RXDESC_NUM ) { + iobuf = alloc_iob ( VELOCITY_RX_MAX_LEN ); + + /* Memory pressure: try again next poll */ + if ( ! iobuf ) + break; + + rx_idx = ( vlc->rx_prod++ % VELOCITY_RXDESC_NUM ); + desc = &vlc->rx_ring[rx_idx]; + + /* Set descrptor fields */ + desc->des1 = 0; + desc->addr = virt_to_le32bus ( iobuf-> data ); + desc->des2 = cpu_to_le32 ( + VELOCITY_DES2_SIZE ( VELOCITY_RX_MAX_LEN - 1 ) | + VELOCITY_DES2_IC ); + + vlc->rx_buffs[rx_idx] = iobuf; + i++; + + /* Return RX descriptors in blocks of 4 (hw requirement) */ + if ( rx_idx % 4 == 3 ) { + int j; + for (j = 0; j < 4; j++) { + desc = &vlc->rx_ring[rx_idx - j]; + desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN ); + } + vlc->rx_commit += 4; + } + } + + wmb(); + + if ( vlc->rx_commit ) { + writew ( vlc->rx_commit, + vlc->regs + VELOCITY_RXDESC_RESIDUECNT ); + vlc->rx_commit = 0; + } + + if ( i > 0 ) + DBGC2 ( vlc, "VELOCITY %p refilled %d RX descriptors\n", + vlc, i ); +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int velocity_open ( struct net_device *netdev ) { + struct velocity_nic *vlc = netdev->priv; + int rc; + + DBGC ( vlc, "VELOCITY %p open\n", vlc ); + DBGC ( vlc, "VELOCITY %p regs at: %p\n", vlc, vlc->regs ); + + /* Allocate descriptor rings */ + if ( ( rc = velocity_alloc_rings ( vlc ) ) != 0 ) + return rc; + + velocity_refill_rx ( vlc ); + + /* Enable TX/RX queue */ + writew ( VELOCITY_TXQCSRS_RUN0, vlc->regs + VELOCITY_TXQCSRS ); + writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK, + vlc->regs + VELOCITY_RXQCSRS ); + + /* Enable interrupts */ + writeb ( 0xff, vlc->regs + VELOCITY_IMR0 ); + writeb ( 0xff, vlc->regs + VELOCITY_IMR1 ); + + /* Start MAC */ + writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRC0 ); + writeb ( VELOCITY_CR1_DPOLL, vlc->regs + VELOCITY_CRC0 ); + writeb ( VELOCITY_CR0_START | VELOCITY_CR0_TXON | VELOCITY_CR0_RXON, + vlc->regs + VELOCITY_CRS0 ); + + /* Receive all packets */ + writeb ( 0xff, vlc->regs + VELOCITY_RCR ); + + /* Set initial link state */ + velocity_check_link ( netdev ); + + velocity_autopoll_start ( vlc ); + + DBGC2 ( vlc, "VELOCITY %p CR3 %02x\n", + vlc, readb ( vlc->regs + 0x0B ) ); + + return 0; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void velocity_close ( struct net_device *netdev ) { + struct velocity_nic *vlc = netdev->priv; + int i; + + /* Stop NIC */ + writeb ( VELOCITY_CR0_TXON | VELOCITY_CR0_RXON, + vlc->regs + VELOCITY_CRC0 ); + writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRS0 ); + + /* Clear RX ring information */ + writel ( 0, vlc->regs + VELOCITY_RXDESC_ADDR_LO ); + writew ( 0, vlc->regs + VELOCITY_RXDESCNUM ); + + /* Destroy RX ring */ + free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); + vlc->rx_ring = NULL; + vlc->rx_prod = 0; + vlc->rx_cons = 0; + + /* Discard receive buffers */ + for ( i = 0 ; i < VELOCITY_RXDESC_NUM ; i++ ) { + if ( vlc->rx_buffs[i] ) + free_iob ( vlc->rx_buffs[i] ); + vlc->rx_buffs[i] = NULL; + } + + /* Clear TX ring information */ + writel ( 0, vlc->regs + VELOCITY_TXDESC_ADDR_LO0 ); + writew ( 0, vlc->regs + VELOCITY_TXDESCNUM ); + + /* Destroy TX ring */ + free_dma ( vlc->tx_ring, VELOCITY_TXDESC_SIZE ); + vlc->tx_ring = NULL; + vlc->tx_prod = 0; + vlc->tx_cons = 0; +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int velocity_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct velocity_nic *vlc = netdev->priv; + struct velocity_tx_descriptor *desc; + unsigned int tx_idx; + + /* Pad packet to minimum length */ + iob_pad ( iobuf, ETH_ZLEN ); + + tx_idx = ( vlc->tx_prod++ % VELOCITY_TXDESC_NUM ); + desc = &vlc->tx_ring[tx_idx]; + + /* Set packet size and transfer ownership to NIC */ + desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN | + VELOCITY_DES2_SIZE ( iob_len ( iobuf ) ) ); + /* Data in first desc fragment, only desc for packet, generate INT */ + desc->des1 = cpu_to_le32 ( VELOCITY_DES1_FRAG ( 1 ) | + VELOCITY_DES1_TCPLS | + VELOCITY_DES1_INTR ); + + desc->frags[0].addr = virt_to_le32bus ( iobuf->data ); + desc->frags[0].des2 = cpu_to_le32 ( + VELOCITY_DES2_SIZE ( iob_len ( iobuf ) ) ); + + wmb(); + + /* Initiate TX */ + velocity_setbit ( vlc->regs + VELOCITY_TXQCSRS, VELOCITY_TXQCSRS_WAK0 ); + + DBGC2 ( vlc, "VELOCITY %p tx_prod=%d desc=%p iobuf=%p len=%zd\n", + vlc, tx_idx, desc, iobuf->data, iob_len ( iobuf ) ); + + return 0; +} + +/** + * Poll for received packets. + * + * @v vlc Velocity device + */ +static void velocity_poll_rx ( struct velocity_nic *vlc ) { + struct velocity_rx_descriptor *desc; + struct io_buffer *iobuf; + int rx_idx; + size_t len; + uint32_t des0; + + /* Check for packets */ + while ( vlc->rx_cons != vlc->rx_prod ) { + rx_idx = ( vlc->rx_cons % VELOCITY_RXDESC_NUM ); + desc = &vlc->rx_ring[rx_idx]; + + des0 = cpu_to_le32 ( desc->des0 ); + + /* Return if descriptor still in use */ + if ( des0 & VELOCITY_DES0_OWN ) + return; + + iobuf = vlc->rx_buffs[rx_idx]; + + /* Get length, strip CRC */ + len = VELOCITY_DES0_RMBC ( des0 ) - 4; + iob_put ( iobuf, len ); + + DBGC2 ( vlc, "VELOCITY %p got packet on idx=%d (prod=%d), len %zd\n", + vlc, rx_idx, vlc->rx_prod % VELOCITY_RXDESC_NUM, len ); + + if ( des0 & VELOCITY_DES0_RX_ERR ) { + /* Report receive error */ + netdev_rx_err ( vlc->netdev, iobuf, -EINVAL ); + DBGC ( vlc, "VELOCITY %p receive error, status: %02x\n", + vlc, des0 ); + } else if ( des0 & VELOCITY_DES0_RXOK ) { + /* Report receive success */ + netdev_rx( vlc->netdev, iobuf ); + } else { + /* Card indicated neither success nor failure + * Technically this shouldn't happen, but we saw it + * in debugging once. */ + DBGC ( vlc, "VELOCITY %p RX neither ERR nor OK: %04x\n", + vlc, des0 ); + DBGC ( vlc, "packet len: %zd\n", len ); + DBGC_HD ( vlc, iobuf->data, 64 ); + + /* we don't know what it is, treat is as an error */ + netdev_rx_err ( vlc->netdev, iobuf, -EINVAL ); + } + + vlc->rx_cons++; + } +} + +/** + * Poll for completed packets. + * + * @v vlc Velocity device + */ +static void velocity_poll_tx ( struct velocity_nic *vlc ) { + struct velocity_tx_descriptor *desc; + int tx_idx; + + /* Check for packets */ + while ( vlc->tx_cons != vlc->tx_prod ) { + tx_idx = ( vlc->tx_cons % VELOCITY_TXDESC_NUM ); + desc = &vlc->tx_ring[tx_idx]; + + /* Return if descriptor still in use */ + if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_OWN ) + return; + + /* Report errors */ + if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_TERR ) { + netdev_tx_complete_next_err ( vlc->netdev, -EINVAL ); + return; + } + + netdev_tx_complete_next ( vlc->netdev ); + + DBGC2 ( vlc, "VELOCITY %p poll_tx cons=%d prod=%d tsr=%04x\n", + vlc, tx_idx, vlc->tx_prod % VELOCITY_TXDESC_NUM, + ( desc->des0 & 0xffff ) ); + vlc->tx_cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void velocity_poll ( struct net_device *netdev ) { + struct velocity_nic *vlc = netdev->priv; + uint8_t isr1; + + isr1 = readb ( vlc->regs + VELOCITY_ISR1 ); + + /* ACK interrupts */ + writew ( 0xFFFF, vlc->regs + VELOCITY_ISR0 ); + + /* Check for competed packets */ + velocity_poll_rx ( vlc ); + velocity_poll_tx ( vlc ); + + if ( isr1 & VELOCITY_ISR1_SRCI ) { + /* Update linkstate */ + DBGC2 ( vlc, "VELOCITY %p link status interrupt\n", vlc ); + velocity_check_link ( netdev ); + } + + velocity_refill_rx ( vlc ); + + /* deal with potential RX stall caused by RX ring underrun */ + writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK, + vlc->regs + VELOCITY_RXQCSRS ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void velocity_irq ( struct net_device *netdev, int enable ) { + struct velocity_nic *vlc = netdev->priv; + + DBGC ( vlc, "VELOCITY %p interrupts %s\n", vlc, + enable ? "enable" : "disable" ); + + if (enable) { + /* Enable interrupts */ + writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRS3 ); + } else { + /* Disable interrupts */ + writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRC3 ); + } +} + +/** Velocity network device operations */ +static struct net_device_operations velocity_operations = { + .open = velocity_open, + .close = velocity_close, + .transmit = velocity_transmit, + .poll = velocity_poll, + .irq = velocity_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int velocity_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct velocity_nic *vlc; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *vlc ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &velocity_operations ); + vlc = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + vlc->regs = ioremap ( pci->membase, VELOCITY_BAR_SIZE ); + vlc->netdev = netdev; + + /* Reset the NIC */ + if ( ( rc = velocity_reset ( vlc ) ) != 0 ) + goto err_reset; + + /* Reload EEPROM */ + if ( ( rc = velocity_reload_eeprom ( vlc ) ) != 0 ) + goto err_reset; + + /* Get MAC address */ + netdev->hw_addr[0] = readb ( vlc->regs + VELOCITY_MAC0 ); + netdev->hw_addr[1] = readb ( vlc->regs + VELOCITY_MAC1 ); + netdev->hw_addr[2] = readb ( vlc->regs + VELOCITY_MAC2 ); + netdev->hw_addr[3] = readb ( vlc->regs + VELOCITY_MAC3 ); + netdev->hw_addr[4] = readb ( vlc->regs + VELOCITY_MAC4 ); + netdev->hw_addr[5] = readb ( vlc->regs + VELOCITY_MAC5 ); + + /* Initialise and reset MII interface */ + mii_init ( &vlc->mii, &velocity_mii_operations ); + if ( ( rc = mii_reset ( &vlc->mii ) ) != 0 ) { + DBGC ( vlc, "VELOCITY %p could not reset MII: %s\n", + vlc, strerror ( rc ) ); + goto err_mii_reset; + } + + /* Enable proper link advertising */ + velocity_set_link ( vlc ); + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + return 0; + + err_register_netdev: + err_mii_reset: + velocity_reset ( vlc ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void velocity_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct velocity_nic *vlc = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + velocity_reset ( vlc ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Velocity PCI device IDs */ +static struct pci_device_id velocity_nics[] = { + PCI_ROM ( 0x1106, 0x3119, "vt6122", "VIA Velocity", 0 ), +}; + +/** Velocity PCI driver */ +struct pci_driver velocity_driver __pci_driver = { + .ids = velocity_nics, + .id_count = ( sizeof ( velocity_nics ) / sizeof ( velocity_nics[0] ) ), + .probe = velocity_probe, + .remove = velocity_remove, +}; diff --git a/roms/ipxe/src/drivers/net/velocity.h b/roms/ipxe/src/drivers/net/velocity.h new file mode 100644 index 000000000..04e6a1460 --- /dev/null +++ b/roms/ipxe/src/drivers/net/velocity.h @@ -0,0 +1,356 @@ +#ifndef _VELOCITY_H +#define _VELOCITY_H + +/** @file + * + * VIA Velocity network driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** Skeleton BAR size */ +#define VELOCITY_BAR_SIZE 256 + +/** Default timeout */ +#define VELOCITY_TIMEOUT_US 10 * 1000 + +struct velocity_frag { + uint32_t addr; + uint32_t des2; +} __attribute__ ((packed)); + +/** Velocity descriptor format */ +struct velocity_tx_descriptor { + uint32_t des0; + uint32_t des1; + /* We only use the first fragment, the HW requires us to have 7 */ + struct velocity_frag frags[7]; +} __attribute__ ((packed)); + +struct velocity_rx_descriptor { + uint32_t des0; + uint32_t des1; + uint32_t addr; + uint32_t des2; +} __attribute__ ((packed)); + +#define VELOCITY_DES0_RMBC(_n) (((_n) >> 16) & 0x1fff) +#define VELOCITY_DES0_OWN (1 << 31) +#define VELOCITY_DES0_TERR (1 << 15) +#define VELOCITY_DES0_RXOK (1 << 15) +#define VELOCITY_DES0_FDX (1 << 14) +#define VELOCITY_DES0_GMII (1 << 13) +#define VELOCITY_DES0_LNKFL (1 << 12) +#define VELOCITY_DES0_SHDN (1 << 10) +#define VELOCITY_DES0_CRS (1 << 9) +#define VELOCITY_DES0_CDH (1 << 8) +#define VELOCITY_DES0_ABT (1 << 7) +#define VELOCITY_DES0_OWT (1 << 6) +#define VELOCITY_DES0_OWC (1 << 5) +#define VELOCITY_DES0_COLS (1 << 4) + +#define VELOCITY_DES0_RXSHDN (1 << 30) +#define VELOCITY_DES0_RXER (1 << 5) +#define VELOCITY_DES0_RLE (1 << 4) +#define VELOCITY_DES0_CE (1 << 3) +#define VELOCITY_DES0_FAE (1 << 2) +#define VELOCITY_DES0_CRC (1 << 1) +#define VELOCITY_DES0_RX_ERR ( VELOCITY_DES0_RXER | \ + VELOCITY_DES0_RLE | \ + VELOCITY_DES0_CE | \ + VELOCITY_DES0_FAE | \ + VELOCITY_DES0_CRC ) + +/** TX descriptor fragment number */ +#define VELOCITY_DES1_FRAG(_n) (((_n + 1) & 0xf) << 28) +#define VELOCITY_DES1_TCPLS ((1 << 24) | (1 << 25)) +#define VELOCITY_DES1_INTR (1 << 23) +#define VELOCITY_DES1_PIC (1 << 22) +#define VELOCITY_DES1_VETAG (1 << 21) +#define VELOCITY_DES1_IPCK (1 << 20) +#define VELOCITY_DES1_UDPCK (1 << 19) +#define VELOCITY_DES1_TCPCK (1 << 18) +#define VELOCITY_DES1_JMBO (1 << 17) +#define VELOCITY_DES1_CRC (1 << 16) + +#define VELOCITY_DES2_IC (1 << 31) +#define VELOCITY_DES2_SIZE(_n) (((_n) & 0x1fff) << 16) + +/** Number of receive descriptors + * + * Must be a multiple of 4 (hardware requirement). + */ +#define VELOCITY_RXDESC_NUM 8 +#define VELOCITY_RXDESC_SIZE \ + ( VELOCITY_RXDESC_NUM * sizeof ( struct velocity_rx_descriptor ) ) + +/** Number of transmit descriptors */ +#define VELOCITY_TXDESC_NUM 8 +#define VELOCITY_TXDESC_SIZE \ + ( VELOCITY_TXDESC_NUM * sizeof ( struct velocity_tx_descriptor ) ) + +/** Descriptor alignment */ +#define VELOCITY_RING_ALIGN 64 + +/** Receive buffer length */ +#define VELOCITY_RX_MAX_LEN 1536 + +/** MAC address registers */ +#define VELOCITY_MAC0 0x00 +#define VELOCITY_MAC1 0x01 +#define VELOCITY_MAC2 0x02 +#define VELOCITY_MAC3 0x03 +#define VELOCITY_MAC4 0x04 +#define VELOCITY_MAC5 0x05 + +/** Receive control register */ +#define VELOCITY_RCR 0x06 +#define RHINE_RCR_SYMERR_ACCEPT (1 << 7) /*< Accept symbol error */ +#define RHINE_RCR_FILTER_ACCEPT (1 << 6) /*< Accept based on filter */ +#define RHINE_RCR_LONG_ACCEPT (1 << 5) /*< Accept long packets */ +#define RHINE_RCR_PROMISC (1 << 4) /*< Promiscuous mode */ +#define RHINE_RCR_BCAST_ACCEPT (1 << 3) /*< Accept broadcast */ +#define RHINE_RCR_MCAST_ACCEPT (1 << 2) /*< Accept multicast */ +#define RHINE_RCR_RUNT_ACCEPT (1 << 1) /*< Accept runt frames */ +#define RHINE_RCR_ERR_ACCEPT (1 << 0) /*< Accept erroneous frames */ + +/** Transmit control register */ +#define VELOCITY_TCR 0x07 +#define VELOCITY_TCR_LB0 (1 << 0) /*< Loopback control */ +#define VELOCITY_TCR_LB1 (1 << 1) /*< Loopback control */ +#define VELOCITY_TCR_COLTMC0 (1 << 2) /*< Collision retry control */ +#define VELOCITY_TCR_COLTMC1 (1 << 3) /*< Collision retry control */ + +/** Command register 0 (set) */ +#define VELOCITY_CRS0 0x08 +#define VELOCITY_CR0_TXON (1 << 3) /*< Transmit enable */ +#define VELOCITY_CR0_RXON (1 << 2) /*< Receive enable */ +#define VELOCITY_CR0_STOP (1 << 1) /*< Stop NIC */ +#define VELOCITY_CR0_START (1 << 0) /*< Start NIC */ + +/** Command register 1 (set) */ +#define VELOCITY_CRS1 0x09 +#define VELOCITY_CR1_SFRST (1 << 7) /*< Software reset */ +#define VELOCITY_CR1_TM1EN (1 << 6) /*< Perioding software counting */ +#define VELOCITY_CR1_TM0EN (1 << 5) /*< Single-shot software counting */ +#define VELOCITY_CR1_DPOLL (1 << 3) /*< Disable auto polling */ +#define VELOCITY_CR1_DISAU (1 << 0) /*< Unicast reception disable */ + +/** Command register 2 (set) */ +#define VELOCITY_CRS2 0x0A +#define VELOCITY_CR2_XONEN (1 << 7) /*< XON/XOFF mode enable */ +#define VELOCITY_CR2_FDXTFCEN (1 << 6) /*< FDX flow control TX */ +#define VELOCITY_CR2_FDXRFCEN (1 << 5) +#define VELOCITY_CR2_HDXFCEN (1 << 4) + +/** Command register 3 (set) */ +#define VELOCITY_CRS3 0x0B +#define VELOCITY_CR3_FOSRST (1 << 6) +#define VELOCITY_CR3_FPHYRST (1 << 5) +#define VELOCITY_CR3_DIAG (1 << 4) +#define VELOCITY_CR3_INTPCTL (1 << 2) +#define VELOCITY_CR3_GINTMSK1 (1 << 1) +#define VELOCITY_CR3_SWPEND (1 << 0) + +/** Command register 0 (clear) */ +#define VELOCITY_CRC0 0x0C + +/** Command register 1 (clear) */ +#define VELOCITY_CRC1 0x0D + +/** Command register 2 (clear */ +#define VELOCITY_CRC2 0x0E + +/** Command register 3 (clear */ +#define VELOCITY_CRC3 0x0F +#define VELOCITY_CAM0 0x10 +#define VELOCITY_CAM1 0x11 +#define VELOCITY_CAM2 0x12 +#define VELOCITY_CAM3 0x13 +#define VELOCITY_CAM4 0x14 +#define VELOCITY_CAM5 0x15 +#define VELOCITY_CAM6 0x16 +#define VELOCITY_CAM7 0x17 +#define VELOCITY_TXDESC_HI 0x18 /* Hi part of 64bit txdesc base addr */ +#define VELOCITY_DATABUF_HI 0x1D /* Hi part of 64bit data buffer addr */ +#define VELOCITY_INTCTL0 0x20 /* interrupt control register */ +#define VELOCITY_RXSUPPTHR 0x20 +#define VELOCITY_TXSUPPTHR 0x20 +#define VELOCITY_INTHOLDOFF 0x20 +#define VELOCITY_INTCTL1 0x21 /* interrupt control register */ +#define VELOCITY_TXHOSTERR 0x22 /* TX host error status */ +#define VELOCITY_RXHOSTERR 0x23 /* RX host error status */ + +/** Interrupt status register 0 */ +#define VELOCITY_ISR0 0x24 +#define VELOCITY_ISR0_PTX3 (1 << 7) +#define VELOCITY_ISR0_PTX2 (1 << 6) +#define VELOCITY_ISR0_PTX1 (1 << 5) +#define VELOCITY_ISR0_PTX0 (1 << 4) +#define VELOCITY_ISR0_PTXI (1 << 3) +#define VELOCITY_ISR0_PRXI (1 << 2) +#define VELOCITY_ISR0_PPTXI (1 << 1) +#define VELOCITY_ISR0_PPRXI (1 << 0) + +/** Interrupt status register 1 */ +#define VELOCITY_ISR1 0x25 +#define VELOCITY_ISR1_SRCI (1 << 7) +#define VELOCITY_ISR1_LSTPEI (1 << 6) +#define VELOCITY_ISR1_LSTEI (1 << 5) +#define VELOCITY_ISR1_OVFL (1 << 4) +#define VELOCITY_ISR1_FLONI (1 << 3) +#define VELOCITY_ISR1_RACEI (1 << 2) + +/** Interrupt status register 2 */ +#define VELOCITY_ISR2 0x26 +#define VELOCITY_ISR2_HFLD (1 << 7) +#define VELOCITY_ISR2_UDPI (1 << 6) +#define VELOCITY_ISR2_MIBFI (1 << 5) +#define VELOCITY_ISR2_SHDNII (1 << 4) +#define VELOCITY_ISR2_PHYI (1 << 3) +#define VELOCITY_ISR2_PWEI (1 << 2) +#define VELOCITY_ISR2_TMR1I (1 << 1) +#define VELOCITY_ISR2_TMR0I (1 << 0) + +/** Interrupt status register 3 */ +#define VELOCITY_ISR3 0x27 + +/** Interrupt mask register 0 */ +#define VELOCITY_IMR0 0x28 + +/** Interrupt mask register 1 */ +#define VELOCITY_IMR1 0x29 + +/** Interrupt mask register 2 */ +#define VELOCITY_IMR2 0x2a + +/** Interrupt mask register 3 */ +#define VELOCITY_IMR3 0x2b + +#define VELOCITY_TXSTS_PORT 0x2C /* Transmit status port (???) */ +#define VELOCITY_TXQCSRS 0x30 /* TX queue ctl/status set */ + +#define VELOCITY_TXQCSRS_DEAD3 (1 << 15) +#define VELOCITY_TXQCSRS_WAK3 (1 << 14) +#define VELOCITY_TXQCSRS_ACT3 (1 << 13) +#define VELOCITY_TXQCSRS_RUN3 (1 << 12) +#define VELOCITY_TXQCSRS_DEAD2 (1 << 11) +#define VELOCITY_TXQCSRS_WAK2 (1 << 10) +#define VELOCITY_TXQCSRS_ACT2 (1 << 9) +#define VELOCITY_TXQCSRS_RUN2 (1 << 8) +#define VELOCITY_TXQCSRS_DEAD1 (1 << 7) +#define VELOCITY_TXQCSRS_WAK1 (1 << 6) +#define VELOCITY_TXQCSRS_ACT1 (1 << 5) +#define VELOCITY_TXQCSRS_RUN1 (1 << 4) +#define VELOCITY_TXQCSRS_DEAD0 (1 << 3) +#define VELOCITY_TXQCSRS_WAK0 (1 << 2) +#define VELOCITY_TXQCSRS_ACT0 (1 << 1) +#define VELOCITY_TXQCSRS_RUN0 (1 << 0) + +#define VELOCITY_RXQCSRS 0x32 /* RX queue ctl/status set */ +#define VELOCITY_RXQCSRC 0x36 + +#define VELOCITY_RXQCSR_DEAD (1 << 3) +#define VELOCITY_RXQCSR_WAK (1 << 2) +#define VELOCITY_RXQCSR_ACT (1 << 1) +#define VELOCITY_RXQCSR_RUN (1 << 0) + +#define VELOCITY_TXQCSRC 0x34 /* TX queue ctl/status clear */ +#define VELOCITY_RXQCSRC 0x36 /* RX queue ctl/status clear */ +#define VELOCITY_RXDESC_ADDR_LO 0x38 /* RX desc base addr (lo 32 bits) */ +#define VELOCITY_RXDESC_CONSIDX 0x3C /* Current RX descriptor index */ +#define VELOCITY_TXQTIMER 0x3E /* TX queue timer pend register */ +#define VELOCITY_RXQTIMER 0x3F /* RX queue timer pend register */ +#define VELOCITY_TXDESC_ADDR_LO0 0x40 /* TX desc0 base addr (lo 32 bits) */ +#define VELOCITY_TXDESC_ADDR_LO1 0x44 /* TX desc1 base addr (lo 32 bits) */ +#define VELOCITY_TXDESC_ADDR_LO2 0x48 /* TX desc2 base addr (lo 32 bits) */ +#define VELOCITY_TXDESC_ADDR_LO3 0x4C /* TX desc3 base addr (lo 32 bits) */ +#define VELOCITY_RXDESCNUM 0x50 /* Size of RX desc ring */ +#define VELOCITY_TXDESCNUM 0x52 /* Size of TX desc ring */ +#define VELOCITY_TXDESC_CONSIDX0 0x54 /* Current TX descriptor index */ +#define VELOCITY_TXDESC_CONSIDX1 0x56 /* Current TX descriptor index */ +#define VELOCITY_TXDESC_CONSIDX2 0x58 /* Current TX descriptor index */ +#define VELOCITY_TXDESC_CONSIDX3 0x5A /* Current TX descriptor index */ +#define VELOCITY_TX_PAUSE_TIMER 0x5C /* TX pause frame timer */ +#define VELOCITY_RXDESC_RESIDUECNT 0x5E /* RX descriptor residue count */ +#define VELOCITY_FIFOTEST0 0x60 /* FIFO test register */ +#define VELOCITY_FIFOTEST1 0x64 /* FIFO test register */ +#define VELOCITY_CAMADDR 0x68 /* CAM address register */ +#define VELOCITY_CAMCTL 0x69 /* CAM control register */ +#define VELOCITY_MIICFG 0x6C /* MII port config register */ +#define VELOCITY_MIISR 0x6D /* MII port status register */ +#define VELOCITY_MIISR_IDLE (1 << 7) +#define VELOCITY_PHYSTS0 0x6E /* PHY status register */ +#define VELOCITY_PHYSTS0_LINK (1 << 6) +#define VELOCITY_PHYSTS1 0x6F /* PHY status register */ +#define VELOCITY_MIICR 0x70 /* MII command register */ +#define VELOCITY_MIICR_MAUTO (1 << 7) +#define VELOCITY_MIICR_RCMD (1 << 6) +#define VELOCITY_MIICR_WCMD (1 << 5) +#define VELOCITY_MIICR_MDPM (1 << 4) +#define VELOCITY_MIICR_MOUT (1 << 3) +#define VELOCITY_MIICR_MDO (1 << 2) +#define VELOCITY_MIICR_MDI (1 << 1) +#define VELOCITY_MIICR_MDC (1 << 0) + +#define VELOCITY_MIIADDR 0x71 /* MII address register */ +#define VELOCITY_MIIDATA 0x72 /* MII data register */ +#define VELOCITY_SSTIMER 0x74 /* single-shot timer */ +#define VELOCITY_PTIMER 0x76 /* periodic timer */ +#define VELOCITY_DMACFG0 0x7C /* DMA config 0 */ +#define VELOCITY_DMACFG1 0x7D /* DMA config 1 */ +#define VELOCITY_RXCFG 0x7E /* MAC RX config */ +#define VELOCITY_TXCFG 0x7F /* MAC TX config */ +#define VELOCITY_SWEEDATA 0x85 /* EEPROM software loaded data */ + +/** Chip Configuration Register A */ +#define VELOCITY_CFGA 0x78 +#define VELOCITY_CFGA_PACPI (1 << 0) + +/** Power Management Sticky Register */ +#define VELOCITY_STICKY 0x83 +#define VELOCITY_STICKY_DS0 (1 << 0) +#define VELOCITY_STICKY_DS1 (1 << 1) + +#define VELOCITY_EEWRDAT 0x8C /* EEPROM embedded write */ +#define VELOCITY_EECSUM 0x92 /* EEPROM checksum */ +#define VELOCITY_EECSR 0x93 /* EEPROM control/status */ +#define VELOCITY_EECSR_RELOAD (1 << 5) +#define VELOCITY_EERDDAT 0x94 /* EEPROM embedded read */ +#define VELOCITY_EEADDR 0x96 /* EEPROM address */ +#define VELOCITY_EECMD 0x97 /* EEPROM embedded command */ + +/** A Velocity network card */ +struct velocity_nic { + /** Registers */ + void *regs; + /** MII interface */ + struct mii_interface mii; + /** Netdev */ + struct net_device *netdev; + + /** Receive descriptor ring */ + struct velocity_rx_descriptor *rx_ring; + /** Receive I/O buffers */ + struct io_buffer *rx_buffs[VELOCITY_RXDESC_NUM]; + /** Receive producer index */ + unsigned int rx_prod; + /** Receive consumer index */ + unsigned int rx_cons; + /** Receive commit number + * + * Used to fullfill the hardware requirement of returning receive buffers + * to the hardware only in blocks of 4. + */ + unsigned int rx_commit; + + /** Transmit descriptor ring */ + struct velocity_tx_descriptor *tx_ring; + /** Transmit producer index */ + unsigned int tx_prod; + /** Transmit consumer index */ + unsigned int tx_cons; +}; + +#endif /* _VELOCITY_H */ diff --git a/roms/ipxe/src/drivers/net/via-rhine.c b/roms/ipxe/src/drivers/net/via-rhine.c deleted file mode 100644 index f3bb4e014..000000000 --- a/roms/ipxe/src/drivers/net/via-rhine.c +++ /dev/null @@ -1,1447 +0,0 @@ -/* rhine.c:Fast Ethernet driver for Linux. */ -/* - Adapted 09-jan-2000 by Paolo Marini (paolom@prisma-eng.it) - - originally written by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License (GPL), incorporated herein by reference. - Drivers derived from this code also fall under the GPL and must retain - this authorship and copyright notice. - - Under no circumstances are the authors responsible for - the proper functioning of this software, nor do the authors assume any - responsibility for damages incurred with its use. - - This driver is designed for the VIA VT86C100A Rhine-II PCI Fast Ethernet - controller. - -*/ - -static const char *version = "rhine.c v1.0.2 2004-10-29\n"; - -/* A few user-configurable values. */ - -// max time out delay time -#define W_MAX_TIMEOUT 0x0FFFU - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) - -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE 1536 -#define RX_BUF_SIZE 1536 - -/* PCI Tuning Parameters - Threshold is bytes transferred to chip before transmission starts. */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ -#define TX_DMA_BURST 4 - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((2000*HZ)/1000) - -#include "etherboot.h" -#include "nic.h" -#include <ipxe/pci.h> -#include <ipxe/ethernet.h> - -/* define all ioaddr */ - -#define byPAR0 ioaddr -#define byRCR ioaddr + 6 -#define byTCR ioaddr + 7 -#define byCR0 ioaddr + 8 -#define byCR1 ioaddr + 9 -#define byISR0 ioaddr + 0x0c -#define byISR1 ioaddr + 0x0d -#define byIMR0 ioaddr + 0x0e -#define byIMR1 ioaddr + 0x0f -#define byMAR0 ioaddr + 0x10 -#define byMAR1 ioaddr + 0x11 -#define byMAR2 ioaddr + 0x12 -#define byMAR3 ioaddr + 0x13 -#define byMAR4 ioaddr + 0x14 -#define byMAR5 ioaddr + 0x15 -#define byMAR6 ioaddr + 0x16 -#define byMAR7 ioaddr + 0x17 -#define dwCurrentRxDescAddr ioaddr + 0x18 -#define dwCurrentTxDescAddr ioaddr + 0x1c -#define dwCurrentRDSE0 ioaddr + 0x20 -#define dwCurrentRDSE1 ioaddr + 0x24 -#define dwCurrentRDSE2 ioaddr + 0x28 -#define dwCurrentRDSE3 ioaddr + 0x2c -#define dwNextRDSE0 ioaddr + 0x30 -#define dwNextRDSE1 ioaddr + 0x34 -#define dwNextRDSE2 ioaddr + 0x38 -#define dwNextRDSE3 ioaddr + 0x3c -#define dwCurrentTDSE0 ioaddr + 0x40 -#define dwCurrentTDSE1 ioaddr + 0x44 -#define dwCurrentTDSE2 ioaddr + 0x48 -#define dwCurrentTDSE3 ioaddr + 0x4c -#define dwNextTDSE0 ioaddr + 0x50 -#define dwNextTDSE1 ioaddr + 0x54 -#define dwNextTDSE2 ioaddr + 0x58 -#define dwNextTDSE3 ioaddr + 0x5c -#define dwCurrRxDMAPtr ioaddr + 0x60 -#define dwCurrTxDMAPtr ioaddr + 0x64 -#define byMPHY ioaddr + 0x6c -#define byMIISR ioaddr + 0x6d -#define byBCR0 ioaddr + 0x6e -#define byBCR1 ioaddr + 0x6f -#define byMIICR ioaddr + 0x70 -#define byMIIAD ioaddr + 0x71 -#define wMIIDATA ioaddr + 0x72 -#define byEECSR ioaddr + 0x74 -#define byTEST ioaddr + 0x75 -#define byGPIO ioaddr + 0x76 -#define byCFGA ioaddr + 0x78 -#define byCFGB ioaddr + 0x79 -#define byCFGC ioaddr + 0x7a -#define byCFGD ioaddr + 0x7b -#define wTallyCntMPA ioaddr + 0x7c -#define wTallyCntCRC ioaddr + 0x7d -#define bySTICKHW ioaddr + 0x83 -#define byWOLcrClr ioaddr + 0xA4 -#define byWOLcgClr ioaddr + 0xA7 -#define byPwrcsrClr ioaddr + 0xAC - -/*--------------------- Exioaddr Definitions -------------------------*/ - -/* - * Bits in the RCR register - */ - -#define RCR_RRFT2 0x80 -#define RCR_RRFT1 0x40 -#define RCR_RRFT0 0x20 -#define RCR_PROM 0x10 -#define RCR_AB 0x08 -#define RCR_AM 0x04 -#define RCR_AR 0x02 -#define RCR_SEP 0x01 - -/* - * Bits in the TCR register - */ - -#define TCR_RTSF 0x80 -#define TCR_RTFT1 0x40 -#define TCR_RTFT0 0x20 -#define TCR_OFSET 0x08 -#define TCR_LB1 0x04 /* loopback[1] */ -#define TCR_LB0 0x02 /* loopback[0] */ - -/* - * Bits in the CR0 register - */ - -#define CR0_RDMD 0x40 /* rx descriptor polling demand */ -#define CR0_TDMD 0x20 /* tx descriptor polling demand */ -#define CR0_TXON 0x10 -#define CR0_RXON 0x08 -#define CR0_STOP 0x04 /* stop NIC, default = 1 */ -#define CR0_STRT 0x02 /* start NIC */ -#define CR0_INIT 0x01 /* start init process */ - - -/* - * Bits in the CR1 register - */ - -#define CR1_SFRST 0x80 /* software reset */ -#define CR1_RDMD1 0x40 /* RDMD1 */ -#define CR1_TDMD1 0x20 /* TDMD1 */ -#define CR1_KEYPAG 0x10 /* turn on par/key */ -#define CR1_DPOLL 0x08 /* disable rx/tx auto polling */ -#define CR1_FDX 0x04 /* full duplex mode */ -#define CR1_ETEN 0x02 /* early tx mode */ -#define CR1_EREN 0x01 /* early rx mode */ - -/* - * Bits in the CR register - */ - -#define CR_RDMD 0x0040 /* rx descriptor polling demand */ -#define CR_TDMD 0x0020 /* tx descriptor polling demand */ -#define CR_TXON 0x0010 -#define CR_RXON 0x0008 -#define CR_STOP 0x0004 /* stop NIC, default = 1 */ -#define CR_STRT 0x0002 /* start NIC */ -#define CR_INIT 0x0001 /* start init process */ -#define CR_SFRST 0x8000 /* software reset */ -#define CR_RDMD1 0x4000 /* RDMD1 */ -#define CR_TDMD1 0x2000 /* TDMD1 */ -#define CR_KEYPAG 0x1000 /* turn on par/key */ -#define CR_DPOLL 0x0800 /* disable rx/tx auto polling */ -#define CR_FDX 0x0400 /* full duplex mode */ -#define CR_ETEN 0x0200 /* early tx mode */ -#define CR_EREN 0x0100 /* early rx mode */ - -/* - * Bits in the IMR0 register - */ - -#define IMR0_CNTM 0x80 -#define IMR0_BEM 0x40 -#define IMR0_RUM 0x20 -#define IMR0_TUM 0x10 -#define IMR0_TXEM 0x08 -#define IMR0_RXEM 0x04 -#define IMR0_PTXM 0x02 -#define IMR0_PRXM 0x01 - -/* define imrshadow */ - -#define IMRShadow 0x5AFF - -/* - * Bits in the IMR1 register - */ - -#define IMR1_INITM 0x80 -#define IMR1_SRCM 0x40 -#define IMR1_NBFM 0x10 -#define IMR1_PRAIM 0x08 -#define IMR1_RES0M 0x04 -#define IMR1_ETM 0x02 -#define IMR1_ERM 0x01 - -/* - * Bits in the ISR register - */ - -#define ISR_INITI 0x8000 -#define ISR_SRCI 0x4000 -#define ISR_ABTI 0x2000 -#define ISR_NORBF 0x1000 -#define ISR_PKTRA 0x0800 -#define ISR_RES0 0x0400 -#define ISR_ETI 0x0200 -#define ISR_ERI 0x0100 -#define ISR_CNT 0x0080 -#define ISR_BE 0x0040 -#define ISR_RU 0x0020 -#define ISR_TU 0x0010 -#define ISR_TXE 0x0008 -#define ISR_RXE 0x0004 -#define ISR_PTX 0x0002 -#define ISR_PRX 0x0001 - -/* - * Bits in the ISR0 register - */ - -#define ISR0_CNT 0x80 -#define ISR0_BE 0x40 -#define ISR0_RU 0x20 -#define ISR0_TU 0x10 -#define ISR0_TXE 0x08 -#define ISR0_RXE 0x04 -#define ISR0_PTX 0x02 -#define ISR0_PRX 0x01 - -/* - * Bits in the ISR1 register - */ - -#define ISR1_INITI 0x80 -#define ISR1_SRCI 0x40 -#define ISR1_NORBF 0x10 -#define ISR1_PKTRA 0x08 -#define ISR1_ETI 0x02 -#define ISR1_ERI 0x01 - -/* ISR ABNORMAL CONDITION */ - -#define ISR_ABNORMAL ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA - -/* - * Bits in the MIISR register - */ - -#define MIISR_MIIERR 0x08 -#define MIISR_MRERR 0x04 -#define MIISR_LNKFL 0x02 -#define MIISR_SPEED 0x01 - -/* - * Bits in the MIICR register - */ - -#define MIICR_MAUTO 0x80 -#define MIICR_RCMD 0x40 -#define MIICR_WCMD 0x20 -#define MIICR_MDPM 0x10 -#define MIICR_MOUT 0x08 -#define MIICR_MDO 0x04 -#define MIICR_MDI 0x02 -#define MIICR_MDC 0x01 - -/* - * Bits in the EECSR register - */ - -#define EECSR_EEPR 0x80 /* eeprom programed status, 73h means programed */ -#define EECSR_EMBP 0x40 /* eeprom embedded programming */ -#define EECSR_AUTOLD 0x20 /* eeprom content reload */ -#define EECSR_DPM 0x10 /* eeprom direct programming */ -#define EECSR_CS 0x08 /* eeprom CS pin */ -#define EECSR_SK 0x04 /* eeprom SK pin */ -#define EECSR_DI 0x02 /* eeprom DI pin */ -#define EECSR_DO 0x01 /* eeprom DO pin */ - -/* - * Bits in the BCR0 register - */ - -#define BCR0_CRFT2 0x20 -#define BCR0_CRFT1 0x10 -#define BCR0_CRFT0 0x08 -#define BCR0_DMAL2 0x04 -#define BCR0_DMAL1 0x02 -#define BCR0_DMAL0 0x01 - -/* - * Bits in the BCR1 register - */ - -#define BCR1_CTSF 0x20 -#define BCR1_CTFT1 0x10 -#define BCR1_CTFT0 0x08 -#define BCR1_POT2 0x04 -#define BCR1_POT1 0x02 -#define BCR1_POT0 0x01 - -/* - * Bits in the CFGA register - */ - -#define CFGA_EELOAD 0x80 /* enable eeprom embedded and direct programming */ -#define CFGA_JUMPER 0x40 -#define CFGA_MTGPIO 0x08 -#define CFGA_T10EN 0x02 -#define CFGA_AUTO 0x01 - -/* - * Bits in the CFGB register - */ - -#define CFGB_PD 0x80 -#define CFGB_POLEN 0x02 -#define CFGB_LNKEN 0x01 - -/* - * Bits in the CFGC register - */ - -#define CFGC_M10TIO 0x80 -#define CFGC_M10POL 0x40 -#define CFGC_PHY1 0x20 -#define CFGC_PHY0 0x10 -#define CFGC_BTSEL 0x08 -#define CFGC_BPS2 0x04 /* bootrom select[2] */ -#define CFGC_BPS1 0x02 /* bootrom select[1] */ -#define CFGC_BPS0 0x01 /* bootrom select[0] */ - -/* - * Bits in the CFGD register - */ - -#define CFGD_GPIOEN 0x80 -#define CFGD_DIAG 0x40 -#define CFGD_MAGIC 0x10 -#define CFGD_RANDOM 0x08 -#define CFGD_CFDX 0x04 -#define CFGD_CEREN 0x02 -#define CFGD_CETEN 0x01 - -/* Bits in RSR */ -#define RSR_RERR 0x00000001 -#define RSR_CRC 0x00000002 -#define RSR_FAE 0x00000004 -#define RSR_FOV 0x00000008 -#define RSR_LONG 0x00000010 -#define RSR_RUNT 0x00000020 -#define RSR_SERR 0x00000040 -#define RSR_BUFF 0x00000080 -#define RSR_EDP 0x00000100 -#define RSR_STP 0x00000200 -#define RSR_CHN 0x00000400 -#define RSR_PHY 0x00000800 -#define RSR_BAR 0x00001000 -#define RSR_MAR 0x00002000 -#define RSR_RXOK 0x00008000 -#define RSR_ABNORMAL RSR_RERR+RSR_LONG+RSR_RUNT - -/* Bits in TSR */ -#define TSR_NCR0 0x00000001 -#define TSR_NCR1 0x00000002 -#define TSR_NCR2 0x00000004 -#define TSR_NCR3 0x00000008 -#define TSR_COLS 0x00000010 -#define TSR_CDH 0x00000080 -#define TSR_ABT 0x00000100 -#define TSR_OWC 0x00000200 -#define TSR_CRS 0x00000400 -#define TSR_UDF 0x00000800 -#define TSR_TBUFF 0x00001000 -#define TSR_SERR 0x00002000 -#define TSR_JAB 0x00004000 -#define TSR_TERR 0x00008000 -#define TSR_ABNORMAL TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS -#define TSR_OWN_BIT 0x80000000 - -#define CB_DELAY_LOOP_WAIT 10 /* 10ms */ -/* enabled mask value of irq */ - -#define W_IMR_MASK_VALUE 0x1BFF /* initial value of IMR */ - -/* Ethernet address filter type */ -#define PKT_TYPE_DIRECTED 0x0001 /* obsolete, directed address is always accepted */ -#define PKT_TYPE_MULTICAST 0x0002 -#define PKT_TYPE_ALL_MULTICAST 0x0004 -#define PKT_TYPE_BROADCAST 0x0008 -#define PKT_TYPE_PROMISCUOUS 0x0020 -#define PKT_TYPE_LONG 0x2000 -#define PKT_TYPE_RUNT 0x4000 -#define PKT_TYPE_ERROR 0x8000 /* accept error packets, e.g. CRC error */ - -/* Loopback mode */ - -#define NIC_LB_NONE 0x00 -#define NIC_LB_INTERNAL 0x01 -#define NIC_LB_PHY 0x02 /* MII or Internal-10BaseT loopback */ - -#define TX_RING_SIZE 2 -#define RX_RING_SIZE 2 -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ - -#define PCI_REG_MODE3 0x53 -#define MODE3_MIION 0x04 /* in PCI_REG_MOD3 OF PCI space */ - -enum rhine_revs { - VT86C100A = 0x00, - VTunknown0 = 0x20, - VT6102 = 0x40, - VT8231 = 0x50, /* Integrated MAC */ - VT8233 = 0x60, /* Integrated MAC */ - VT8235 = 0x74, /* Integrated MAC */ - VT8237 = 0x78, /* Integrated MAC */ - VTunknown1 = 0x7C, - VT6105 = 0x80, - VT6105_B0 = 0x83, - VT6105L = 0x8A, - VT6107 = 0x8C, - VTunknown2 = 0x8E, - VT6105M = 0x90, -}; - -/* Transmit and receive descriptors definition */ - -struct rhine_tx_desc -{ - union VTC_tx_status_tag - { - struct - { - unsigned long ncro:1; - unsigned long ncr1:1; - unsigned long ncr2:1; - unsigned long ncr3:1; - unsigned long cols:1; - unsigned long reserve_1:2; - unsigned long cdh:1; - unsigned long abt:1; - unsigned long owc:1; - unsigned long crs:1; - unsigned long udf:1; - unsigned long tbuff:1; - unsigned long serr:1; - unsigned long jab:1; - unsigned long terr:1; - unsigned long reserve_2:15; - unsigned long own_bit:1; - } - bits; - unsigned long lw; - } - tx_status; - - union VTC_tx_ctrl_tag - { - struct - { - unsigned long tx_buf_size:11; - unsigned long extend_tx_buf_size:4; - unsigned long chn:1; - unsigned long crc:1; - unsigned long reserve_1:4; - unsigned long stp:1; - unsigned long edp:1; - unsigned long ic:1; - unsigned long reserve_2:8; - } - bits; - unsigned long lw; - } - tx_ctrl; - - unsigned long buf_addr_1:32; - unsigned long buf_addr_2:32; - -}; - -struct rhine_rx_desc -{ - union VTC_rx_status_tag - { - struct - { - unsigned long rerr:1; - unsigned long crc_error:1; - unsigned long fae:1; - unsigned long fov:1; - unsigned long toolong:1; - unsigned long runt:1; - unsigned long serr:1; - unsigned long buff:1; - unsigned long edp:1; - unsigned long stp:1; - unsigned long chn:1; - unsigned long phy:1; - unsigned long bar:1; - unsigned long mar:1; - unsigned long reserve_1:1; - unsigned long rxok:1; - unsigned long frame_length:11; - unsigned long reverve_2:4; - unsigned long own_bit:1; - } - bits; - unsigned long lw; - } - rx_status; - - union VTC_rx_ctrl_tag - { - struct - { - unsigned long rx_buf_size:11; - unsigned long extend_rx_buf_size:4; - unsigned long reserved_1:17; - } - bits; - unsigned long lw; - } - rx_ctrl; - - unsigned long buf_addr_1:32; - unsigned long buf_addr_2:32; - -}; - -struct { - char txbuf[TX_RING_SIZE * PKT_BUF_SZ + 32]; - char rxbuf[RX_RING_SIZE * PKT_BUF_SZ + 32]; - char txdesc[TX_RING_SIZE * sizeof (struct rhine_tx_desc) + 32]; - char rxdesc[RX_RING_SIZE * sizeof (struct rhine_rx_desc) + 32]; -} rhine_buffers __shared; - -/* The I/O extent. */ -#define rhine_TOTAL_SIZE 0x80 - -#ifdef HAVE_DEVLIST -struct netdev_entry rhine_drv = - { "rhine", rhine_probe, rhine_TOTAL_SIZE, NULL }; -#endif - -static int rhine_debug = 1; - -/* - Theory of Operation - -I. Board Compatibility - -This driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet -controller. - -II. Board-specific settings - -Boards with this chip are functional only in a bus-master PCI slot. - -Many operational settings are loaded from the EEPROM to the Config word at -offset 0x78. This driver assumes that they are correct. -If this driver is compiled to use PCI memory space operations the EEPROM -must be configured to enable memory ops. - -III. Driver operation - -IIIa. Ring buffers - -This driver uses two statically allocated fixed-size descriptor lists -formed into rings by a branch from the final descriptor to the beginning of -the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. - -IIIb/c. Transmit/Receive Structure - -This driver attempts to use a zero-copy receive and transmit scheme. - -Alas, all data buffers are required to start on a 32 bit boundary, so -the driver must often copy transmit packets into bounce buffers. - -The driver allocates full frame size skbuffs for the Rx ring buffers at -open() time and passes the skb->data field to the chip as receive data -buffers. When an incoming frame is less than RX_COPYBREAK bytes long, -a fresh skbuff is allocated and the frame is copied to the new skbuff. -When the incoming frame is larger, the skbuff is passed directly up the -protocol stack. Buffers consumed this way are replaced by newly allocated -skbuffs in the last phase of netdev_rx(). - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. New boards are typically used in generously configured machines -and the underfilled buffers have negligible impact compared to the benefit of -a single allocation size, so the default value of zero results in never -copying packets. When copying is done, the cost is usually mitigated by using -a combined copy/checksum routine. Copying also preloads the cache, which is -most useful with small frames. - -Since the VIA chips are only able to transfer data to buffers on 32 bit -boundaries, the the IP header at offset 14 in an ethernet frame isn't -longword aligned for further processing. Copying these unaligned buffers -has the beneficial effect of 16-byte aligning the IP header. - -IIId. Synchronization - -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and interrupt handling software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'lp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. - -IV. Notes - -IVb. References - -Preliminary VT86C100A manual from http://www.via.com.tw/ -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - -IVc. Errata - -The VT86C100A manual is not reliable information. -The chip does not handle unaligned transmit or receive buffers, resulting -in significant performance degradation for bounce buffer copies on transmit -and unaligned IP headers on receive. -The chip does not pad to minimum transmit length. - -*/ - -/* The rest of these values should never change. */ -#define NUM_TX_DESC 2 /* Number of Tx descriptor registers. */ - -static struct rhine_private -{ - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct rhine_rx_desc *rx_ring; - struct rhine_tx_desc *tx_ring; - char *rx_buffs[RX_RING_SIZE]; - char *tx_buffs[TX_RING_SIZE]; - - /* temporary Rx buffers. */ - - int chip_id; - int chip_revision; - unsigned short ioaddr; - unsigned int cur_rx, cur_tx; /* The next free and used entries */ - unsigned int dirty_rx, dirty_tx; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - unsigned char mc_filter[8]; /* Current multicast filter. */ - char phys[4]; /* MII device addresses. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ -} -rhine; - -static void rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, - int chip_id, int options); -static int QueryAuto (int); -static int ReadMII (int byMIIIndex, int); -static void WriteMII (char, char, char, int); -static void MIIDelay (void); -static void rhine_init_ring (struct nic *dev); -static void rhine_disable (struct nic *nic); -static void rhine_reset (struct nic *nic); -static int rhine_poll (struct nic *nic, int retrieve); -static void rhine_transmit (struct nic *nic, const char *d, unsigned int t, - unsigned int s, const char *p); -static void reload_eeprom(int ioaddr); - - -static void reload_eeprom(int ioaddr) -{ - int i; - outb(0x20, byEECSR); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (inb(byEECSR) & 0x20)) - break; -} -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -rhine_init_ring (struct nic *nic) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int i; - - tp->tx_full = 0; - tp->cur_rx = tp->cur_tx = 0; - tp->dirty_rx = tp->dirty_tx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) - { - - tp->rx_ring[i].rx_status.bits.own_bit = 1; - tp->rx_ring[i].rx_ctrl.bits.rx_buf_size = 1536; - - tp->rx_ring[i].buf_addr_1 = virt_to_bus (tp->rx_buffs[i]); - tp->rx_ring[i].buf_addr_2 = virt_to_bus (&tp->rx_ring[i + 1]); - /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->rx_ring[i].buf_addr_1,tp->rx_ring[i].buf_addr_2); */ - } - /* Mark the last entry as wrapping the ring. */ - /* tp->rx_ring[i-1].rx_ctrl.bits.rx_buf_size =1518; */ - tp->rx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->rx_ring[0]); - /*printf("[%d]buf1=%hX,buf2=%hX",i-1,tp->rx_ring[i-1].buf_addr_1,tp->rx_ring[i-1].buf_addr_2); */ - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - - for (i = 0; i < TX_RING_SIZE; i++) - { - - tp->tx_ring[i].tx_status.lw = 0; - tp->tx_ring[i].tx_ctrl.lw = 0x00e08000; - tp->tx_ring[i].buf_addr_1 = virt_to_bus (tp->tx_buffs[i]); - tp->tx_ring[i].buf_addr_2 = virt_to_bus (&tp->tx_ring[i + 1]); - /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i].buf_addr_1,tp->tx_ring[i].buf_addr_2); */ - } - - tp->tx_ring[i - 1].buf_addr_2 = virt_to_bus (&tp->tx_ring[0]); - /* printf("[%d]buf1=%hX,buf2=%hX",i,tp->tx_ring[i-1].buf_addr_1,tp->tx_ring[i-1].buf_addr_2); */ -} - -int -QueryAuto (int ioaddr) -{ - int byMIIIndex; - int MIIReturn; - - int advertising,mii_reg5; - int negociated; - - byMIIIndex = 0x04; - MIIReturn = ReadMII (byMIIIndex, ioaddr); - advertising=MIIReturn; - - byMIIIndex = 0x05; - MIIReturn = ReadMII (byMIIIndex, ioaddr); - mii_reg5=MIIReturn; - - negociated=mii_reg5 & advertising; - - if ( (negociated & 0x100) || (negociated & 0x1C0) == 0x40 ) - return 1; - else - return 0; - -} - -int -ReadMII (int byMIIIndex, int ioaddr) -{ - int ReturnMII; - char byMIIAdrbak; - char byMIICRbak; - char byMIItemp; - unsigned long ct; - - byMIIAdrbak = inb (byMIIAD); - byMIICRbak = inb (byMIICR); - outb (byMIICRbak & 0x7f, byMIICR); - MIIDelay (); - - outb (byMIIIndex, byMIIAD); - MIIDelay (); - - outb (inb (byMIICR) | 0x40, byMIICR); - - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - - ct = currticks(); - while (byMIItemp != 0 && ct + 2*1000 < currticks()) - { - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - } - MIIDelay (); - - ReturnMII = inw (wMIIDATA); - - outb (byMIIAdrbak, byMIIAD); - outb (byMIICRbak, byMIICR); - MIIDelay (); - - return (ReturnMII); - -} - -void -WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr) -{ - int ReadMIItmp; - int MIIMask; - char byMIIAdrbak; - char byMIICRbak; - char byMIItemp; - unsigned long ct; - - - byMIIAdrbak = inb (byMIIAD); - - byMIICRbak = inb (byMIICR); - outb (byMIICRbak & 0x7f, byMIICR); - MIIDelay (); - outb (byMIISetByte, byMIIAD); - MIIDelay (); - - outb (inb (byMIICR) | 0x40, byMIICR); - - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - - ct = currticks(); - while (byMIItemp != 0 && ct + 2*1000 < currticks()) - { - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x40; - } - MIIDelay (); - - ReadMIItmp = inw (wMIIDATA); - MIIMask = 0x0001; - MIIMask = MIIMask << byMIISetBit; - - - if (byMIIOP == 0) - { - MIIMask = ~MIIMask; - ReadMIItmp = ReadMIItmp & MIIMask; - } - else - { - ReadMIItmp = ReadMIItmp | MIIMask; - - } - outw (ReadMIItmp, wMIIDATA); - MIIDelay (); - - outb (inb (byMIICR) | 0x20, byMIICR); - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x20; - - ct = currticks(); - while (byMIItemp != 0 && ct + 2*1000 < currticks()) - { - byMIItemp = inb (byMIICR); - byMIItemp = byMIItemp & 0x20; - } - MIIDelay (); - - outb (byMIIAdrbak & 0x7f, byMIIAD); - outb (byMIICRbak, byMIICR); - MIIDelay (); - -} - -void -MIIDelay (void) -{ - int i; - for (i = 0; i < 0x7fff; i++) - { - ( void ) inb (0x61); - ( void ) inb (0x61); - ( void ) inb (0x61); - ( void ) inb (0x61); - } -} - -/* Offsets to the device registers. */ -enum register_offsets { - StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, - IntrStatus=0x0C, IntrEnable=0x0E, - MulticastFilter0=0x10, MulticastFilter1=0x14, - RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, - MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, - MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74, - ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, - RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, - StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7, - PwrcsrClr=0xAC, -}; - -/* Bits in the interrupt status/mask registers. */ -enum intr_status_bits { - IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, - IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210, - IntrPCIErr=0x0040, - IntrStatsMax=0x0080, IntrRxEarly=0x0100, - IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, - IntrTxAborted=0x2000, IntrLinkChange=0x4000, - IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, - IntrTxDescRace=0x080000, /* mapped from IntrStatus2 */ - IntrTxErrSummary=0x082218, -}; -#define DEFAULT_INTR (IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | \ - IntrRxDropped | IntrRxNoBuf) - -/*************************************************************************** - IRQ - PXE IRQ Handler -***************************************************************************/ -void rhine_irq ( struct nic *nic, irq_action_t action ) { - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - /* Enable interrupts by setting the interrupt mask. */ - unsigned int intr_status; - - switch ( action ) { - case DISABLE : - case ENABLE : - intr_status = inw(nic->ioaddr + IntrStatus); - /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */ - - /* added comment by guard */ - /* For supporting VT6107, please use revision id to recognize different chips in driver */ - // if (tp->chip_id == 0x3065) - if( tp->chip_revision < 0x80 && tp->chip_revision >=0x40 ) - intr_status |= inb(nic->ioaddr + IntrStatus2) << 16; - intr_status = (intr_status & ~DEFAULT_INTR); - if ( action == ENABLE ) - intr_status = intr_status | DEFAULT_INTR; - outw(intr_status, nic->ioaddr + IntrEnable); - break; - case FORCE : - outw(0x0010, nic->ioaddr + 0x84); - break; - } -} - -static struct nic_operations rhine_operations; - -static int -rhine_probe ( struct nic *nic, struct pci_device *pci ) { - - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - - if (!pci->ioaddr) - return 0; - - rhine_probe1 (nic, pci, pci->ioaddr, pci->device, -1); - - adjust_pci_device ( pci ); - - rhine_reset (nic); - - nic->nic_op = &rhine_operations; - - nic->irqno = pci->irq; - nic->ioaddr = tp->ioaddr; - - return 1; -} - -static void set_rx_mode(struct nic *nic __unused) { - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - unsigned char rx_mode; - int ioaddr = tp->ioaddr; - - /* ! IFF_PROMISC */ - outl(0xffffffff, byMAR0); - outl(0xffffffff, byMAR4); - rx_mode = 0x0C; - - outb(0x60 /* thresh */ | rx_mode, byRCR ); -} - -static void -rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id, int options) -{ - struct rhine_private *tp; - static int did_version = 0; /* Already printed version info. */ - unsigned int i, ww; - unsigned int timeout; - int FDXFlag; - int byMIIvalue, LineSpeed, MIICRbak; - uint8_t revision_id; - unsigned char mode3_reg; - - if (rhine_debug > 0 && did_version++ == 0) - printf ("%s",version); - - // get revision id. - pci_read_config_byte(pci, PCI_REVISION, &revision_id); - - /* D-Link provided reset code (with comment additions) */ - if (revision_id >= 0x40) { - unsigned char byOrgValue; - - if(rhine_debug > 0) - printf("Enabling Sticky Bit Workaround for Chip_id: 0x%hX\n" - , chip_id); - /* clear sticky bit before reset & read ethernet address */ - byOrgValue = inb(bySTICKHW); - byOrgValue = byOrgValue & 0xFC; - outb(byOrgValue, bySTICKHW); - - /* (bits written are cleared?) */ - /* disable force PME-enable */ - outb(0x80, byWOLcgClr); - /* disable power-event config bit */ - outb(0xFF, byWOLcrClr); - /* clear power status (undocumented in vt6102 docs?) */ - outb(0xFF, byPwrcsrClr); - - } - - /* Reset the chip to erase previous misconfiguration. */ - outw(CR_SFRST, byCR0); - // if vt3043 delay after reset - if (revision_id <0x40) { - udelay(10000); - } - // polling till software reset complete - // W_MAX_TIMEOUT is the timeout period - for(ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if ((inw(byCR0) & CR_SFRST) == 0) - break; - } - - // issue AUTOLoad in EECSR to reload eeprom - outb(0x20, byEECSR ); - - // if vt3065 delay after reset - if (revision_id >=0x40) { - // delay 8ms to let MAC stable - mdelay(8); - /* - * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA - * turned on. it makes MAC receive magic packet - * automatically. So, we turn it off. (D-Link) - */ - outb(inb(byCFGA) & 0xFE, byCFGA); - } - - /* turn on bit2 in PCI configuration register 0x53 , only for 3065*/ - if (revision_id >= 0x40) { - pci_read_config_byte(pci, PCI_REG_MODE3, &mode3_reg); - pci_write_config_byte(pci, PCI_REG_MODE3, mode3_reg|MODE3_MIION); - } - - - /* back off algorithm ,disable the right-most 4-bit off CFGD*/ - outb(inb(byCFGD) & (~(CFGD_RANDOM | CFGD_CFDX | CFGD_CEREN | CFGD_CETEN)), byCFGD); - - /* reload eeprom */ - reload_eeprom(ioaddr); - - /* Perhaps this should be read from the EEPROM? */ - for (i = 0; i < ETH_ALEN; i++) - nic->node_addr[i] = inb (byPAR0 + i); - - DBG ( "IO address %#hX Ethernet Address: %s\n", ioaddr, eth_ntoa ( nic->node_addr ) ); - - /* restart MII auto-negotiation */ - WriteMII (0, 9, 1, ioaddr); - printf ("Analyzing Media type,this may take several seconds... "); - for (i = 0; i < 5; i++) - { - /* need to wait 1 millisecond - we will round it up to 50-100ms */ - timeout = currticks() + 2; - for (timeout = currticks() + 2; currticks() < timeout;) - /* nothing */; - if (ReadMII (1, ioaddr) & 0x0020) - break; - } - printf ("OK.\n"); - -#if 0 - /* JJM : for Debug */ - printf("MII : Address %hhX ",inb(ioaddr+0x6c)); - { - unsigned char st1,st2,adv1,adv2,l1,l2; - - st1=ReadMII(1,ioaddr)>>8; - st2=ReadMII(1,ioaddr)&0xFF; - adv1=ReadMII(4,ioaddr)>>8; - adv2=ReadMII(4,ioaddr)&0xFF; - l1=ReadMII(5,ioaddr)>>8; - l2=ReadMII(5,ioaddr)&0xFF; - printf(" status 0x%hhX%hhX, advertising 0x%hhX%hhX, link 0x%hhX%hhX\n", st1,st2,adv1,adv2,l1,l2); - } -#endif - - - /* query MII to know LineSpeed,duplex mode */ - byMIIvalue = inb (ioaddr + 0x6d); - LineSpeed = byMIIvalue & MIISR_SPEED; - if (LineSpeed != 0) //JJM - { - printf ("Linespeed=10Mbs"); - } - else - { - printf ("Linespeed=100Mbs"); - } - - FDXFlag = QueryAuto (ioaddr); - if (FDXFlag == 1) - { - printf (" Fullduplex\n"); - outw (CR_FDX, byCR0); - } - else - { - printf (" Halfduplex\n"); - } - - - /* set MII 10 FULL ON, only apply in vt3043 */ - if(chip_id == 0x3043) - WriteMII (0x17, 1, 1, ioaddr); - - /* turn on MII link change */ - MIICRbak = inb (byMIICR); - outb (MIICRbak & 0x7F, byMIICR); - MIIDelay (); - outb (0x41, byMIIAD); - MIIDelay (); - - /* while((inb(byMIIAD)&0x20)==0) ; */ - outb (MIICRbak | 0x80, byMIICR); - - nic->priv_data = &rhine; - tp = &rhine; - tp->chip_id = chip_id; - tp->ioaddr = ioaddr; - tp->phys[0] = -1; - tp->chip_revision = revision_id; - - /* The lower four bits are the media type. */ - if (options > 0) - { - tp->full_duplex = (options & 16) ? 1 : 0; - tp->default_port = options & 15; - if (tp->default_port) - tp->medialock = 1; - } - return; -} - -static void -rhine_disable ( struct nic *nic ) { - - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int ioaddr = tp->ioaddr; - - rhine_reset(nic); - - printf ("rhine disable\n"); - /* Switch to loopback mode to avoid hardware races. */ - outb(0x60 | 0x01, byTCR); - /* Stop the chip's Tx and Rx processes. */ - outw(CR_STOP, byCR0); -} - -/************************************************************************** -ETH_RESET - Reset adapter -***************************************************************************/ -static void -rhine_reset (struct nic *nic) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int ioaddr = tp->ioaddr; - int i, j; - int FDXFlag, CRbak; - void *rx_ring_tmp; - void *tx_ring_tmp; - void *rx_bufs_tmp; - void *tx_bufs_tmp; - unsigned long rx_ring_tmp1; - unsigned long tx_ring_tmp1; - unsigned long rx_bufs_tmp1; - unsigned long tx_bufs_tmp1; - - /* printf ("rhine_reset\n"); */ - /* Soft reset the chip. */ - /*outb(CmdReset, ioaddr + ChipCmd); */ - - tx_bufs_tmp = rhine_buffers.txbuf; - tx_ring_tmp = rhine_buffers.txdesc; - rx_bufs_tmp = rhine_buffers.rxbuf; - rx_ring_tmp = rhine_buffers.rxdesc; - - /* tune RD TD 32 byte alignment */ - rx_ring_tmp1 = virt_to_bus ( rx_ring_tmp ); - j = (rx_ring_tmp1 + 32) & (~0x1f); - /* printf ("txring[%d]", j); */ - tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j); - - tx_ring_tmp1 = virt_to_bus ( tx_ring_tmp ); - j = (tx_ring_tmp1 + 32) & (~0x1f); - tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j); - /* printf ("rxring[%X]", j); */ - - - tx_bufs_tmp1 = virt_to_bus ( tx_bufs_tmp ); - j = (int) (tx_bufs_tmp1 + 32) & (~0x1f); - tx_bufs_tmp = bus_to_virt (j); - /* printf ("txb[%X]", j); */ - - rx_bufs_tmp1 = virt_to_bus ( rx_bufs_tmp ); - j = (int) (rx_bufs_tmp1 + 32) & (~0x1f); - rx_bufs_tmp = bus_to_virt (j); - /* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */ - - for (i = 0; i < RX_RING_SIZE; i++) - { - tp->rx_buffs[i] = (char *) rx_bufs_tmp; - /* printf("r[%X]",tp->rx_buffs[i]); */ - rx_bufs_tmp += 1536; - } - - for (i = 0; i < TX_RING_SIZE; i++) - { - tp->tx_buffs[i] = (char *) tx_bufs_tmp; - /* printf("t[%X]",tp->tx_buffs[i]); */ - tx_bufs_tmp += 1536; - } - - /* software reset */ - outb (CR1_SFRST, byCR1); - MIIDelay (); - - /* printf ("init ring"); */ - rhine_init_ring (nic); - /*write TD RD Descriptor to MAC */ - outl (virt_to_bus (tp->rx_ring), dwCurrentRxDescAddr); - outl (virt_to_bus (tp->tx_ring), dwCurrentTxDescAddr); - - /* Setup Multicast */ - set_rx_mode(nic); - - /* set TCR RCR threshold to store and forward*/ - outb (0x3e, byBCR0); - outb (0x38, byBCR1); - outb (0x2c, byRCR); - outb (0x60, byTCR); - /* Set Fulldupex */ - FDXFlag = QueryAuto (ioaddr); - if (FDXFlag == 1) - { - outb (CFGD_CFDX, byCFGD); - outw (CR_FDX, byCR0); - } - - /* KICK NIC to WORK */ - CRbak = inw (byCR0); - CRbak = CRbak & 0xFFFB; /* not CR_STOP */ - outw ((CRbak | CR_STRT | CR_TXON | CR_RXON | CR_DPOLL), byCR0); - - /* disable all known interrupt */ - outw (0, byIMR0); -} -/* Beware of PCI posted writes */ -#define IOSYNC do { inb(nic->ioaddr + StationAddr); } while (0) - -static int -rhine_poll (struct nic *nic, int retrieve) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int rxstatus, good = 0;; - - if (tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit == 0) - { - unsigned int intr_status; - /* There is a packet ready */ - if(!retrieve) - return 1; - - intr_status = inw(nic->ioaddr + IntrStatus); - /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */ -#if 0 - if (tp->chip_id == 0x3065) - intr_status |= inb(nic->ioaddr + IntrStatus2) << 16; -#endif - /* Acknowledge all of the current interrupt sources ASAP. */ - if (intr_status & IntrTxDescRace) - outb(0x08, nic->ioaddr + IntrStatus2); - outw(intr_status & 0xffff, nic->ioaddr + IntrStatus); - IOSYNC; - - rxstatus = tp->rx_ring[tp->cur_rx].rx_status.lw; - if ((rxstatus & 0x0300) != 0x0300) - { - printf("rhine_poll: bad status\n"); - } - else if (rxstatus & (RSR_ABNORMAL)) - { - printf ("rxerr[%X]\n", rxstatus); - } - else - good = 1; - - if (good) - { - nic->packetlen = tp->rx_ring[tp->cur_rx].rx_status.bits.frame_length; - memcpy (nic->packet, tp->rx_buffs[tp->cur_rx], nic->packetlen); - /* printf ("Packet RXed\n"); */ - } - tp->rx_ring[tp->cur_rx].rx_status.bits.own_bit = 1; - tp->cur_rx++; - tp->cur_rx = tp->cur_rx % RX_RING_SIZE; - } - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(DEFAULT_INTR & ~IntrRxDone, nic->ioaddr + IntrStatus); - - IOSYNC; - - return good; -} - -static void -rhine_transmit (struct nic *nic, - const char *d, unsigned int t, unsigned int s, const char *p) -{ - struct rhine_private *tp = (struct rhine_private *) nic->priv_data; - int ioaddr = tp->ioaddr; - int entry; - unsigned char CR1bak; - unsigned char CR0bak; - unsigned int nstype; - unsigned long ct; - - - /*printf ("rhine_transmit\n"); */ - /* setup ethernet header */ - - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % TX_RING_SIZE; - - memcpy (tp->tx_buffs[entry], d, ETH_ALEN); /* dst */ - memcpy (tp->tx_buffs[entry] + ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */ - - nstype=htons(t); - memcpy(tp->tx_buffs[entry] + 2 * ETH_ALEN, (char*)&nstype, 2); - - memcpy (tp->tx_buffs[entry] + ETH_HLEN, p, s); - s += ETH_HLEN; - while (s < ETH_ZLEN) - *((char *) tp->tx_buffs[entry] + (s++)) = 0; - - tp->tx_ring[entry].tx_ctrl.bits.tx_buf_size = s; - - tp->tx_ring[entry].tx_status.bits.own_bit = 1; - - - CR1bak = inb (byCR1); - - CR1bak = CR1bak | CR1_TDMD1; - /*printf("tdsw=[%X]",tp->tx_ring[entry].tx_status.lw); */ - /*printf("tdcw=[%X]",tp->tx_ring[entry].tx_ctrl.lw); */ - /*printf("tdbuf1=[%X]",tp->tx_ring[entry].buf_addr_1); */ - /*printf("tdbuf2=[%X]",tp->tx_ring[entry].buf_addr_2); */ - /*printf("td1=[%X]",inl(dwCurrentTDSE0)); */ - /*printf("td2=[%X]",inl(dwCurrentTDSE1)); */ - /*printf("td3=[%X]",inl(dwCurrentTDSE2)); */ - /*printf("td4=[%X]",inl(dwCurrentTDSE3)); */ - - outb (CR1bak, byCR1); - do - { - ct = currticks(); - /* Wait until transmit is finished or timeout*/ - while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) && - ct + 10*1000 < currticks()) - ; - - if(tp->tx_ring[entry].tx_status.bits.terr == 0) - break; - - if(tp->tx_ring[entry].tx_status.bits.abt == 1) - { - // turn on TX - CR0bak = inb(byCR0); - CR0bak = CR0bak|CR_TXON; - outb(CR0bak,byCR0); - } - }while(0); - tp->cur_tx++; - - /*outw(IMRShadow,byIMR0); */ - /*dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE); */ - /*tp->tx_skbuff[entry] = 0; */ -} - -static struct nic_operations rhine_operations = { - .connect = dummy_connect, - .poll = rhine_poll, - .transmit = rhine_transmit, - .irq = rhine_irq, - -}; - -static struct pci_device_id rhine_nics[] = { -PCI_ROM(0x1106, 0x3065, "dlink-530tx", "VIA 6102", 0), -PCI_ROM(0x1106, 0x3106, "via-rhine-6105", "VIA 6105", 0), -PCI_ROM(0x1106, 0x3043, "dlink-530tx-old", "VIA 3043", 0), /* Rhine-I 86c100a */ -PCI_ROM(0x1106, 0x3053, "via6105m", "VIA 6105M", 0), -PCI_ROM(0x1106, 0x6100, "via-rhine-old", "VIA 86C100A", 0), /* Rhine-II */ -}; - -PCI_DRIVER ( rhine_driver, rhine_nics, PCI_NO_CLASS ); - -DRIVER ( "VIA 86C100", nic_driver, pci_driver, rhine_driver, - rhine_probe, rhine_disable ); - -/* EOF via-rhine.c */ - -/* - * Local variables: - * c-basic-offset: 8 - * c-indent-level: 8 - * tab-width: 8 - * End: - */ diff --git a/roms/ipxe/src/drivers/net/via-velocity.c b/roms/ipxe/src/drivers/net/via-velocity.c deleted file mode 100644 index 9ba0b093d..000000000 --- a/roms/ipxe/src/drivers/net/via-velocity.c +++ /dev/null @@ -1,1927 +0,0 @@ -/************************************************************************** -* via-velocity.c: Etherboot device driver for the VIA 6120 Gigabit -* Changes for Etherboot port: -* Copyright (c) 2006 by Timothy Legge <tlegge@rogers.com> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -* 02110-1301, USA. -* -* This driver is based on: -* via-velocity.c: VIA Velocity VT6120, VT6122 Ethernet driver -* The changes are (c) Copyright 2004, Red Hat Inc. -* <alan@redhat.com> -* Additional fixes and clean up: Francois Romieu -* -* Original code: -* Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. -* All rights reserved. -* Author: Chuang Liang-Shing, AJ Jiang -* -* Linux Driver Version 2.6.15.4 -* -* REVISION HISTORY: -* ================ -* -* v1.0 03-06-2006 timlegge Initial port of Linux driver -* -* Indent Options: indent -kr -i8 -*************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "etherboot.h" -#include "nic.h" -#include <ipxe/pci.h> -#include <ipxe/ethernet.h> - -#include "via-velocity.h" - -typedef int pci_power_t; - -#define PCI_D0 ((int) 0) -#define PCI_D1 ((int) 1) -#define PCI_D2 ((int) 2) -#define PCI_D3hot ((int) 3) -#define PCI_D3cold ((int) 4) -#define PCI_POWER_ERROR ((int) -1) - - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -//FIXME: Move to pci.c -int pci_set_power_state(struct pci_device *dev, int state); - -/* FIXME: Move BASE to the private structure */ -static u32 BASE; - -/* NIC specific static variables go here */ -#define VELOCITY_PARAM(N,D) \ - static const int N[MAX_UNITS]=OPTION_DEFAULT; -/* MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\ - MODULE_PARM_DESC(N, D); */ - -VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors"); -VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors"); - - -#define VLAN_ID_MIN 0 -#define VLAN_ID_MAX 4095 -#define VLAN_ID_DEF 0 -/* VID_setting[] is used for setting the VID of NIC. - 0: default VID. - 1-4094: other VIDs. -*/ -VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID"); - -#define RX_THRESH_MIN 0 -#define RX_THRESH_MAX 3 -#define RX_THRESH_DEF 0 -/* rx_thresh[] is used for controlling the receive fifo threshold. - 0: indicate the rxfifo threshold is 128 bytes. - 1: indicate the rxfifo threshold is 512 bytes. - 2: indicate the rxfifo threshold is 1024 bytes. - 3: indicate the rxfifo threshold is store & forward. -*/ -VELOCITY_PARAM(rx_thresh, "Receive fifo threshold"); - -#define DMA_LENGTH_MIN 0 -#define DMA_LENGTH_MAX 7 -#define DMA_LENGTH_DEF 0 - -/* DMA_length[] is used for controlling the DMA length - 0: 8 DWORDs - 1: 16 DWORDs - 2: 32 DWORDs - 3: 64 DWORDs - 4: 128 DWORDs - 5: 256 DWORDs - 6: SF(flush till emply) - 7: SF(flush till emply) -*/ -VELOCITY_PARAM(DMA_length, "DMA length"); - -#define TAGGING_DEF 0 -/* enable_tagging[] is used for enabling 802.1Q VID tagging. - 0: disable VID seeting(default). - 1: enable VID setting. -*/ -VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging"); - -#define IP_ALIG_DEF 0 -/* IP_byte_align[] is used for IP header DWORD byte aligned - 0: indicate the IP header won't be DWORD byte aligned.(Default) . - 1: indicate the IP header will be DWORD byte aligned. - In some environment, the IP header should be DWORD byte aligned, - or the packet will be droped when we receive it. (eg: IPVS) -*/ -VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned"); - -#define TX_CSUM_DEF 1 -/* txcsum_offload[] is used for setting the checksum offload ability of NIC. - (We only support RX checksum offload now) - 0: disable csum_offload[checksum offload - 1: enable checksum offload. (Default) -*/ -VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload"); - -#define FLOW_CNTL_DEF 1 -#define FLOW_CNTL_MIN 1 -#define FLOW_CNTL_MAX 5 - -/* flow_control[] is used for setting the flow control ability of NIC. - 1: hardware deafult - AUTO (default). Use Hardware default value in ANAR. - 2: enable TX flow control. - 3: enable RX flow control. - 4: enable RX/TX flow control. - 5: disable -*/ -VELOCITY_PARAM(flow_control, "Enable flow control ability"); - -#define MED_LNK_DEF 0 -#define MED_LNK_MIN 0 -#define MED_LNK_MAX 4 -/* speed_duplex[] is used for setting the speed and duplex mode of NIC. - 0: indicate autonegotiation for both speed and duplex mode - 1: indicate 100Mbps half duplex mode - 2: indicate 100Mbps full duplex mode - 3: indicate 10Mbps half duplex mode - 4: indicate 10Mbps full duplex mode - - Note: - if EEPROM have been set to the force mode, this option is ignored - by driver. -*/ -VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode"); - -#define VAL_PKT_LEN_DEF 0 -/* ValPktLen[] is used for setting the checksum offload ability of NIC. - 0: Receive frame with invalid layer 2 length (Default) - 1: Drop frame with invalid layer 2 length -*/ -VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame"); - -#define WOL_OPT_DEF 0 -#define WOL_OPT_MIN 0 -#define WOL_OPT_MAX 7 -/* wol_opts[] is used for controlling wake on lan behavior. - 0: Wake up if recevied a magic packet. (Default) - 1: Wake up if link status is on/off. - 2: Wake up if recevied an arp packet. - 4: Wake up if recevied any unicast packet. - Those value can be sumed up to support more than one option. -*/ -VELOCITY_PARAM(wol_opts, "Wake On Lan options"); - -#define INT_WORKS_DEF 20 -#define INT_WORKS_MIN 10 -#define INT_WORKS_MAX 64 - -VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); - -/* The descriptors for this card are required to be aligned on -64 byte boundaries. As the align attribute does not guarantee alignment -greater than the alignment of the start address (which for Etherboot -is 16 bytes of alignment) it requires some extra steps. Add 64 to the -size of the array and the init_ring adjusts the alignment */ - -/* Define the TX Descriptor */ -static u8 tx_ring[TX_DESC_DEF * sizeof(struct tx_desc) + 64]; - -/* Create a static buffer of size PKT_BUF_SZ for each TX Descriptor. -All descriptors point to a part of this buffer */ -static u8 txb[(TX_DESC_DEF * PKT_BUF_SZ) + 64]; - -/* Define the RX Descriptor */ -static u8 rx_ring[RX_DESC_DEF * sizeof(struct rx_desc) + 64]; - -/* Create a static buffer of size PKT_BUF_SZ for each RX Descriptor - All descriptors point to a part of this buffer */ -static u8 rxb[(RX_DESC_DEF * PKT_BUF_SZ) + 64]; - -static void velocity_init_info(struct pci_device *pdev, - struct velocity_info *vptr, - struct velocity_info_tbl *info); -static int velocity_get_pci_info(struct velocity_info *, - struct pci_device *pdev); -static int velocity_open(struct nic *nic, struct pci_device *pci); - -static int velocity_soft_reset(struct velocity_info *vptr); -static void velocity_init_cam_filter(struct velocity_info *vptr); -static void mii_init(struct velocity_info *vptr, u32 mii_status); -static u32 velocity_get_opt_media_mode(struct velocity_info *vptr); -static void velocity_print_link_status(struct velocity_info *vptr); -static void safe_disable_mii_autopoll(struct mac_regs *regs); -static void enable_flow_control_ability(struct velocity_info *vptr); -static void enable_mii_autopoll(struct mac_regs *regs); -static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata); -static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data); -static u32 mii_check_media_mode(struct mac_regs *regs); -static u32 check_connection_type(struct mac_regs *regs); -static int velocity_set_media_mode(struct velocity_info *vptr, - u32 mii_status); - - -/* - * Internal board variants. At the moment we have only one - */ - -static struct velocity_info_tbl chip_info_table[] = { - {CHIP_TYPE_VT6110, - "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, - 0x00FFFFFFUL}, - {0, NULL, 0, 0, 0} -}; - -/** - * velocity_set_int_opt - parser for integer options - * @opt: pointer to option value - * @val: value the user requested (or -1 for default) - * @min: lowest value allowed - * @max: highest value allowed - * @def: default value - * @name: property name - * @dev: device name - * - * Set an integer property in the module options. This function does - * all the verification and checking as well as reporting so that - * we don't duplicate code for each option. - */ - -static void velocity_set_int_opt(int *opt, int val, int min, int max, - int def, char *name, const char *devname) -{ - if (val == -1) { - printf("%s: set value of parameter %s to %d\n", - devname, name, def); - *opt = def; - } else if (val < min || val > max) { - printf - ("%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n", - devname, name, min, max); - *opt = def; - } else { - printf("%s: set value of parameter %s to %d\n", - devname, name, val); - *opt = val; - } -} - -/** - * velocity_set_bool_opt - parser for boolean options - * @opt: pointer to option value - * @val: value the user requested (or -1 for default) - * @def: default value (yes/no) - * @flag: numeric value to set for true. - * @name: property name - * @dev: device name - * - * Set a boolean property in the module options. This function does - * all the verification and checking as well as reporting so that - * we don't duplicate code for each option. - */ - -static void velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, - char *name, const char *devname) -{ - (*opt) &= (~flag); - if (val == -1) { - printf("%s: set parameter %s to %s\n", - devname, name, def ? "TRUE" : "FALSE"); - *opt |= (def ? flag : 0); - } else if (val < 0 || val > 1) { - printf - ("%s: the value of parameter %s is invalid, the valid range is (0-1)\n", - devname, name); - *opt |= (def ? flag : 0); - } else { - printf("%s: set parameter %s to %s\n", - devname, name, val ? "TRUE" : "FALSE"); - *opt |= (val ? flag : 0); - } -} - -/** - * velocity_get_options - set options on device - * @opts: option structure for the device - * @index: index of option to use in module options array - * @devname: device name - * - * Turn the module and command options into a single structure - * for the current device - */ - -static void velocity_get_options(struct velocity_opt *opts, int index, - const char *devname) -{ - - /* FIXME Do the options need to be configurable */ - velocity_set_int_opt(&opts->rx_thresh, -1, RX_THRESH_MIN, - RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh", - devname); - velocity_set_int_opt(&opts->DMA_length, DMA_length[index], - DMA_LENGTH_MIN, DMA_LENGTH_MAX, - DMA_LENGTH_DEF, "DMA_length", devname); - velocity_set_int_opt(&opts->numrx, RxDescriptors[index], - RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, - "RxDescriptors", devname); - velocity_set_int_opt(&opts->numtx, TxDescriptors[index], - TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, - "TxDescriptors", devname); - velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, - VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", - devname); - velocity_set_bool_opt(&opts->flags, enable_tagging[index], - TAGGING_DEF, VELOCITY_FLAGS_TAGGING, - "enable_tagging", devname); - velocity_set_bool_opt(&opts->flags, txcsum_offload[index], - TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, - "txcsum_offload", devname); - velocity_set_int_opt(&opts->flow_cntl, flow_control[index], - FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, - "flow_control", devname); - velocity_set_bool_opt(&opts->flags, IP_byte_align[index], - IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, - "IP_byte_align", devname); - velocity_set_bool_opt(&opts->flags, ValPktLen[index], - VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, - "ValPktLen", devname); - velocity_set_int_opt((void *) &opts->spd_dpx, speed_duplex[index], - MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, - "Media link mode", devname); - velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], - WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, - "Wake On Lan options", devname); - velocity_set_int_opt((int *) &opts->int_works, int_works[index], - INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, - "Interrupt service works", devname); - opts->numrx = (opts->numrx & ~3); -} - -/** - * velocity_init_cam_filter - initialise CAM - * @vptr: velocity to program - * - * Initialize the content addressable memory used for filters. Load - * appropriately according to the presence of VLAN - */ - -static void velocity_init_cam_filter(struct velocity_info *vptr) -{ - struct mac_regs *regs = vptr->mac_regs; - - /* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */ - WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, ®s->MCFG); - WORD_REG_BITS_ON(MCFG_VIDFR, ®s->MCFG); - - /* Disable all CAMs */ - memset(vptr->vCAMmask, 0, sizeof(u8) * 8); - memset(vptr->mCAMmask, 0, sizeof(u8) * 8); - mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM); - mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM); - - /* Enable first VCAM */ - if (vptr->flags & VELOCITY_FLAGS_TAGGING) { - /* If Tagging option is enabled and VLAN ID is not zero, then - turn on MCFG_RTGOPT also */ - if (vptr->options.vid != 0) - WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG); - - mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), - VELOCITY_VLAN_ID_CAM); - vptr->vCAMmask[0] |= 1; - mac_set_cam_mask(regs, vptr->vCAMmask, - VELOCITY_VLAN_ID_CAM); - } else { - u16 temp = 0; - mac_set_cam(regs, 0, (u8 *) & temp, VELOCITY_VLAN_ID_CAM); - temp = 1; - mac_set_cam_mask(regs, (u8 *) & temp, - VELOCITY_VLAN_ID_CAM); - } -} - -static inline void velocity_give_many_rx_descs(struct velocity_info *vptr) -{ - struct mac_regs *regs = vptr->mac_regs; - int avail, dirty, unusable; - - /* - * RD number must be equal to 4X per hardware spec - * (programming guide rev 1.20, p.13) - */ - if (vptr->rd_filled < 4) - return; - - wmb(); - - unusable = vptr->rd_filled & 0x0003; - dirty = vptr->rd_dirty - unusable; - for (avail = vptr->rd_filled & 0xfffc; avail; avail--) { - dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1; -// printf("return dirty: %d\n", dirty); - vptr->rd_ring[dirty].rdesc0.owner = OWNED_BY_NIC; - } - - writew(vptr->rd_filled & 0xfffc, ®s->RBRDU); - vptr->rd_filled = unusable; -} - -static int velocity_rx_refill(struct velocity_info *vptr) -{ - int dirty = vptr->rd_dirty, done = 0, ret = 0; - -// printf("rx_refill - rd_curr = %d, dirty = %d\n", vptr->rd_curr, dirty); - do { - struct rx_desc *rd = vptr->rd_ring + dirty; - - /* Fine for an all zero Rx desc at init time as well */ - if (rd->rdesc0.owner == OWNED_BY_NIC) - break; -// printf("rx_refill - after owner %d\n", dirty); - - rd->inten = 1; - rd->pa_high = 0; - rd->rdesc0.len = cpu_to_le32(vptr->rx_buf_sz);; - - done++; - dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0; - } while (dirty != vptr->rd_curr); - - if (done) { -// printf("\nGive Back Desc\n"); - vptr->rd_dirty = dirty; - vptr->rd_filled += done; - velocity_give_many_rx_descs(vptr); - } - - return ret; -} - -extern void hex_dump(const char *data, const unsigned int len); -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int velocity_poll(struct nic *nic, int retrieve) -{ - /* Work out whether or not there's an ethernet packet ready to - * read. Return 0 if not. - */ - - int rd_curr = vptr->rd_curr % RX_DESC_DEF; - struct rx_desc *rd = &(vptr->rd_ring[rd_curr]); - - if (rd->rdesc0.owner == OWNED_BY_NIC) - return 0; - rmb(); - - if ( ! retrieve ) return 1; - - /* - * Don't drop CE or RL error frame although RXOK is off - */ - if ((rd->rdesc0.RSR & RSR_RXOK) - || (!(rd->rdesc0.RSR & RSR_RXOK) - && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) { - - nic->packetlen = rd->rdesc0.len; - // ptr->rxb + (rd_curr * PKT_BUF_SZ) - memcpy(nic->packet, bus_to_virt(rd->pa_low), - nic->packetlen - 4); - - vptr->rd_curr++; - vptr->rd_curr = vptr->rd_curr % RX_DESC_DEF; - velocity_rx_refill(vptr); - return 1; /* Remove this line once this method is implemented */ - } - return 0; -} - -#define TX_TIMEOUT (1000); -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void velocity_transmit(struct nic *nic, const char *dest, /* Destination */ - unsigned int type, /* Type */ - unsigned int size, /* size */ - const char *packet) -{ /* Packet */ - u16 nstype; - u32 to; - u8 *ptxb; - unsigned int pktlen; - struct tx_desc *td_ptr; - - int entry = vptr->td_curr % TX_DESC_DEF; - td_ptr = &(vptr->td_rings[entry]); - - /* point to the current txb incase multiple tx_rings are used */ - ptxb = vptr->txb + (entry * PKT_BUF_SZ); - memcpy(ptxb, dest, ETH_ALEN); /* Destination */ - memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN); /* Source */ - nstype = htons((u16) type); /* Type */ - memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2); /* Type */ - memcpy(ptxb + ETH_HLEN, packet, size); - - td_ptr->tdesc1.TCPLS = TCPLS_NORMAL; - td_ptr->tdesc1.TCR = TCR0_TIC; - td_ptr->td_buf[0].queue = 0; - - size += ETH_HLEN; - while (size < ETH_ZLEN) /* pad to min length */ - ptxb[size++] = '\0'; - - if (size < ETH_ZLEN) { -// printf("Padd that packet\n"); - pktlen = ETH_ZLEN; -// memcpy(ptxb, skb->data, skb->len); - memset(ptxb + size, 0, ETH_ZLEN - size); - - vptr->td_rings[entry].tdesc0.pktsize = pktlen; - vptr->td_rings[entry].td_buf[0].pa_low = virt_to_bus(ptxb); - vptr->td_rings[entry].td_buf[0].pa_high &= - cpu_to_le32(0xffff0000UL); - vptr->td_rings[entry].td_buf[0].bufsize = - vptr->td_rings[entry].tdesc0.pktsize; - vptr->td_rings[entry].tdesc1.CMDZ = 2; - } else { -// printf("Correct size packet\n"); - td_ptr->tdesc0.pktsize = size; - td_ptr->td_buf[0].pa_low = virt_to_bus(ptxb); - td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize; -// tdinfo->nskb_dma = 1; - td_ptr->tdesc1.CMDZ = 2; - } - - if (vptr->flags & VELOCITY_FLAGS_TAGGING) { - td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff); - td_ptr->tdesc1.pqinf.priority = 0; - td_ptr->tdesc1.pqinf.CFI = 0; - td_ptr->tdesc1.TCR |= TCR0_VETAG; - } - - vptr->td_curr = (entry + 1); - - { - - int prev = entry - 1; - - if (prev < 0) - prev = TX_DESC_DEF - 1; - td_ptr->tdesc0.owner |= OWNED_BY_NIC; - td_ptr = &(vptr->td_rings[prev]); - td_ptr->td_buf[0].queue = 1; - mac_tx_queue_wake(vptr->mac_regs, 0); - - } - - to = currticks() + TX_TIMEOUT; - while ((td_ptr->tdesc0.owner & OWNED_BY_NIC) && (currticks() < to)); /* wait */ - - if (currticks() >= to) { - printf("TX Time Out"); - } - -} - -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void velocity_disable(struct nic *nic __unused) -{ - /* put the card in its initial state */ - /* This function serves 3 purposes. - * This disables DMA and interrupts so we don't receive - * unexpected packets or interrupts from the card after - * etherboot has finished. - * This frees resources so etherboot may use - * this driver on another interface - * This allows etherboot to reinitialize the interface - * if something is something goes wrong. - */ - struct mac_regs *regs = vptr->mac_regs; - mac_disable_int(regs); - writel(CR0_STOP, ®s->CR0Set); - writew(0xFFFF, ®s->TDCSRClr); - writeb(0xFF, ®s->RDCSRClr); - safe_disable_mii_autopoll(regs); - mac_clear_isr(regs); - - /* Power down the chip */ -// pci_set_power_state(vptr->pdev, PCI_D3hot); - - vptr->flags &= (~VELOCITY_FLAGS_OPENED); -} - -/************************************************************************** -IRQ - handle interrupts -***************************************************************************/ -static void velocity_irq(struct nic *nic __unused, irq_action_t action) -{ - /* This routine is somewhat optional. Etherboot itself - * doesn't use interrupts, but they are required under some - * circumstances when we're acting as a PXE stack. - * - * If you don't implement this routine, the only effect will - * be that your driver cannot be used via Etherboot's UNDI - * API. This won't affect programs that use only the UDP - * portion of the PXE API, such as pxelinux. - */ - - switch (action) { - case DISABLE: - case ENABLE: - /* Set receive interrupt enabled/disabled state */ - /* - outb ( action == ENABLE ? IntrMaskEnabled : IntrMaskDisabled, - nic->ioaddr + IntrMaskRegister ); - */ - break; - case FORCE: - /* Force NIC to generate a receive interrupt */ - /* - outb ( ForceInterrupt, nic->ioaddr + IntrForceRegister ); - */ - break; - } -} - -static struct nic_operations velocity_operations = { - .connect = dummy_connect, - .poll = velocity_poll, - .transmit = velocity_transmit, - .irq = velocity_irq, -}; - -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ -static int velocity_probe( struct nic *nic, struct pci_device *pci) -{ - int ret, i; - struct mac_regs *regs; - - printf("via-velocity.c: Found %s Vendor=0x%hX Device=0x%hX\n", - pci->id->name, pci->vendor, pci->device); - - /* point to private storage */ - vptr = &vptx; - info = chip_info_table; - - velocity_init_info(pci, vptr, info); - -//FIXME: pci_enable_device(pci); -//FIXME: pci_set_power_state(pci, PCI_D0); - - ret = velocity_get_pci_info(vptr, pci); - if (ret < 0) { - printf("Failed to find PCI device.\n"); - return 0; - } - - regs = ioremap(vptr->memaddr, vptr->io_size); - if (regs == NULL) { - printf("Unable to remap io\n"); - return 0; - } - - vptr->mac_regs = regs; - - BASE = vptr->ioaddr; - - printf("Chip ID: %hX\n", vptr->chip_id); - - for (i = 0; i < 6; i++) - nic->node_addr[i] = readb(®s->PAR[i]); - - DBG ( "%s: %s at ioaddr %#hX\n", pci->id->name, eth_ntoa ( nic->node_addr ), - (unsigned int) BASE ); - - velocity_get_options(&vptr->options, 0, pci->id->name); - - /* - * Mask out the options cannot be set to the chip - */ - vptr->options.flags &= 0x00FFFFFFUL; //info->flags = 0x00FFFFFFUL; - - /* - * Enable the chip specified capbilities - */ - - vptr->flags = - vptr->options. - flags | (0x00FFFFFFUL /*info->flags */ & 0xFF000000UL); - - vptr->wol_opts = vptr->options.wol_opts; - vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED; - - vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); - - if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) { - printf("features missing\n"); - } - - /* and leave the chip powered down */ -// FIXME: pci_set_power_state(pci, PCI_D3hot); - - check_connection_type(vptr->mac_regs); - velocity_open(nic, pci); - - /* store NIC parameters */ - nic->nic_op = &velocity_operations; - return 1; -} - -//#define IORESOURCE_IO 0x00000100 /* Resource type */ - -/** - * velocity_init_info - init private data - * @pdev: PCI device - * @vptr: Velocity info - * @info: Board type - * - * Set up the initial velocity_info struct for the device that has been - * discovered. - */ - -static void velocity_init_info(struct pci_device *pdev, - struct velocity_info *vptr, - struct velocity_info_tbl *info) -{ - memset(vptr, 0, sizeof(struct velocity_info)); - - vptr->pdev = pdev; - vptr->chip_id = info->chip_id; - vptr->io_size = info->io_size; - vptr->num_txq = info->txqueue; - vptr->multicast_limit = MCAM_SIZE; - - printf - ("chip_id: 0x%hX, io_size: %d, num_txq %d, multicast_limit: %d\n", - vptr->chip_id, (unsigned int) vptr->io_size, vptr->num_txq, - vptr->multicast_limit); - printf("Name: %s\n", info->name); - -// spin_lock_init(&vptr->lock); -// INIT_LIST_HEAD(&vptr->list); -} - -/** - * velocity_get_pci_info - retrieve PCI info for device - * @vptr: velocity device - * @pdev: PCI device it matches - * - * Retrieve the PCI configuration space data that interests us from - * the kernel PCI layer - */ - -#define IORESOURCE_IO 0x00000100 /* Resource type */ -#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ - -#define IORESOURCE_MEM 0x00000200 -#define BAR_0 0 -#define BAR_1 1 -#define BAR_5 5 -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ -//#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) -// #define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) - -unsigned long pci_resource_flags(struct pci_device *pdev, unsigned int bar) -{ - uint32_t l, sz; - unsigned long flags = 0; - - pci_read_config_dword(pdev, bar, &l); - pci_write_config_dword(pdev, bar, ~0); - pci_read_config_dword(pdev, bar, &sz); - pci_write_config_dword(pdev, bar, l); - - if (!sz || sz == 0xffffffff) - printf("Weird size\n"); - if (l == 0xffffffff) - l = 0; - if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { - /* sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK); - if (!sz) - continue; - res->start = l & PCI_BASE_ADDRESS_MEM_MASK; - */ flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; - printf("Memory Resource\n"); - } else { - // sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); - /// if (!sz) - /// continue; -// res->start = l & PCI_BASE_ADDRESS_IO_MASK; - flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; - printf("I/O Resource\n"); - } - if (flags & PCI_BASE_ADDRESS_SPACE_IO) { - printf("Why is it here\n"); - flags |= IORESOURCE_IO; - } else { - printf("here\n"); -//flags &= ~IORESOURCE_IO; - } - - - if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) - flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; - - - return flags; -} -static int velocity_get_pci_info(struct velocity_info *vptr, - struct pci_device *pdev) -{ - if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0) { - printf("DEBUG: pci_read_config_byte failed\n"); - return -1; - } - - adjust_pci_device(pdev); - - vptr->ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0); - vptr->memaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_1); - - printf("Looking for I/O Resource - Found:"); - if (! - (pci_resource_flags(pdev, PCI_BASE_ADDRESS_0) & IORESOURCE_IO)) - { - printf - ("DEBUG: region #0 is not an I/O resource, aborting.\n"); - return -1; - } - - printf("Looking for Memory Resource - Found:"); - if ((pci_resource_flags(pdev, PCI_BASE_ADDRESS_1) & IORESOURCE_IO)) { - printf("DEBUG: region #1 is an I/O resource, aborting.\n"); - return -1; - } - - if (pci_bar_size(pdev, PCI_BASE_ADDRESS_1) < 256) { - printf("DEBUG: region #1 is too small.\n"); - return -1; - } - vptr->pdev = pdev; - - return 0; -} - -/** - * velocity_print_link_status - link status reporting - * @vptr: velocity to report on - * - * Turn the link status of the velocity card into a kernel log - * description of the new link state, detailing speed and duplex - * status - */ - -static void velocity_print_link_status(struct velocity_info *vptr) -{ - - if (vptr->mii_status & VELOCITY_LINK_FAIL) { - printf("failed to detect cable link\n"); - } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) { - printf("Link autonegation"); - - if (vptr->mii_status & VELOCITY_SPEED_1000) - printf(" speed 1000M bps"); - else if (vptr->mii_status & VELOCITY_SPEED_100) - printf(" speed 100M bps"); - else - printf(" speed 10M bps"); - - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - printf(" full duplex\n"); - else - printf(" half duplex\n"); - } else { - printf("Link forced"); - switch (vptr->options.spd_dpx) { - case SPD_DPX_100_HALF: - printf(" speed 100M bps half duplex\n"); - break; - case SPD_DPX_100_FULL: - printf(" speed 100M bps full duplex\n"); - break; - case SPD_DPX_10_HALF: - printf(" speed 10M bps half duplex\n"); - break; - case SPD_DPX_10_FULL: - printf(" speed 10M bps full duplex\n"); - break; - default: - break; - } - } -} - -/** - * velocity_rx_reset - handle a receive reset - * @vptr: velocity we are resetting - * - * Reset the ownership and status for the receive ring side. - * Hand all the receive queue to the NIC. - */ - -static void velocity_rx_reset(struct velocity_info *vptr) -{ - - struct mac_regs *regs = vptr->mac_regs; - int i; - -//ptr->rd_dirty = vptr->rd_filled = vptr->rd_curr = 0; - - /* - * Init state, all RD entries belong to the NIC - */ - for (i = 0; i < vptr->options.numrx; ++i) - vptr->rd_ring[i].rdesc0.owner = OWNED_BY_NIC; - - writew(RX_DESC_DEF, ®s->RBRDU); - writel(virt_to_le32desc(vptr->rd_ring), ®s->RDBaseLo); - writew(0, ®s->RDIdx); - writew(RX_DESC_DEF - 1, ®s->RDCSize); -} - -/** - * velocity_init_registers - initialise MAC registers - * @vptr: velocity to init - * @type: type of initialisation (hot or cold) - * - * Initialise the MAC on a reset or on first set up on the - * hardware. - */ - -static void velocity_init_registers(struct nic *nic, - struct velocity_info *vptr, - enum velocity_init_type type) -{ - struct mac_regs *regs = vptr->mac_regs; - int i, mii_status; - - mac_wol_reset(regs); - - switch (type) { - case VELOCITY_INIT_RESET: - case VELOCITY_INIT_WOL: - -//netif_stop_queue(vptr->dev); - - /* - * Reset RX to prevent RX pointer not on the 4X location - */ - velocity_rx_reset(vptr); - mac_rx_queue_run(regs); - mac_rx_queue_wake(regs); - - mii_status = velocity_get_opt_media_mode(vptr); - - if (velocity_set_media_mode(vptr, mii_status) != - VELOCITY_LINK_CHANGE) { - velocity_print_link_status(vptr); - if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) - printf("Link Failed\n"); -// netif_wake_queue(vptr->dev); - } - - enable_flow_control_ability(vptr); - - mac_clear_isr(regs); - writel(CR0_STOP, ®s->CR0Clr); - //writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), - ®s->CR0Set); - break; - - case VELOCITY_INIT_COLD: - default: - /* - * Do reset - */ - velocity_soft_reset(vptr); - mdelay(5); - - mac_eeprom_reload(regs); - for (i = 0; i < 6; i++) { - writeb(nic->node_addr[i], &(regs->PAR[i])); - } - /* - * clear Pre_ACPI bit. - */ - BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA)); - mac_set_rx_thresh(regs, vptr->options.rx_thresh); - mac_set_dma_length(regs, vptr->options.DMA_length); - - writeb(WOLCFG_SAM | WOLCFG_SAB, ®s->WOLCFGSet); - /* - * Back off algorithm use original IEEE standard - */ - BYTE_REG_BITS_SET(CFGB_OFSET, - (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | - CFGB_BAKOPT), ®s->CFGB); - - /* - * Init CAM filter - */ - velocity_init_cam_filter(vptr); - - /* - * Set packet filter: Receive directed and broadcast address - */ -//FIXME Multicast velocity_set_multi(nic); - - /* - * Enable MII auto-polling - */ - enable_mii_autopoll(regs); - - vptr->int_mask = INT_MASK_DEF; - - writel(virt_to_le32desc(vptr->rd_ring), ®s->RDBaseLo); - writew(vptr->options.numrx - 1, ®s->RDCSize); - mac_rx_queue_run(regs); - mac_rx_queue_wake(regs); - - writew(vptr->options.numtx - 1, ®s->TDCSize); - -// for (i = 0; i < vptr->num_txq; i++) { - writel(virt_to_le32desc(vptr->td_rings), - &(regs->TDBaseLo[0])); - mac_tx_queue_run(regs, 0); -// } - - init_flow_control_register(vptr); - - writel(CR0_STOP, ®s->CR0Clr); - writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), - ®s->CR0Set); - - mii_status = velocity_get_opt_media_mode(vptr); -// netif_stop_queue(vptr->dev); - - mii_init(vptr, mii_status); - - if (velocity_set_media_mode(vptr, mii_status) != - VELOCITY_LINK_CHANGE) { - velocity_print_link_status(vptr); - if (!(vptr->mii_status & VELOCITY_LINK_FAIL)) - printf("Link Faaailll\n"); -// netif_wake_queue(vptr->dev); - } - - enable_flow_control_ability(vptr); - mac_hw_mibs_init(regs); - mac_write_int_mask(vptr->int_mask, regs); - mac_clear_isr(regs); - - - } - velocity_print_link_status(vptr); -} - -/** - * velocity_soft_reset - soft reset - * @vptr: velocity to reset - * - * Kick off a soft reset of the velocity adapter and then poll - * until the reset sequence has completed before returning. - */ - -static int velocity_soft_reset(struct velocity_info *vptr) -{ - struct mac_regs *regs = vptr->mac_regs; - unsigned int i = 0; - - writel(CR0_SFRST, ®s->CR0Set); - - for (i = 0; i < W_MAX_TIMEOUT; i++) { - udelay(5); - if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, ®s->CR0Set)) - break; - } - - if (i == W_MAX_TIMEOUT) { - writel(CR0_FORSRST, ®s->CR0Set); - /* FIXME: PCI POSTING */ - /* delay 2ms */ - mdelay(2); - } - return 0; -} - -/** - * velocity_init_rings - set up DMA rings - * @vptr: Velocity to set up - * - * Allocate PCI mapped DMA rings for the receive and transmit layer - * to use. - */ - -static int velocity_init_rings(struct velocity_info *vptr) -{ - - int idx; - - vptr->rd_curr = 0; - vptr->td_curr = 0; - memset(vptr->td_rings, 0, TX_DESC_DEF * sizeof(struct tx_desc)); - memset(vptr->rd_ring, 0, RX_DESC_DEF * sizeof(struct rx_desc)); -// memset(vptr->tx_buffs, 0, TX_DESC_DEF * PKT_BUF_SZ); - - - for (idx = 0; idx < RX_DESC_DEF; idx++) { - vptr->rd_ring[idx].rdesc0.RSR = 0; - vptr->rd_ring[idx].rdesc0.len = 0; - vptr->rd_ring[idx].rdesc0.reserved = 0; - vptr->rd_ring[idx].rdesc0.owner = 0; - vptr->rd_ring[idx].len = cpu_to_le32(vptr->rx_buf_sz); - vptr->rd_ring[idx].inten = 1; - vptr->rd_ring[idx].pa_low = - virt_to_bus(vptr->rxb + (RX_DESC_DEF * idx)); - vptr->rd_ring[idx].pa_high = 0; - vptr->rd_ring[idx].rdesc0.owner = OWNED_BY_NIC; - } - -/* for (i = 0; idx < TX_DESC_DEF; idx++ ) { - vptr->td_rings[idx].tdesc1.TCPLS = TCPLS_NORMAL; - vptr->td_rings[idx].tdesc1.TCR = TCR0_TIC; - vptr->td_rings[idx].td_buf[0].queue = 0; - vptr->td_rings[idx].tdesc0.owner = ~OWNED_BY_NIC; - vptr->td_rings[idx].tdesc0.pktsize = 0; - vptr->td_rings[idx].td_buf[0].pa_low = cpu_to_le32(virt_to_bus(vptr->txb + (idx * PKT_BUF_SZ))); - vptr->td_rings[idx].td_buf[0].pa_high = 0; - vptr->td_rings[idx].td_buf[0].bufsize = 0; - vptr->td_rings[idx].tdesc1.CMDZ = 2; - } -*/ - return 0; -} - -/** - * velocity_open - interface activation callback - * @dev: network layer device to open - * - * Called when the network layer brings the interface up. Returns - * a negative posix error code on failure, or zero on success. - * - * All the ring allocation and set up is done on open for this - * adapter to minimise memory usage when inactive - */ - -#define PCI_BYTE_REG_BITS_ON(x,i,p) do{\ - u8 byReg;\ - pci_read_config_byte((p), (i), &(byReg));\ - (byReg) |= (x);\ - pci_write_config_byte((p), (i), (byReg));\ -} while (0) - -// -// Registers in the PCI configuration space -// -#define PCI_REG_COMMAND 0x04 // -#define PCI_REG_MODE0 0x60 // -#define PCI_REG_MODE1 0x61 // -#define PCI_REG_MODE2 0x62 // -#define PCI_REG_MODE3 0x63 // -#define PCI_REG_DELAY_TIMER 0x64 // - -// Bits in the (MODE2, 0x62) register -// -#define MODE2_PCEROPT 0x80 // take PCI bus ERror as a fatal and shutdown from software control -#define MODE2_TXQ16 0x40 // TX write-back Queue control. 0->32 entries available in Tx write-back queue, 1->16 entries -#define MODE2_TXPOST 0x08 // (Not support in VT3119) -#define MODE2_AUTOOPT 0x04 // (VT3119 GHCI without such behavior) -#define MODE2_MODE10T 0x02 // used to control tx Threshold for 10M case -#define MODE2_TCPLSOPT 0x01 // TCP large send field update disable, hardware will not update related fields, leave it to software. - -// -// Bits in the MODE3 register -// -#define MODE3_MIION 0x04 // MII symbol codine error detect enable ?? - -// Bits in the (COMMAND, 0x04) register -#define COMMAND_BUSM 0x04 -#define COMMAND_WAIT 0x80 -static int velocity_open(struct nic *nic, struct pci_device *pci __unused) -{ - u8 diff; - u32 TxPhyAddr, RxPhyAddr; - u32 TxBufPhyAddr, RxBufPhyAddr; - vptr->TxDescArrays = tx_ring; - if (vptr->TxDescArrays == 0) - printf("Allot Error"); - - /* Tx Descriptor needs 64 bytes alignment; */ - TxPhyAddr = virt_to_bus(vptr->TxDescArrays); - printf("Unaligned Address : %X\n", TxPhyAddr); - diff = 64 - (TxPhyAddr - ((TxPhyAddr >> 6) << 6)); - TxPhyAddr += diff; - vptr->td_rings = (struct tx_desc *) (vptr->TxDescArrays + diff); - - printf("Aligned Address: %lX\n", virt_to_bus(vptr->td_rings)); - vptr->tx_buffs = txb; - /* Rx Buffer needs 64 bytes alignment; */ - TxBufPhyAddr = virt_to_bus(vptr->tx_buffs); - diff = 64 - (TxBufPhyAddr - ((TxBufPhyAddr >> 6) << 6)); - TxBufPhyAddr += diff; - vptr->txb = (unsigned char *) (vptr->tx_buffs + diff); - - vptr->RxDescArrays = rx_ring; - /* Rx Descriptor needs 64 bytes alignment; */ - RxPhyAddr = virt_to_bus(vptr->RxDescArrays); - diff = 64 - (RxPhyAddr - ((RxPhyAddr >> 6) << 6)); - RxPhyAddr += diff; - vptr->rd_ring = (struct rx_desc *) (vptr->RxDescArrays + diff); - - vptr->rx_buffs = rxb; - /* Rx Buffer needs 64 bytes alignment; */ - RxBufPhyAddr = virt_to_bus(vptr->rx_buffs); - diff = 64 - (RxBufPhyAddr - ((RxBufPhyAddr >> 6) << 6)); - RxBufPhyAddr += diff; - vptr->rxb = (unsigned char *) (vptr->rx_buffs + diff); - - if (vptr->RxDescArrays == NULL || vptr->RxDescArrays == NULL) { - printf("Allocate tx_ring or rd_ring failed\n"); - return 0; - } - - vptr->rx_buf_sz = PKT_BUF_SZ; -/* - // turn this on to avoid retry forever - PCI_BYTE_REG_BITS_ON(MODE2_PCEROPT, PCI_REG_MODE2, pci); - // for some legacy BIOS and OS don't open BusM - // bit in PCI configuration space. So, turn it on. - PCI_BYTE_REG_BITS_ON(COMMAND_BUSM, PCI_REG_COMMAND, pci); - // turn this on to detect MII coding error - PCI_BYTE_REG_BITS_ON(MODE3_MIION, PCI_REG_MODE3, pci); - */ - velocity_init_rings(vptr); - - /* Ensure chip is running */ -//FIXME: pci_set_power_state(vptr->pdev, PCI_D0); - - velocity_init_registers(nic, vptr, VELOCITY_INIT_COLD); - mac_write_int_mask(0, vptr->mac_regs); -// _int(vptr->mac_regs); - //mac_enable_int(vptr->mac_regs); - - vptr->flags |= VELOCITY_FLAGS_OPENED; - return 1; - -} - -/* - * MII access , media link mode setting functions - */ - - -/** - * mii_init - set up MII - * @vptr: velocity adapter - * @mii_status: links tatus - * - * Set up the PHY for the current link state. - */ - -static void mii_init(struct velocity_info *vptr, u32 mii_status __unused) -{ - u16 BMCR; - - switch (PHYID_GET_PHY_ID(vptr->phy_id)) { - case PHYID_CICADA_CS8201: - /* - * Reset to hardware default - */ - MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, - vptr->mac_regs); - /* - * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. - * legacy-forced issue. - */ - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, - vptr->mac_regs); - else - MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, - vptr->mac_regs); - /* - * Turn on Link/Activity LED enable bit for CIS8201 - */ - MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs); - break; - case PHYID_VT3216_32BIT: - case PHYID_VT3216_64BIT: - /* - * Reset to hardware default - */ - MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, - vptr->mac_regs); - /* - * Turn on ECHODIS bit in NWay-forced full mode and turn it - * off it in NWay-forced half mode for NWay-forced v.s. - * legacy-forced issue - */ - if (vptr->mii_status & VELOCITY_DUPLEX_FULL) - MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, - vptr->mac_regs); - else - MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, - vptr->mac_regs); - break; - - case PHYID_MARVELL_1000: - case PHYID_MARVELL_1000S: - /* - * Assert CRS on Transmit - */ - MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs); - /* - * Reset to hardware default - */ - MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, - vptr->mac_regs); - break; - default: - ; - } - velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR); - if (BMCR & BMCR_ISO) { - BMCR &= ~BMCR_ISO; - velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR); - } -} - -/** - * safe_disable_mii_autopoll - autopoll off - * @regs: velocity registers - * - * Turn off the autopoll and wait for it to disable on the chip - */ - -static void safe_disable_mii_autopoll(struct mac_regs *regs) -{ - u16 ww; - - /* turn off MAUTO */ - writeb(0, ®s->MIICR); - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - udelay(1); - if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; - } -} - -/** - * enable_mii_autopoll - turn on autopolling - * @regs: velocity registers - * - * Enable the MII link status autopoll feature on the Velocity - * hardware. Wait for it to enable. - */ - -static void enable_mii_autopoll(struct mac_regs *regs) -{ - unsigned int ii; - - writeb(0, &(regs->MIICR)); - writeb(MIIADR_SWMPL, ®s->MIIADR); - - for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { - udelay(1); - if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; - } - - writeb(MIICR_MAUTO, ®s->MIICR); - - for (ii = 0; ii < W_MAX_TIMEOUT; ii++) { - udelay(1); - if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, ®s->MIISR)) - break; - } - -} - -/** - * velocity_mii_read - read MII data - * @regs: velocity registers - * @index: MII register index - * @data: buffer for received data - * - * Perform a single read of an MII 16bit register. Returns zero - * on success or -ETIMEDOUT if the PHY did not respond. - */ - -static int velocity_mii_read(struct mac_regs *regs, u8 index, u16 * data) -{ - u16 ww; - - /* - * Disable MIICR_MAUTO, so that mii addr can be set normally - */ - safe_disable_mii_autopoll(regs); - - writeb(index, ®s->MIIADR); - - BYTE_REG_BITS_ON(MIICR_RCMD, ®s->MIICR); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(readb(®s->MIICR) & MIICR_RCMD)) - break; - } - - *data = readw(®s->MIIDATA); - - enable_mii_autopoll(regs); - if (ww == W_MAX_TIMEOUT) - return -1; - return 0; -} - -/** - * velocity_mii_write - write MII data - * @regs: velocity registers - * @index: MII register index - * @data: 16bit data for the MII register - * - * Perform a single write to an MII 16bit register. Returns zero - * on success or -ETIMEDOUT if the PHY did not respond. - */ - -static int velocity_mii_write(struct mac_regs *regs, u8 mii_addr, u16 data) -{ - u16 ww; - - /* - * Disable MIICR_MAUTO, so that mii addr can be set normally - */ - safe_disable_mii_autopoll(regs); - - /* MII reg offset */ - writeb(mii_addr, ®s->MIIADR); - /* set MII data */ - writew(data, ®s->MIIDATA); - - /* turn on MIICR_WCMD */ - BYTE_REG_BITS_ON(MIICR_WCMD, ®s->MIICR); - - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - udelay(5); - if (!(readb(®s->MIICR) & MIICR_WCMD)) - break; - } - enable_mii_autopoll(regs); - - if (ww == W_MAX_TIMEOUT) - return -1; - return 0; -} - -/** - * velocity_get_opt_media_mode - get media selection - * @vptr: velocity adapter - * - * Get the media mode stored in EEPROM or module options and load - * mii_status accordingly. The requested link state information - * is also returned. - */ - -static u32 velocity_get_opt_media_mode(struct velocity_info *vptr) -{ - u32 status = 0; - - switch (vptr->options.spd_dpx) { - case SPD_DPX_AUTO: - status = VELOCITY_AUTONEG_ENABLE; - break; - case SPD_DPX_100_FULL: - status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL; - break; - case SPD_DPX_10_FULL: - status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL; - break; - case SPD_DPX_100_HALF: - status = VELOCITY_SPEED_100; - break; - case SPD_DPX_10_HALF: - status = VELOCITY_SPEED_10; - break; - } - vptr->mii_status = status; - return status; -} - -/** - * mii_set_auto_on - autonegotiate on - * @vptr: velocity - * - * Enable autonegotation on this interface - */ - -static void mii_set_auto_on(struct velocity_info *vptr) -{ - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs)) - MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs); - else - MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); -} - - -/* -static void mii_set_auto_off(struct velocity_info * vptr) -{ - MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); -} -*/ - -/** - * set_mii_flow_control - flow control setup - * @vptr: velocity interface - * - * Set up the flow control on this interface according to - * the supplied user/eeprom options. - */ - -static void set_mii_flow_control(struct velocity_info *vptr) -{ - /*Enable or Disable PAUSE in ANAR */ - switch (vptr->options.flow_cntl) { - case FLOW_CNTL_TX: - MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); - break; - - case FLOW_CNTL_RX: - MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); - break; - - case FLOW_CNTL_TX_RX: - MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs); - break; - - case FLOW_CNTL_DISABLE: - MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, - vptr->mac_regs); - break; - default: - break; - } -} - -/** - * velocity_set_media_mode - set media mode - * @mii_status: old MII link state - * - * Check the media link state and configure the flow control - * PHY and also velocity hardware setup accordingly. In particular - * we need to set up CD polling and frame bursting. - */ - -static int velocity_set_media_mode(struct velocity_info *vptr, - u32 mii_status) -{ - struct mac_regs *regs = vptr->mac_regs; - - vptr->mii_status = mii_check_media_mode(vptr->mac_regs); - - /* Set mii link status */ - set_mii_flow_control(vptr); - - if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) { - MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, - vptr->mac_regs); - } - - /* - * If connection type is AUTO - */ - if (mii_status & VELOCITY_AUTONEG_ENABLE) { - printf("Velocity is AUTO mode\n"); - /* clear force MAC mode bit */ - BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); - /* set duplex mode of MAC according to duplex mode of MII */ - MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, - MII_REG_ANAR, vptr->mac_regs); - MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, - MII_REG_G1000CR, vptr->mac_regs); - MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, - vptr->mac_regs); - - /* enable AUTO-NEGO mode */ - mii_set_auto_on(vptr); - } else { - u16 ANAR; - u8 CHIPGCR; - - /* - * 1. if it's 3119, disable frame bursting in halfduplex mode - * and enable it in fullduplex mode - * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR - * 3. only enable CD heart beat counter in 10HD mode - */ - - /* set force MAC mode bit */ - BYTE_REG_BITS_ON(CHIPGCR_FCMODE, ®s->CHIPGCR); - - CHIPGCR = readb(®s->CHIPGCR); - CHIPGCR &= ~CHIPGCR_FCGMII; - - if (mii_status & VELOCITY_DUPLEX_FULL) { - CHIPGCR |= CHIPGCR_FCFDX; - writeb(CHIPGCR, ®s->CHIPGCR); - printf - ("DEBUG: set Velocity to forced full mode\n"); - if (vptr->rev_id < REV_ID_VT3216_A0) - BYTE_REG_BITS_OFF(TCR_TB2BDIS, ®s->TCR); - } else { - CHIPGCR &= ~CHIPGCR_FCFDX; - printf - ("DEBUG: set Velocity to forced half mode\n"); - writeb(CHIPGCR, ®s->CHIPGCR); - if (vptr->rev_id < REV_ID_VT3216_A0) - BYTE_REG_BITS_ON(TCR_TB2BDIS, ®s->TCR); - } - - MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, - MII_REG_G1000CR, vptr->mac_regs); - - if (!(mii_status & VELOCITY_DUPLEX_FULL) - && (mii_status & VELOCITY_SPEED_10)) { - BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); - } else { - BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); - } - /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */ - velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR); - ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)); - if (mii_status & VELOCITY_SPEED_100) { - if (mii_status & VELOCITY_DUPLEX_FULL) - ANAR |= ANAR_TXFD; - else - ANAR |= ANAR_TX; - } else { - if (mii_status & VELOCITY_DUPLEX_FULL) - ANAR |= ANAR_10FD; - else - ANAR |= ANAR_10; - } - velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR); - /* enable AUTO-NEGO mode */ - mii_set_auto_on(vptr); - /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */ - } - /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */ - /* vptr->mii_status=check_connection_type(vptr->mac_regs); */ - return VELOCITY_LINK_CHANGE; -} - -/** - * mii_check_media_mode - check media state - * @regs: velocity registers - * - * Check the current MII status and determine the link status - * accordingly - */ - -static u32 mii_check_media_mode(struct mac_regs *regs) -{ - u32 status = 0; - u16 ANAR; - - if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs)) - status |= VELOCITY_LINK_FAIL; - - if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs)) - status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL; - else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs)) - status |= (VELOCITY_SPEED_1000); - else { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if (ANAR & ANAR_TXFD) - status |= - (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL); - else if (ANAR & ANAR_TX) - status |= VELOCITY_SPEED_100; - else if (ANAR & ANAR_10FD) - status |= - (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL); - else - status |= (VELOCITY_SPEED_10); - } - - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) - == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { - if (MII_REG_BITS_IS_ON - (G1000CR_1000 | G1000CR_1000FD, - MII_REG_G1000CR, regs)) - status |= VELOCITY_AUTONEG_ENABLE; - } - } - - return status; -} - -static u32 check_connection_type(struct mac_regs *regs) -{ - u32 status = 0; - u8 PHYSR0; - u16 ANAR; - PHYSR0 = readb(®s->PHYSR0); - - /* - if (!(PHYSR0 & PHYSR0_LINKGD)) - status|=VELOCITY_LINK_FAIL; - */ - - if (PHYSR0 & PHYSR0_FDPX) - status |= VELOCITY_DUPLEX_FULL; - - if (PHYSR0 & PHYSR0_SPDG) - status |= VELOCITY_SPEED_1000; - if (PHYSR0 & PHYSR0_SPD10) - status |= VELOCITY_SPEED_10; - else - status |= VELOCITY_SPEED_100; - - if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) { - velocity_mii_read(regs, MII_REG_ANAR, &ANAR); - if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) - == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) { - if (MII_REG_BITS_IS_ON - (G1000CR_1000 | G1000CR_1000FD, - MII_REG_G1000CR, regs)) - status |= VELOCITY_AUTONEG_ENABLE; - } - } - - return status; -} - -/** - * enable_flow_control_ability - flow control - * @vptr: veloity to configure - * - * Set up flow control according to the flow control options - * determined by the eeprom/configuration. - */ - -static void enable_flow_control_ability(struct velocity_info *vptr) -{ - - struct mac_regs *regs = vptr->mac_regs; - - switch (vptr->options.flow_cntl) { - - case FLOW_CNTL_DEFAULT: - if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, ®s->PHYSR0)) - writel(CR0_FDXRFCEN, ®s->CR0Set); - else - writel(CR0_FDXRFCEN, ®s->CR0Clr); - - if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, ®s->PHYSR0)) - writel(CR0_FDXTFCEN, ®s->CR0Set); - else - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; - - case FLOW_CNTL_TX: - writel(CR0_FDXTFCEN, ®s->CR0Set); - writel(CR0_FDXRFCEN, ®s->CR0Clr); - break; - - case FLOW_CNTL_RX: - writel(CR0_FDXRFCEN, ®s->CR0Set); - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; - - case FLOW_CNTL_TX_RX: - writel(CR0_FDXTFCEN, ®s->CR0Set); - writel(CR0_FDXRFCEN, ®s->CR0Set); - break; - - case FLOW_CNTL_DISABLE: - writel(CR0_FDXRFCEN, ®s->CR0Clr); - writel(CR0_FDXTFCEN, ®s->CR0Clr); - break; - - default: - break; - } - -} - -/* FIXME: Move to pci.c */ -/** - * pci_set_power_state - Set the power state of a PCI device - * @dev: PCI device to be suspended - * @state: Power state we're entering - * - * Transition a device to a new power state, using the Power Management - * Capabilities in the device's config space. - * - * RETURN VALUE: - * -EINVAL if trying to enter a lower state than we're already in. - * 0 if we're already in the requested state. - * -EIO if device does not support PCI PM. - * 0 if we can successfully change the power state. - */ - -int pci_set_power_state(struct pci_device *dev, int state) -{ - int pm; - u16 pmcsr; - int current_state = 0; - - /* bound the state we're entering */ - if (state > 3) - state = 3; - - /* Validate current state: - * Can enter D0 from any state, but if we can only go deeper - * to sleep if we're already in a low power state - */ - if (state > 0 && current_state > state) - return -1; - else if (current_state == state) - return 0; /* we're already there */ - - /* find PCI PM capability in list */ - pm = pci_find_capability(dev, PCI_CAP_ID_PM); - - /* abort if the device doesn't support PM capabilities */ - if (!pm) - return -2; - - /* check if this device supports the desired state */ - if (state == 1 || state == 2) { - u16 pmc; - pci_read_config_word(dev, pm + PCI_PM_PMC, &pmc); - if (state == 1 && !(pmc & PCI_PM_CAP_D1)) - return -2; - else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) - return -2; - } - - /* If we're in D3, force entire word to 0. - * This doesn't affect PME_Status, disables PME_En, and - * sets PowerState to 0. - */ - if (current_state >= 3) - pmcsr = 0; - else { - pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= state; - } - - /* enter specified state */ - pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr); - - /* Mandatory power management transition delays */ - /* see PCI PM 1.1 5.6.1 table 18 */ - if (state == 3 || current_state == 3) - mdelay(10); - else if (state == 2 || current_state == 2) - udelay(200); - current_state = state; - - return 0; -} - -static struct pci_device_id velocity_nics[] = { - PCI_ROM(0x1106, 0x3119, "via-velocity", "VIA Networking Velocity Family Gigabit Ethernet Adapter", 0), -}; - -PCI_DRIVER ( velocity_driver, velocity_nics, PCI_NO_CLASS ); - -DRIVER ( "VIA-VELOCITY/PCI", nic_driver, pci_driver, velocity_driver, - velocity_probe, velocity_disable ); diff --git a/roms/ipxe/src/drivers/net/via-velocity.h b/roms/ipxe/src/drivers/net/via-velocity.h deleted file mode 100644 index 753fe445f..000000000 --- a/roms/ipxe/src/drivers/net/via-velocity.h +++ /dev/null @@ -1,1932 +0,0 @@ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * This software may be redistributed and/or modified 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. - * - * File: via-velocity.h - * - * Purpose: Header file to define driver's private structures. - * - * Author: Chuang Liang-Shing, AJ Jiang - * - * Date: Jan 24, 2003 - * - * Changes for Etherboot Port: - * Copyright (c) 2006 by Timothy Legge <tlegge@rogers.com> - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef VELOCITY_H -#define VELOCITY_H - -#define VELOCITY_TX_CSUM_SUPPORT - -#define VELOCITY_NAME "via-velocity" -#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver" -#define VELOCITY_VERSION "1.13" - -#define PKT_BUF_SZ 1564 - -#define MAX_UNITS 8 -#define OPTION_DEFAULT { [0 ... MAX_UNITS-1] = -1} - -#define REV_ID_VT6110 (0) - -#define BYTE_REG_BITS_ON(x,p) do { writeb(readb((p))|(x),(p));} while (0) -#define WORD_REG_BITS_ON(x,p) do { writew(readw((p))|(x),(p));} while (0) -#define DWORD_REG_BITS_ON(x,p) do { writel(readl((p))|(x),(p));} while (0) - -#define BYTE_REG_BITS_IS_ON(x,p) (readb((p)) & (x)) -#define WORD_REG_BITS_IS_ON(x,p) (readw((p)) & (x)) -#define DWORD_REG_BITS_IS_ON(x,p) (readl((p)) & (x)) - -#define BYTE_REG_BITS_OFF(x,p) do { writeb(readb((p)) & (~(x)),(p));} while (0) -#define WORD_REG_BITS_OFF(x,p) do { writew(readw((p)) & (~(x)),(p));} while (0) -#define DWORD_REG_BITS_OFF(x,p) do { writel(readl((p)) & (~(x)),(p));} while (0) - -#define BYTE_REG_BITS_SET(x,m,p) do { writeb( (readb((p)) & (~(m))) |(x),(p));} while (0) -#define WORD_REG_BITS_SET(x,m,p) do { writew( (readw((p)) & (~(m))) |(x),(p));} while (0) -#define DWORD_REG_BITS_SET(x,m,p) do { writel( (readl((p)) & (~(m)))|(x),(p));} while (0) - -#define VAR_USED(p) do {(p)=(p);} while (0) - -/* - * Purpose: Structures for MAX RX/TX descriptors. - */ - - -#define B_OWNED_BY_CHIP 1 -#define B_OWNED_BY_HOST 0 - -/* - * Bits in the RSR0 register - */ - -#define RSR_DETAG 0x0080 -#define RSR_SNTAG 0x0040 -#define RSR_RXER 0x0020 -#define RSR_RL 0x0010 -#define RSR_CE 0x0008 -#define RSR_FAE 0x0004 -#define RSR_CRC 0x0002 -#define RSR_VIDM 0x0001 - -/* - * Bits in the RSR1 register - */ - -#define RSR_RXOK 0x8000 // rx OK -#define RSR_PFT 0x4000 // Perfect filtering address match -#define RSR_MAR 0x2000 // MAC accept multicast address packet -#define RSR_BAR 0x1000 // MAC accept broadcast address packet -#define RSR_PHY 0x0800 // MAC accept physical address packet -#define RSR_VTAG 0x0400 // 802.1p/1q tagging packet indicator -#define RSR_STP 0x0200 // start of packet -#define RSR_EDP 0x0100 // end of packet - -/* - * Bits in the RSR1 register - */ - -#define RSR1_RXOK 0x80 // rx OK -#define RSR1_PFT 0x40 // Perfect filtering address match -#define RSR1_MAR 0x20 // MAC accept multicast address packet -#define RSR1_BAR 0x10 // MAC accept broadcast address packet -#define RSR1_PHY 0x08 // MAC accept physical address packet -#define RSR1_VTAG 0x04 // 802.1p/1q tagging packet indicator -#define RSR1_STP 0x02 // start of packet -#define RSR1_EDP 0x01 // end of packet - -/* - * Bits in the CSM register - */ - -#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok -#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok -#define CSM_FRAG 0x10 //Fragment IP datagram -#define CSM_IPKT 0x04 //Received an IP packet -#define CSM_TCPKT 0x02 //Received a TCP packet -#define CSM_UDPKT 0x01 //Received a UDP packet - -/* - * Bits in the TSR0 register - */ - -#define TSR0_ABT 0x0080 // Tx abort because of excessive collision -#define TSR0_OWT 0x0040 // Jumbo frame Tx abort -#define TSR0_OWC 0x0020 // Out of window collision -#define TSR0_COLS 0x0010 // experience collision in this transmit event -#define TSR0_NCR3 0x0008 // collision retry counter[3] -#define TSR0_NCR2 0x0004 // collision retry counter[2] -#define TSR0_NCR1 0x0002 // collision retry counter[1] -#define TSR0_NCR0 0x0001 // collision retry counter[0] -#define TSR0_TERR 0x8000 // -#define TSR0_FDX 0x4000 // current transaction is serviced by full duplex mode -#define TSR0_GMII 0x2000 // current transaction is serviced by GMII mode -#define TSR0_LNKFL 0x1000 // packet serviced during link down -#define TSR0_SHDN 0x0400 // shutdown case -#define TSR0_CRS 0x0200 // carrier sense lost -#define TSR0_CDH 0x0100 // AQE test fail (CD heartbeat) - -/* - * Bits in the TSR1 register - */ - -#define TSR1_TERR 0x80 // -#define TSR1_FDX 0x40 // current transaction is serviced by full duplex mode -#define TSR1_GMII 0x20 // current transaction is serviced by GMII mode -#define TSR1_LNKFL 0x10 // packet serviced during link down -#define TSR1_SHDN 0x04 // shutdown case -#define TSR1_CRS 0x02 // carrier sense lost -#define TSR1_CDH 0x01 // AQE test fail (CD heartbeat) - -// -// Bits in the TCR0 register -// -#define TCR0_TIC 0x80 // assert interrupt immediately while descriptor has been send complete -#define TCR0_PIC 0x40 // priority interrupt request, INA# is issued over adaptive interrupt scheme -#define TCR0_VETAG 0x20 // enable VLAN tag -#define TCR0_IPCK 0x10 // request IP checksum calculation. -#define TCR0_UDPCK 0x08 // request UDP checksum calculation. -#define TCR0_TCPCK 0x04 // request TCP checksum calculation. -#define TCR0_JMBO 0x02 // indicate a jumbo packet in GMAC side -#define TCR0_CRC 0x01 // disable CRC generation - -#define TCPLS_NORMAL 3 -#define TCPLS_START 2 -#define TCPLS_END 1 -#define TCPLS_MED 0 - - -// max transmit or receive buffer size -#define CB_RX_BUF_SIZE 2048UL // max buffer size - // NOTE: must be multiple of 4 - -#define CB_MAX_RD_NUM 512 // MAX # of RD -#define CB_MAX_TD_NUM 256 // MAX # of TD - -#define CB_INIT_RD_NUM_3119 128 // init # of RD, for setup VT3119 -#define CB_INIT_TD_NUM_3119 64 // init # of TD, for setup VT3119 - -#define CB_INIT_RD_NUM 128 // init # of RD, for setup default -#define CB_INIT_TD_NUM 64 // init # of TD, for setup default - -// for 3119 -#define CB_TD_RING_NUM 4 // # of TD rings. -#define CB_MAX_SEG_PER_PKT 7 // max data seg per packet (Tx) - - -/* - * If collisions excess 15 times , tx will abort, and - * if tx fifo underflow, tx will fail - * we should try to resend it - */ - -#define CB_MAX_TX_ABORT_RETRY 3 - -/* - * Receive descriptor - */ - -struct rdesc0 { - u16 RSR; /* Receive status */ - u16 len:14; /* Received packet length */ - u16 reserved:1; - u16 owner:1; /* Who owns this buffer ? */ -}; - -struct rdesc1 { - u16 PQTAG; - u8 CSM; - u8 IPKT; -}; - -struct rx_desc { - struct rdesc0 rdesc0; - struct rdesc1 rdesc1; - u32 pa_low; /* Low 32 bit PCI address */ - u16 pa_high; /* Next 16 bit PCI address (48 total) */ - u16 len:15; /* Frame size */ - u16 inten:1; /* Enable interrupt */ -} __attribute__ ((__packed__)); - -/* - * Transmit descriptor - */ - -struct tdesc0 { - u16 TSR; /* Transmit status register */ - u16 pktsize:14; /* Size of frame */ - u16 reserved:1; - u16 owner:1; /* Who owns the buffer */ -}; - -struct pqinf { /* Priority queue info */ - u16 VID:12; - u16 CFI:1; - u16 priority:3; -} __attribute__ ((__packed__)); - -struct tdesc1 { - struct pqinf pqinf; - u8 TCR; - u8 TCPLS:2; - u8 reserved:2; - u8 CMDZ:4; -} __attribute__ ((__packed__)); - -struct td_buf { - u32 pa_low; - u16 pa_high; - u16 bufsize:14; - u16 reserved:1; - u16 queue:1; -} __attribute__ ((__packed__)); - -struct tx_desc { - struct tdesc0 tdesc0; - struct tdesc1 tdesc1; - struct td_buf td_buf[7]; -}; - -#ifdef LINUX -struct velocity_rd_info { - struct sk_buff *skb; - dma_addr_t skb_dma; -}; - - -/** - * alloc_rd_info - allocate an rd info block - * - * Alocate and initialize a receive info structure used for keeping - * track of kernel side information related to each receive - * descriptor we are using - */ - -static inline struct velocity_rd_info *alloc_rd_info(void) -{ - struct velocity_rd_info *ptr; - if ((ptr = - kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL) - return NULL; - else { - memset(ptr, 0, sizeof(struct velocity_rd_info)); - return ptr; - } -} - -/* - * Used to track transmit side buffers. - */ - -struct velocity_td_info { - struct sk_buff *skb; - u8 *buf; - int nskb_dma; - dma_addr_t skb_dma[7]; - dma_addr_t buf_dma; -}; - -#endif -enum { - OWNED_BY_HOST = 0, - OWNED_BY_NIC = 1 -} velocity_owner; - - -/* - * MAC registers and macros. - */ - - -#define MCAM_SIZE 64 -#define VCAM_SIZE 64 -#define TX_QUEUE_NO 4 - -#define MAX_HW_MIB_COUNTER 32 -#define VELOCITY_MIN_MTU (1514-14) -#define VELOCITY_MAX_MTU (9000) - -/* - * Registers in the MAC - */ - -#define MAC_REG_PAR 0x00 // physical address -#define MAC_REG_RCR 0x06 -#define MAC_REG_TCR 0x07 -#define MAC_REG_CR0_SET 0x08 -#define MAC_REG_CR1_SET 0x09 -#define MAC_REG_CR2_SET 0x0A -#define MAC_REG_CR3_SET 0x0B -#define MAC_REG_CR0_CLR 0x0C -#define MAC_REG_CR1_CLR 0x0D -#define MAC_REG_CR2_CLR 0x0E -#define MAC_REG_CR3_CLR 0x0F -#define MAC_REG_MAR 0x10 -#define MAC_REG_CAM 0x10 -#define MAC_REG_DEC_BASE_HI 0x18 -#define MAC_REG_DBF_BASE_HI 0x1C -#define MAC_REG_ISR_CTL 0x20 -#define MAC_REG_ISR_HOTMR 0x20 -#define MAC_REG_ISR_TSUPTHR 0x20 -#define MAC_REG_ISR_RSUPTHR 0x20 -#define MAC_REG_ISR_CTL1 0x21 -#define MAC_REG_TXE_SR 0x22 -#define MAC_REG_RXE_SR 0x23 -#define MAC_REG_ISR 0x24 -#define MAC_REG_ISR0 0x24 -#define MAC_REG_ISR1 0x25 -#define MAC_REG_ISR2 0x26 -#define MAC_REG_ISR3 0x27 -#define MAC_REG_IMR 0x28 -#define MAC_REG_IMR0 0x28 -#define MAC_REG_IMR1 0x29 -#define MAC_REG_IMR2 0x2A -#define MAC_REG_IMR3 0x2B -#define MAC_REG_TDCSR_SET 0x30 -#define MAC_REG_RDCSR_SET 0x32 -#define MAC_REG_TDCSR_CLR 0x34 -#define MAC_REG_RDCSR_CLR 0x36 -#define MAC_REG_RDBASE_LO 0x38 -#define MAC_REG_RDINDX 0x3C -#define MAC_REG_TDBASE_LO 0x40 -#define MAC_REG_RDCSIZE 0x50 -#define MAC_REG_TDCSIZE 0x52 -#define MAC_REG_TDINDX 0x54 -#define MAC_REG_TDIDX0 0x54 -#define MAC_REG_TDIDX1 0x56 -#define MAC_REG_TDIDX2 0x58 -#define MAC_REG_TDIDX3 0x5A -#define MAC_REG_PAUSE_TIMER 0x5C -#define MAC_REG_RBRDU 0x5E -#define MAC_REG_FIFO_TEST0 0x60 -#define MAC_REG_FIFO_TEST1 0x64 -#define MAC_REG_CAMADDR 0x68 -#define MAC_REG_CAMCR 0x69 -#define MAC_REG_GFTEST 0x6A -#define MAC_REG_FTSTCMD 0x6B -#define MAC_REG_MIICFG 0x6C -#define MAC_REG_MIISR 0x6D -#define MAC_REG_PHYSR0 0x6E -#define MAC_REG_PHYSR1 0x6F -#define MAC_REG_MIICR 0x70 -#define MAC_REG_MIIADR 0x71 -#define MAC_REG_MIIDATA 0x72 -#define MAC_REG_SOFT_TIMER0 0x74 -#define MAC_REG_SOFT_TIMER1 0x76 -#define MAC_REG_CFGA 0x78 -#define MAC_REG_CFGB 0x79 -#define MAC_REG_CFGC 0x7A -#define MAC_REG_CFGD 0x7B -#define MAC_REG_DCFG0 0x7C -#define MAC_REG_DCFG1 0x7D -#define MAC_REG_MCFG0 0x7E -#define MAC_REG_MCFG1 0x7F - -#define MAC_REG_TBIST 0x80 -#define MAC_REG_RBIST 0x81 -#define MAC_REG_PMCC 0x82 -#define MAC_REG_STICKHW 0x83 -#define MAC_REG_MIBCR 0x84 -#define MAC_REG_EERSV 0x85 -#define MAC_REG_REVID 0x86 -#define MAC_REG_MIBREAD 0x88 -#define MAC_REG_BPMA 0x8C -#define MAC_REG_EEWR_DATA 0x8C -#define MAC_REG_BPMD_WR 0x8F -#define MAC_REG_BPCMD 0x90 -#define MAC_REG_BPMD_RD 0x91 -#define MAC_REG_EECHKSUM 0x92 -#define MAC_REG_EECSR 0x93 -#define MAC_REG_EERD_DATA 0x94 -#define MAC_REG_EADDR 0x96 -#define MAC_REG_EMBCMD 0x97 -#define MAC_REG_JMPSR0 0x98 -#define MAC_REG_JMPSR1 0x99 -#define MAC_REG_JMPSR2 0x9A -#define MAC_REG_JMPSR3 0x9B -#define MAC_REG_CHIPGSR 0x9C -#define MAC_REG_TESTCFG 0x9D -#define MAC_REG_DEBUG 0x9E -#define MAC_REG_CHIPGCR 0x9F -#define MAC_REG_WOLCR0_SET 0xA0 -#define MAC_REG_WOLCR1_SET 0xA1 -#define MAC_REG_PWCFG_SET 0xA2 -#define MAC_REG_WOLCFG_SET 0xA3 -#define MAC_REG_WOLCR0_CLR 0xA4 -#define MAC_REG_WOLCR1_CLR 0xA5 -#define MAC_REG_PWCFG_CLR 0xA6 -#define MAC_REG_WOLCFG_CLR 0xA7 -#define MAC_REG_WOLSR0_SET 0xA8 -#define MAC_REG_WOLSR1_SET 0xA9 -#define MAC_REG_WOLSR0_CLR 0xAC -#define MAC_REG_WOLSR1_CLR 0xAD -#define MAC_REG_PATRN_CRC0 0xB0 -#define MAC_REG_PATRN_CRC1 0xB2 -#define MAC_REG_PATRN_CRC2 0xB4 -#define MAC_REG_PATRN_CRC3 0xB6 -#define MAC_REG_PATRN_CRC4 0xB8 -#define MAC_REG_PATRN_CRC5 0xBA -#define MAC_REG_PATRN_CRC6 0xBC -#define MAC_REG_PATRN_CRC7 0xBE -#define MAC_REG_BYTEMSK0_0 0xC0 -#define MAC_REG_BYTEMSK0_1 0xC4 -#define MAC_REG_BYTEMSK0_2 0xC8 -#define MAC_REG_BYTEMSK0_3 0xCC -#define MAC_REG_BYTEMSK1_0 0xD0 -#define MAC_REG_BYTEMSK1_1 0xD4 -#define MAC_REG_BYTEMSK1_2 0xD8 -#define MAC_REG_BYTEMSK1_3 0xDC -#define MAC_REG_BYTEMSK2_0 0xE0 -#define MAC_REG_BYTEMSK2_1 0xE4 -#define MAC_REG_BYTEMSK2_2 0xE8 -#define MAC_REG_BYTEMSK2_3 0xEC -#define MAC_REG_BYTEMSK3_0 0xF0 -#define MAC_REG_BYTEMSK3_1 0xF4 -#define MAC_REG_BYTEMSK3_2 0xF8 -#define MAC_REG_BYTEMSK3_3 0xFC - -/* - * Bits in the RCR register - */ - -#define RCR_AS 0x80 -#define RCR_AP 0x40 -#define RCR_AL 0x20 -#define RCR_PROM 0x10 -#define RCR_AB 0x08 -#define RCR_AM 0x04 -#define RCR_AR 0x02 -#define RCR_SEP 0x01 - -/* - * Bits in the TCR register - */ - -#define TCR_TB2BDIS 0x80 -#define TCR_COLTMC1 0x08 -#define TCR_COLTMC0 0x04 -#define TCR_LB1 0x02 /* loopback[1] */ -#define TCR_LB0 0x01 /* loopback[0] */ - -/* - * Bits in the CR0 register - */ - -#define CR0_TXON 0x00000008UL -#define CR0_RXON 0x00000004UL -#define CR0_STOP 0x00000002UL /* stop MAC, default = 1 */ -#define CR0_STRT 0x00000001UL /* start MAC */ -#define CR0_SFRST 0x00008000UL /* software reset */ -#define CR0_TM1EN 0x00004000UL -#define CR0_TM0EN 0x00002000UL -#define CR0_DPOLL 0x00000800UL /* disable rx/tx auto polling */ -#define CR0_DISAU 0x00000100UL -#define CR0_XONEN 0x00800000UL -#define CR0_FDXTFCEN 0x00400000UL /* full-duplex TX flow control enable */ -#define CR0_FDXRFCEN 0x00200000UL /* full-duplex RX flow control enable */ -#define CR0_HDXFCEN 0x00100000UL /* half-duplex flow control enable */ -#define CR0_XHITH1 0x00080000UL /* TX XON high threshold 1 */ -#define CR0_XHITH0 0x00040000UL /* TX XON high threshold 0 */ -#define CR0_XLTH1 0x00020000UL /* TX pause frame low threshold 1 */ -#define CR0_XLTH0 0x00010000UL /* TX pause frame low threshold 0 */ -#define CR0_GSPRST 0x80000000UL -#define CR0_FORSRST 0x40000000UL -#define CR0_FPHYRST 0x20000000UL -#define CR0_DIAG 0x10000000UL -#define CR0_INTPCTL 0x04000000UL -#define CR0_GINTMSK1 0x02000000UL -#define CR0_GINTMSK0 0x01000000UL - -/* - * Bits in the CR1 register - */ - -#define CR1_SFRST 0x80 /* software reset */ -#define CR1_TM1EN 0x40 -#define CR1_TM0EN 0x20 -#define CR1_DPOLL 0x08 /* disable rx/tx auto polling */ -#define CR1_DISAU 0x01 - -/* - * Bits in the CR2 register - */ - -#define CR2_XONEN 0x80 -#define CR2_FDXTFCEN 0x40 /* full-duplex TX flow control enable */ -#define CR2_FDXRFCEN 0x20 /* full-duplex RX flow control enable */ -#define CR2_HDXFCEN 0x10 /* half-duplex flow control enable */ -#define CR2_XHITH1 0x08 /* TX XON high threshold 1 */ -#define CR2_XHITH0 0x04 /* TX XON high threshold 0 */ -#define CR2_XLTH1 0x02 /* TX pause frame low threshold 1 */ -#define CR2_XLTH0 0x01 /* TX pause frame low threshold 0 */ - -/* - * Bits in the CR3 register - */ - -#define CR3_GSPRST 0x80 -#define CR3_FORSRST 0x40 -#define CR3_FPHYRST 0x20 -#define CR3_DIAG 0x10 -#define CR3_INTPCTL 0x04 -#define CR3_GINTMSK1 0x02 -#define CR3_GINTMSK0 0x01 - -#define ISRCTL_UDPINT 0x8000 -#define ISRCTL_TSUPDIS 0x4000 -#define ISRCTL_RSUPDIS 0x2000 -#define ISRCTL_PMSK1 0x1000 -#define ISRCTL_PMSK0 0x0800 -#define ISRCTL_INTPD 0x0400 -#define ISRCTL_HCRLD 0x0200 -#define ISRCTL_SCRLD 0x0100 - -/* - * Bits in the ISR_CTL1 register - */ - -#define ISRCTL1_UDPINT 0x80 -#define ISRCTL1_TSUPDIS 0x40 -#define ISRCTL1_RSUPDIS 0x20 -#define ISRCTL1_PMSK1 0x10 -#define ISRCTL1_PMSK0 0x08 -#define ISRCTL1_INTPD 0x04 -#define ISRCTL1_HCRLD 0x02 -#define ISRCTL1_SCRLD 0x01 - -/* - * Bits in the TXE_SR register - */ - -#define TXESR_TFDBS 0x08 -#define TXESR_TDWBS 0x04 -#define TXESR_TDRBS 0x02 -#define TXESR_TDSTR 0x01 - -/* - * Bits in the RXE_SR register - */ - -#define RXESR_RFDBS 0x08 -#define RXESR_RDWBS 0x04 -#define RXESR_RDRBS 0x02 -#define RXESR_RDSTR 0x01 - -/* - * Bits in the ISR register - */ - -#define ISR_ISR3 0x80000000UL -#define ISR_ISR2 0x40000000UL -#define ISR_ISR1 0x20000000UL -#define ISR_ISR0 0x10000000UL -#define ISR_TXSTLI 0x02000000UL -#define ISR_RXSTLI 0x01000000UL -#define ISR_HFLD 0x00800000UL -#define ISR_UDPI 0x00400000UL -#define ISR_MIBFI 0x00200000UL -#define ISR_SHDNI 0x00100000UL -#define ISR_PHYI 0x00080000UL -#define ISR_PWEI 0x00040000UL -#define ISR_TMR1I 0x00020000UL -#define ISR_TMR0I 0x00010000UL -#define ISR_SRCI 0x00008000UL -#define ISR_LSTPEI 0x00004000UL -#define ISR_LSTEI 0x00002000UL -#define ISR_OVFI 0x00001000UL -#define ISR_FLONI 0x00000800UL -#define ISR_RACEI 0x00000400UL -#define ISR_TXWB1I 0x00000200UL -#define ISR_TXWB0I 0x00000100UL -#define ISR_PTX3I 0x00000080UL -#define ISR_PTX2I 0x00000040UL -#define ISR_PTX1I 0x00000020UL -#define ISR_PTX0I 0x00000010UL -#define ISR_PTXI 0x00000008UL -#define ISR_PRXI 0x00000004UL -#define ISR_PPTXI 0x00000002UL -#define ISR_PPRXI 0x00000001UL - -/* - * Bits in the IMR register - */ - -#define IMR_TXSTLM 0x02000000UL -#define IMR_UDPIM 0x00400000UL -#define IMR_MIBFIM 0x00200000UL -#define IMR_SHDNIM 0x00100000UL -#define IMR_PHYIM 0x00080000UL -#define IMR_PWEIM 0x00040000UL -#define IMR_TMR1IM 0x00020000UL -#define IMR_TMR0IM 0x00010000UL - -#define IMR_SRCIM 0x00008000UL -#define IMR_LSTPEIM 0x00004000UL -#define IMR_LSTEIM 0x00002000UL -#define IMR_OVFIM 0x00001000UL -#define IMR_FLONIM 0x00000800UL -#define IMR_RACEIM 0x00000400UL -#define IMR_TXWB1IM 0x00000200UL -#define IMR_TXWB0IM 0x00000100UL - -#define IMR_PTX3IM 0x00000080UL -#define IMR_PTX2IM 0x00000040UL -#define IMR_PTX1IM 0x00000020UL -#define IMR_PTX0IM 0x00000010UL -#define IMR_PTXIM 0x00000008UL -#define IMR_PRXIM 0x00000004UL -#define IMR_PPTXIM 0x00000002UL -#define IMR_PPRXIM 0x00000001UL - -/* 0x0013FB0FUL = initial value of IMR */ - -#define INT_MASK_DEF ( IMR_PPTXIM|IMR_PPRXIM| IMR_PTXIM|IMR_PRXIM | \ - IMR_PWEIM|IMR_TXWB0IM|IMR_TXWB1IM|IMR_FLONIM| \ - IMR_OVFIM|IMR_LSTEIM|IMR_LSTPEIM|IMR_SRCIM|IMR_MIBFIM|\ - IMR_SHDNIM |IMR_TMR1IM|IMR_TMR0IM|IMR_TXSTLM ) - -/* - * Bits in the TDCSR0/1, RDCSR0 register - */ - -#define TRDCSR_DEAD 0x0008 -#define TRDCSR_WAK 0x0004 -#define TRDCSR_ACT 0x0002 -#define TRDCSR_RUN 0x0001 - -/* - * Bits in the CAMADDR register - */ - -#define CAMADDR_CAMEN 0x80 -#define CAMADDR_VCAMSL 0x40 - -/* - * Bits in the CAMCR register - */ - -#define CAMCR_PS1 0x80 -#define CAMCR_PS0 0x40 -#define CAMCR_AITRPKT 0x20 -#define CAMCR_AITR16 0x10 -#define CAMCR_CAMRD 0x08 -#define CAMCR_CAMWR 0x04 -#define CAMCR_PS_CAM_MASK 0x40 -#define CAMCR_PS_CAM_DATA 0x80 -#define CAMCR_PS_MAR 0x00 - -/* - * Bits in the MIICFG register - */ - -#define MIICFG_MPO1 0x80 -#define MIICFG_MPO0 0x40 -#define MIICFG_MFDC 0x20 - -/* - * Bits in the MIISR register - */ - -#define MIISR_MIDLE 0x80 - -/* - * Bits in the PHYSR0 register - */ - -#define PHYSR0_PHYRST 0x80 -#define PHYSR0_LINKGD 0x40 -#define PHYSR0_FDPX 0x10 -#define PHYSR0_SPDG 0x08 -#define PHYSR0_SPD10 0x04 -#define PHYSR0_RXFLC 0x02 -#define PHYSR0_TXFLC 0x01 - -/* - * Bits in the PHYSR1 register - */ - -#define PHYSR1_PHYTBI 0x01 - -/* - * Bits in the MIICR register - */ - -#define MIICR_MAUTO 0x80 -#define MIICR_RCMD 0x40 -#define MIICR_WCMD 0x20 -#define MIICR_MDPM 0x10 -#define MIICR_MOUT 0x08 -#define MIICR_MDO 0x04 -#define MIICR_MDI 0x02 -#define MIICR_MDC 0x01 - -/* - * Bits in the MIIADR register - */ - -#define MIIADR_SWMPL 0x80 - -/* - * Bits in the CFGA register - */ - -#define CFGA_PMHCTG 0x08 -#define CFGA_GPIO1PD 0x04 -#define CFGA_ABSHDN 0x02 -#define CFGA_PACPI 0x01 - -/* - * Bits in the CFGB register - */ - -#define CFGB_GTCKOPT 0x80 -#define CFGB_MIIOPT 0x40 -#define CFGB_CRSEOPT 0x20 -#define CFGB_OFSET 0x10 -#define CFGB_CRANDOM 0x08 -#define CFGB_CAP 0x04 -#define CFGB_MBA 0x02 -#define CFGB_BAKOPT 0x01 - -/* - * Bits in the CFGC register - */ - -#define CFGC_EELOAD 0x80 -#define CFGC_BROPT 0x40 -#define CFGC_DLYEN 0x20 -#define CFGC_DTSEL 0x10 -#define CFGC_BTSEL 0x08 -#define CFGC_BPS2 0x04 /* bootrom select[2] */ -#define CFGC_BPS1 0x02 /* bootrom select[1] */ -#define CFGC_BPS0 0x01 /* bootrom select[0] */ - -/* - * Bits in the CFGD register - */ - -#define CFGD_IODIS 0x80 -#define CFGD_MSLVDACEN 0x40 -#define CFGD_CFGDACEN 0x20 -#define CFGD_PCI64EN 0x10 -#define CFGD_HTMRL4 0x08 - -/* - * Bits in the DCFG1 register - */ - -#define DCFG_XMWI 0x8000 -#define DCFG_XMRM 0x4000 -#define DCFG_XMRL 0x2000 -#define DCFG_PERDIS 0x1000 -#define DCFG_MRWAIT 0x0400 -#define DCFG_MWWAIT 0x0200 -#define DCFG_LATMEN 0x0100 - -/* - * Bits in the MCFG0 register - */ - -#define MCFG_RXARB 0x0080 -#define MCFG_RFT1 0x0020 -#define MCFG_RFT0 0x0010 -#define MCFG_LOWTHOPT 0x0008 -#define MCFG_PQEN 0x0004 -#define MCFG_RTGOPT 0x0002 -#define MCFG_VIDFR 0x0001 - -/* - * Bits in the MCFG1 register - */ - -#define MCFG_TXARB 0x8000 -#define MCFG_TXQBK1 0x0800 -#define MCFG_TXQBK0 0x0400 -#define MCFG_TXQNOBK 0x0200 -#define MCFG_SNAPOPT 0x0100 - -/* - * Bits in the PMCC register - */ - -#define PMCC_DSI 0x80 -#define PMCC_D2_DIS 0x40 -#define PMCC_D1_DIS 0x20 -#define PMCC_D3C_EN 0x10 -#define PMCC_D3H_EN 0x08 -#define PMCC_D2_EN 0x04 -#define PMCC_D1_EN 0x02 -#define PMCC_D0_EN 0x01 - -/* - * Bits in STICKHW - */ - -#define STICKHW_SWPTAG 0x10 -#define STICKHW_WOLSR 0x08 -#define STICKHW_WOLEN 0x04 -#define STICKHW_DS1 0x02 /* R/W by software/cfg cycle */ -#define STICKHW_DS0 0x01 /* suspend well DS write port */ - -/* - * Bits in the MIBCR register - */ - -#define MIBCR_MIBISTOK 0x80 -#define MIBCR_MIBISTGO 0x40 -#define MIBCR_MIBINC 0x20 -#define MIBCR_MIBHI 0x10 -#define MIBCR_MIBFRZ 0x08 -#define MIBCR_MIBFLSH 0x04 -#define MIBCR_MPTRINI 0x02 -#define MIBCR_MIBCLR 0x01 - -/* - * Bits in the EERSV register - */ - -#define EERSV_BOOT_RPL ((u8) 0x01) /* Boot method selection for VT6110 */ - -#define EERSV_BOOT_MASK ((u8) 0x06) -#define EERSV_BOOT_INT19 ((u8) 0x00) -#define EERSV_BOOT_INT18 ((u8) 0x02) -#define EERSV_BOOT_LOCAL ((u8) 0x04) -#define EERSV_BOOT_BEV ((u8) 0x06) - - -/* - * Bits in BPCMD - */ - -#define BPCMD_BPDNE 0x80 -#define BPCMD_EBPWR 0x02 -#define BPCMD_EBPRD 0x01 - -/* - * Bits in the EECSR register - */ - -#define EECSR_EMBP 0x40 /* eeprom embedded programming */ -#define EECSR_RELOAD 0x20 /* eeprom content reload */ -#define EECSR_DPM 0x10 /* eeprom direct programming */ -#define EECSR_ECS 0x08 /* eeprom CS pin */ -#define EECSR_ECK 0x04 /* eeprom CK pin */ -#define EECSR_EDI 0x02 /* eeprom DI pin */ -#define EECSR_EDO 0x01 /* eeprom DO pin */ - -/* - * Bits in the EMBCMD register - */ - -#define EMBCMD_EDONE 0x80 -#define EMBCMD_EWDIS 0x08 -#define EMBCMD_EWEN 0x04 -#define EMBCMD_EWR 0x02 -#define EMBCMD_ERD 0x01 - -/* - * Bits in TESTCFG register - */ - -#define TESTCFG_HBDIS 0x80 - -/* - * Bits in CHIPGCR register - */ - -#define CHIPGCR_FCGMII 0x80 -#define CHIPGCR_FCFDX 0x40 -#define CHIPGCR_FCRESV 0x20 -#define CHIPGCR_FCMODE 0x10 -#define CHIPGCR_LPSOPT 0x08 -#define CHIPGCR_TM1US 0x04 -#define CHIPGCR_TM0US 0x02 -#define CHIPGCR_PHYINTEN 0x01 - -/* - * Bits in WOLCR0 - */ - -#define WOLCR_MSWOLEN7 0x0080 /* enable pattern match filtering */ -#define WOLCR_MSWOLEN6 0x0040 -#define WOLCR_MSWOLEN5 0x0020 -#define WOLCR_MSWOLEN4 0x0010 -#define WOLCR_MSWOLEN3 0x0008 -#define WOLCR_MSWOLEN2 0x0004 -#define WOLCR_MSWOLEN1 0x0002 -#define WOLCR_MSWOLEN0 0x0001 -#define WOLCR_ARP_EN 0x0001 - -/* - * Bits in WOLCR1 - */ - -#define WOLCR_LINKOFF_EN 0x0800 /* link off detected enable */ -#define WOLCR_LINKON_EN 0x0400 /* link on detected enable */ -#define WOLCR_MAGIC_EN 0x0200 /* magic packet filter enable */ -#define WOLCR_UNICAST_EN 0x0100 /* unicast filter enable */ - - -/* - * Bits in PWCFG - */ - -#define PWCFG_PHYPWOPT 0x80 /* internal MII I/F timing */ -#define PWCFG_PCISTICK 0x40 /* PCI sticky R/W enable */ -#define PWCFG_WOLTYPE 0x20 /* pulse(1) or button (0) */ -#define PWCFG_LEGCY_WOL 0x10 -#define PWCFG_PMCSR_PME_SR 0x08 -#define PWCFG_PMCSR_PME_EN 0x04 /* control by PCISTICK */ -#define PWCFG_LEGACY_WOLSR 0x02 /* Legacy WOL_SR shadow */ -#define PWCFG_LEGACY_WOLEN 0x01 /* Legacy WOL_EN shadow */ - -/* - * Bits in WOLCFG - */ - -#define WOLCFG_PMEOVR 0x80 /* for legacy use, force PMEEN always */ -#define WOLCFG_SAM 0x20 /* accept multicast case reset, default=0 */ -#define WOLCFG_SAB 0x10 /* accept broadcast case reset, default=0 */ -#define WOLCFG_SMIIACC 0x08 /* ?? */ -#define WOLCFG_SGENWH 0x02 -#define WOLCFG_PHYINTEN 0x01 /* 0:PHYINT trigger enable, 1:use internal MII - to report status change */ -/* - * Bits in WOLSR1 - */ - -#define WOLSR_LINKOFF_INT 0x0800 -#define WOLSR_LINKON_INT 0x0400 -#define WOLSR_MAGIC_INT 0x0200 -#define WOLSR_UNICAST_INT 0x0100 - -/* - * Ethernet address filter type - */ - -#define PKT_TYPE_NONE 0x0000 /* Turn off receiver */ -#define PKT_TYPE_DIRECTED 0x0001 /* obselete, directed address is always accepted */ -#define PKT_TYPE_MULTICAST 0x0002 -#define PKT_TYPE_ALL_MULTICAST 0x0004 -#define PKT_TYPE_BROADCAST 0x0008 -#define PKT_TYPE_PROMISCUOUS 0x0020 -#define PKT_TYPE_LONG 0x2000 /* NOTE.... the definition of LONG is >2048 bytes in our chip */ -#define PKT_TYPE_RUNT 0x4000 -#define PKT_TYPE_ERROR 0x8000 /* Accept error packets, e.g. CRC error */ - -/* - * Loopback mode - */ - -#define MAC_LB_NONE 0x00 -#define MAC_LB_INTERNAL 0x01 -#define MAC_LB_EXTERNAL 0x02 - -/* - * Enabled mask value of irq - */ - -#if defined(_SIM) -#define IMR_MASK_VALUE 0x0033FF0FUL /* initial value of IMR - set IMR0 to 0x0F according to spec */ - -#else -#define IMR_MASK_VALUE 0x0013FB0FUL /* initial value of IMR - ignore MIBFI,RACEI to - reduce intr. frequency - NOTE.... do not enable NoBuf int mask at driver driver - when (1) NoBuf -> RxThreshold = SF - (2) OK -> RxThreshold = original value - */ -#endif - -/* - * Revision id - */ - -#define REV_ID_VT3119_A0 0x00 -#define REV_ID_VT3119_A1 0x01 -#define REV_ID_VT3216_A0 0x10 - -/* - * Max time out delay time - */ - -#define W_MAX_TIMEOUT 0x0FFFU - - -/* - * MAC registers as a structure. Cannot be directly accessed this - * way but generates offsets for readl/writel() calls - */ - -struct mac_regs { - volatile u8 PAR[6]; /* 0x00 */ - volatile u8 RCR; - volatile u8 TCR; - - volatile u32 CR0Set; /* 0x08 */ - volatile u32 CR0Clr; /* 0x0C */ - - volatile u8 MARCAM[8]; /* 0x10 */ - - volatile u32 DecBaseHi; /* 0x18 */ - volatile u16 DbfBaseHi; /* 0x1C */ - volatile u16 reserved_1E; - - volatile u16 ISRCTL; /* 0x20 */ - volatile u8 TXESR; - volatile u8 RXESR; - - volatile u32 ISR; /* 0x24 */ - volatile u32 IMR; - - volatile u32 TDStatusPort; /* 0x2C */ - - volatile u16 TDCSRSet; /* 0x30 */ - volatile u8 RDCSRSet; - volatile u8 reserved_33; - volatile u16 TDCSRClr; - volatile u8 RDCSRClr; - volatile u8 reserved_37; - - volatile u32 RDBaseLo; /* 0x38 */ - volatile u16 RDIdx; /* 0x3C */ - volatile u16 reserved_3E; - - volatile u32 TDBaseLo[4]; /* 0x40 */ - - volatile u16 RDCSize; /* 0x50 */ - volatile u16 TDCSize; /* 0x52 */ - volatile u16 TDIdx[4]; /* 0x54 */ - volatile u16 tx_pause_timer; /* 0x5C */ - volatile u16 RBRDU; /* 0x5E */ - - volatile u32 FIFOTest0; /* 0x60 */ - volatile u32 FIFOTest1; /* 0x64 */ - - volatile u8 CAMADDR; /* 0x68 */ - volatile u8 CAMCR; /* 0x69 */ - volatile u8 GFTEST; /* 0x6A */ - volatile u8 FTSTCMD; /* 0x6B */ - - volatile u8 MIICFG; /* 0x6C */ - volatile u8 MIISR; - volatile u8 PHYSR0; - volatile u8 PHYSR1; - volatile u8 MIICR; - volatile u8 MIIADR; - volatile u16 MIIDATA; - - volatile u16 SoftTimer0; /* 0x74 */ - volatile u16 SoftTimer1; - - volatile u8 CFGA; /* 0x78 */ - volatile u8 CFGB; - volatile u8 CFGC; - volatile u8 CFGD; - - volatile u16 DCFG; /* 0x7C */ - volatile u16 MCFG; - - volatile u8 TBIST; /* 0x80 */ - volatile u8 RBIST; - volatile u8 PMCPORT; - volatile u8 STICKHW; - - volatile u8 MIBCR; /* 0x84 */ - volatile u8 reserved_85; - volatile u8 rev_id; - volatile u8 PORSTS; - - volatile u32 MIBData; /* 0x88 */ - - volatile u16 EEWrData; - - volatile u8 reserved_8E; - volatile u8 BPMDWr; - volatile u8 BPCMD; - volatile u8 BPMDRd; - - volatile u8 EECHKSUM; /* 0x92 */ - volatile u8 EECSR; - - volatile u16 EERdData; /* 0x94 */ - volatile u8 EADDR; - volatile u8 EMBCMD; - - - volatile u8 JMPSR0; /* 0x98 */ - volatile u8 JMPSR1; - volatile u8 JMPSR2; - volatile u8 JMPSR3; - volatile u8 CHIPGSR; /* 0x9C */ - volatile u8 TESTCFG; - volatile u8 DEBUG; - volatile u8 CHIPGCR; - - volatile u16 WOLCRSet; /* 0xA0 */ - volatile u8 PWCFGSet; - volatile u8 WOLCFGSet; - - volatile u16 WOLCRClr; /* 0xA4 */ - volatile u8 PWCFGCLR; - volatile u8 WOLCFGClr; - - volatile u16 WOLSRSet; /* 0xA8 */ - volatile u16 reserved_AA; - - volatile u16 WOLSRClr; /* 0xAC */ - volatile u16 reserved_AE; - - volatile u16 PatternCRC[8]; /* 0xB0 */ - volatile u32 ByteMask[4][4]; /* 0xC0 */ -} __attribute__ ((__packed__)); - - -enum hw_mib { - HW_MIB_ifRxAllPkts = 0, - HW_MIB_ifRxOkPkts, - HW_MIB_ifTxOkPkts, - HW_MIB_ifRxErrorPkts, - HW_MIB_ifRxRuntOkPkt, - HW_MIB_ifRxRuntErrPkt, - HW_MIB_ifRx64Pkts, - HW_MIB_ifTx64Pkts, - HW_MIB_ifRx65To127Pkts, - HW_MIB_ifTx65To127Pkts, - HW_MIB_ifRx128To255Pkts, - HW_MIB_ifTx128To255Pkts, - HW_MIB_ifRx256To511Pkts, - HW_MIB_ifTx256To511Pkts, - HW_MIB_ifRx512To1023Pkts, - HW_MIB_ifTx512To1023Pkts, - HW_MIB_ifRx1024To1518Pkts, - HW_MIB_ifTx1024To1518Pkts, - HW_MIB_ifTxEtherCollisions, - HW_MIB_ifRxPktCRCE, - HW_MIB_ifRxJumboPkts, - HW_MIB_ifTxJumboPkts, - HW_MIB_ifRxMacControlFrames, - HW_MIB_ifTxMacControlFrames, - HW_MIB_ifRxPktFAE, - HW_MIB_ifRxLongOkPkt, - HW_MIB_ifRxLongPktErrPkt, - HW_MIB_ifTXSQEErrors, - HW_MIB_ifRxNobuf, - HW_MIB_ifRxSymbolErrors, - HW_MIB_ifInRangeLengthErrors, - HW_MIB_ifLateCollisions, - HW_MIB_SIZE -}; - -enum chip_type { - CHIP_TYPE_VT6110 = 1, -}; - -struct velocity_info_tbl { - enum chip_type chip_id; - char *name; - int io_size; - int txqueue; - u32 flags; -}; - -static struct velocity_info_tbl *info; - -#define mac_hw_mibs_init(regs) {\ - BYTE_REG_BITS_ON(MIBCR_MIBFRZ,&((regs)->MIBCR));\ - BYTE_REG_BITS_ON(MIBCR_MIBCLR,&((regs)->MIBCR));\ - do {}\ - while (BYTE_REG_BITS_IS_ON(MIBCR_MIBCLR,&((regs)->MIBCR)));\ - BYTE_REG_BITS_OFF(MIBCR_MIBFRZ,&((regs)->MIBCR));\ -} - -#define mac_read_isr(regs) readl(&((regs)->ISR)) -#define mac_write_isr(regs, x) writel((x),&((regs)->ISR)) -#define mac_clear_isr(regs) writel(0xffffffffL,&((regs)->ISR)) - -#define mac_write_int_mask(mask, regs) writel((mask),&((regs)->IMR)); -#define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr)) -#define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set)) - -#define mac_hw_mibs_read(regs, MIBs) {\ - int i;\ - BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\ - for (i=0;i<HW_MIB_SIZE;i++) {\ - (MIBs)[i]=readl(&((regs)->MIBData));\ - }\ -} - -#define mac_set_dma_length(regs, n) {\ - BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\ -} - -#define mac_set_rx_thresh(regs, n) {\ - BYTE_REG_BITS_SET((n),(MCFG_RFT0|MCFG_RFT1),&((regs)->MCFG));\ -} - -#define mac_rx_queue_run(regs) {\ - writeb(TRDCSR_RUN, &((regs)->RDCSRSet));\ -} - -#define mac_rx_queue_wake(regs) {\ - writeb(TRDCSR_WAK, &((regs)->RDCSRSet));\ -} - -#define mac_tx_queue_run(regs, n) {\ - writew(TRDCSR_RUN<<((n)*4),&((regs)->TDCSRSet));\ -} - -#define mac_tx_queue_wake(regs, n) {\ - writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\ -} - -#define mac_eeprom_reload(regs) {\ - int i=0;\ - BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\ - do {\ - udelay(10);\ - if (i++>0x1000) {\ - break;\ - }\ - }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\ -} - -enum velocity_cam_type { - VELOCITY_VLAN_ID_CAM = 0, - VELOCITY_MULTICAST_CAM -}; - -/** - * mac_get_cam_mask - Read a CAM mask - * @regs: register block for this velocity - * @mask: buffer to store mask - * @cam_type: CAM to fetch - * - * Fetch the mask bits of the selected CAM and store them into the - * provided mask buffer. - */ - -static inline void mac_get_cam_mask(struct mac_regs *regs, u8 * mask, - enum velocity_cam_type cam_type) -{ - int i; - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_VCAMSL, ®s->CAMADDR); - else - writeb(0, ®s->CAMADDR); - - /* read mask */ - for (i = 0; i < 8; i++) - *mask++ = readb(&(regs->MARCAM[i])); - - /* disable CAMEN */ - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); - -} - -/** - * mac_set_cam_mask - Set a CAM mask - * @regs: register block for this velocity - * @mask: CAM mask to load - * @cam_type: CAM to store - * - * Store a new mask into a CAM - */ - -static inline void mac_set_cam_mask(struct mac_regs *regs, u8 * mask, - enum velocity_cam_type cam_type) -{ - int i; - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN, ®s->CAMADDR); - - for (i = 0; i < 8; i++) { - writeb(*mask++, &(regs->MARCAM[i])); - } - /* disable CAMEN */ - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); -} - -/** - * mac_set_cam - set CAM data - * @regs: register block of this velocity - * @idx: Cam index - * @addr: 2 or 6 bytes of CAM data - * @cam_type: CAM to load - * - * Load an address or vlan tag into a CAM - */ - -static inline void mac_set_cam(struct mac_regs *regs, int idx, u8 * addr, - enum velocity_cam_type cam_type) -{ - int i; - - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); - - idx &= (64 - 1); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, - ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writew(*((u16 *) addr), ®s->MARCAM[0]); - else { - for (i = 0; i < 6; i++) { - writeb(*addr++, &(regs->MARCAM[i])); - } - } - BYTE_REG_BITS_ON(CAMCR_CAMWR, ®s->CAMCR); - - udelay(10); - - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); -} - -/** - * mac_get_cam - fetch CAM data - * @regs: register block of this velocity - * @idx: Cam index - * @addr: buffer to hold up to 6 bytes of CAM data - * @cam_type: CAM to load - * - * Load an address or vlan tag from a CAM into the buffer provided by - * the caller. VLAN tags are 2 bytes the address cam entries are 6. - */ - -static inline void mac_get_cam(struct mac_regs *regs, int idx, u8 * addr, - enum velocity_cam_type cam_type) -{ - int i; - - /* Select CAM mask */ - BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); - - idx &= (64 - 1); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, - ®s->CAMADDR); - else - writeb(CAMADDR_CAMEN | idx, ®s->CAMADDR); - - BYTE_REG_BITS_ON(CAMCR_CAMRD, ®s->CAMCR); - - udelay(10); - - if (cam_type == VELOCITY_VLAN_ID_CAM) - *((u16 *) addr) = readw(&(regs->MARCAM[0])); - else - for (i = 0; i < 6; i++, addr++) - *((u8 *) addr) = readb(&(regs->MARCAM[i])); - - writeb(0, ®s->CAMADDR); - - /* Select mar */ - BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, - ®s->CAMCR); -} - -/** - * mac_wol_reset - reset WOL after exiting low power - * @regs: register block of this velocity - * - * Called after we drop out of wake on lan mode in order to - * reset the Wake on lan features. This function doesn't restore - * the rest of the logic from the result of sleep/wakeup - */ - -inline static void mac_wol_reset(struct mac_regs *regs) -{ - - /* Turn off SWPTAG right after leaving power mode */ - BYTE_REG_BITS_OFF(STICKHW_SWPTAG, ®s->STICKHW); - /* clear sticky bits */ - BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), ®s->STICKHW); - - BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, ®s->CHIPGCR); - BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, ®s->CHIPGCR); - /* disable force PME-enable */ - writeb(WOLCFG_PMEOVR, ®s->WOLCFGClr); - /* disable power-event config bit */ - writew(0xFFFF, ®s->WOLCRClr); - /* clear power status */ - writew(0xFFFF, ®s->WOLSRClr); -} - - -/* - * Header for WOL definitions. Used to compute hashes - */ - -typedef u8 MCAM_ADDR[ETH_ALEN]; - -struct arp_packet { - u8 dest_mac[ETH_ALEN]; - u8 src_mac[ETH_ALEN]; - u16 type; - u16 ar_hrd; - u16 ar_pro; - u8 ar_hln; - u8 ar_pln; - u16 ar_op; - u8 ar_sha[ETH_ALEN]; - u8 ar_sip[4]; - u8 ar_tha[ETH_ALEN]; - u8 ar_tip[4]; -} __attribute__ ((__packed__)); - -struct _magic_packet { - u8 dest_mac[6]; - u8 src_mac[6]; - u16 type; - u8 MAC[16][6]; - u8 password[6]; -} __attribute__ ((__packed__)); - -/* - * Store for chip context when saving and restoring status. Not - * all fields are saved/restored currently. - */ - -struct velocity_context { - u8 mac_reg[256]; - MCAM_ADDR cam_addr[MCAM_SIZE]; - u16 vcam[VCAM_SIZE]; - u32 cammask[2]; - u32 patcrc[2]; - u32 pattern[8]; -}; - - -/* - * MII registers. - */ - - -/* - * Registers in the MII (offset unit is WORD) - */ - -#define MII_REG_BMCR 0x00 // physical address -#define MII_REG_BMSR 0x01 // -#define MII_REG_PHYID1 0x02 // OUI -#define MII_REG_PHYID2 0x03 // OUI + Module ID + REV ID -#define MII_REG_ANAR 0x04 // -#define MII_REG_ANLPAR 0x05 // -#define MII_REG_G1000CR 0x09 // -#define MII_REG_G1000SR 0x0A // -#define MII_REG_MODCFG 0x10 // -#define MII_REG_TCSR 0x16 // -#define MII_REG_PLED 0x1B // -// NS, MYSON only -#define MII_REG_PCR 0x17 // -// ESI only -#define MII_REG_PCSR 0x17 // -#define MII_REG_AUXCR 0x1C // - -// Marvell 88E1000/88E1000S -#define MII_REG_PSCR 0x10 // PHY specific control register - -// -// Bits in the BMCR register -// -#define BMCR_RESET 0x8000 // -#define BMCR_LBK 0x4000 // -#define BMCR_SPEED100 0x2000 // -#define BMCR_AUTO 0x1000 // -#define BMCR_PD 0x0800 // -#define BMCR_ISO 0x0400 // -#define BMCR_REAUTO 0x0200 // -#define BMCR_FDX 0x0100 // -#define BMCR_SPEED1G 0x0040 // -// -// Bits in the BMSR register -// -#define BMSR_AUTOCM 0x0020 // -#define BMSR_LNK 0x0004 // - -// -// Bits in the ANAR register -// -#define ANAR_ASMDIR 0x0800 // Asymmetric PAUSE support -#define ANAR_PAUSE 0x0400 // Symmetric PAUSE Support -#define ANAR_T4 0x0200 // -#define ANAR_TXFD 0x0100 // -#define ANAR_TX 0x0080 // -#define ANAR_10FD 0x0040 // -#define ANAR_10 0x0020 // -// -// Bits in the ANLPAR register -// -#define ANLPAR_ASMDIR 0x0800 // Asymmetric PAUSE support -#define ANLPAR_PAUSE 0x0400 // Symmetric PAUSE Support -#define ANLPAR_T4 0x0200 // -#define ANLPAR_TXFD 0x0100 // -#define ANLPAR_TX 0x0080 // -#define ANLPAR_10FD 0x0040 // -#define ANLPAR_10 0x0020 // - -// -// Bits in the G1000CR register -// -#define G1000CR_1000FD 0x0200 // PHY is 1000-T Full-duplex capable -#define G1000CR_1000 0x0100 // PHY is 1000-T Half-duplex capable - -// -// Bits in the G1000SR register -// -#define G1000SR_1000FD 0x0800 // LP PHY is 1000-T Full-duplex capable -#define G1000SR_1000 0x0400 // LP PHY is 1000-T Half-duplex capable - -#define TCSR_ECHODIS 0x2000 // -#define AUXCR_MDPPS 0x0004 // - -// Bits in the PLED register -#define PLED_LALBE 0x0004 // - -// Marvell 88E1000/88E1000S Bits in the PHY specific control register (10h) -#define PSCR_ACRSTX 0x0800 // Assert CRS on Transmit - -#define PHYID_CICADA_CS8201 0x000FC410UL -#define PHYID_VT3216_32BIT 0x000FC610UL -#define PHYID_VT3216_64BIT 0x000FC600UL -#define PHYID_MARVELL_1000 0x01410C50UL -#define PHYID_MARVELL_1000S 0x01410C40UL - -#define PHYID_REV_ID_MASK 0x0000000FUL - -#define PHYID_GET_PHY_REV_ID(i) ((i) & PHYID_REV_ID_MASK) -#define PHYID_GET_PHY_ID(i) ((i) & ~PHYID_REV_ID_MASK) - -#define MII_REG_BITS_ON(x,i,p) do {\ - u16 w;\ - velocity_mii_read((p),(i),&(w));\ - (w)|=(x);\ - velocity_mii_write((p),(i),(w));\ -} while (0) - -#define MII_REG_BITS_OFF(x,i,p) do {\ - u16 w;\ - velocity_mii_read((p),(i),&(w));\ - (w)&=(~(x));\ - velocity_mii_write((p),(i),(w));\ -} while (0) - -#define MII_REG_BITS_IS_ON(x,i,p) ({\ - u16 w;\ - velocity_mii_read((p),(i),&(w));\ - ((int) ((w) & (x)));}) - -#define MII_GET_PHY_ID(p) ({\ - u32 id; \ - u16 id2; \ - u16 id1; \ - velocity_mii_read((p),MII_REG_PHYID2, &id2);\ - velocity_mii_read((p),MII_REG_PHYID1, &id1);\ - id = ( ( (u32)id2 ) << 16 ) | id1; \ - (id);}) - -#ifdef LINUX -/* - * Inline debug routine - */ - - -enum velocity_msg_level { - MSG_LEVEL_ERR = 0, //Errors that will cause abnormal operation. - MSG_LEVEL_NOTICE = 1, //Some errors need users to be notified. - MSG_LEVEL_INFO = 2, //Normal message. - MSG_LEVEL_VERBOSE = 3, //Will report all trival errors. - MSG_LEVEL_DEBUG = 4 //Only for debug purpose. -}; - -#ifdef VELOCITY_DEBUG -#define ASSERT(x) { \ - if (!(x)) { \ - printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\ - __FUNCTION__, __LINE__);\ - BUG(); \ - }\ -} -#define VELOCITY_DBG(p,args...) printk(p, ##args) -#else -#define ASSERT(x) -#define VELOCITY_DBG(x) -#endif - -#define VELOCITY_PRT(l, p, args...) do {if (l<=msglevel) printf( p ,##args);} while (0) - -#define VELOCITY_PRT_CAMMASK(p,t) {\ - int i;\ - if ((t)==VELOCITY_MULTICAST_CAM) {\ - for (i=0;i<(MCAM_SIZE/8);i++)\ - printk("%02X",(p)->mCAMmask[i]);\ - }\ - else {\ - for (i=0;i<(VCAM_SIZE/8);i++)\ - printk("%02X",(p)->vCAMmask[i]);\ - }\ - printk("\n");\ -} - -#endif - -#define VELOCITY_WOL_MAGIC 0x00000000UL -#define VELOCITY_WOL_PHY 0x00000001UL -#define VELOCITY_WOL_ARP 0x00000002UL -#define VELOCITY_WOL_UCAST 0x00000004UL -#define VELOCITY_WOL_BCAST 0x00000010UL -#define VELOCITY_WOL_MCAST 0x00000020UL -#define VELOCITY_WOL_MAGIC_SEC 0x00000040UL - -/* - * Flags for options - */ - -#define VELOCITY_FLAGS_TAGGING 0x00000001UL -#define VELOCITY_FLAGS_TX_CSUM 0x00000002UL -#define VELOCITY_FLAGS_RX_CSUM 0x00000004UL -#define VELOCITY_FLAGS_IP_ALIGN 0x00000008UL -#define VELOCITY_FLAGS_VAL_PKT_LEN 0x00000010UL - -#define VELOCITY_FLAGS_FLOW_CTRL 0x01000000UL - -/* - * Flags for driver status - */ - -#define VELOCITY_FLAGS_OPENED 0x00010000UL -#define VELOCITY_FLAGS_VMNS_CONNECTED 0x00020000UL -#define VELOCITY_FLAGS_VMNS_COMMITTED 0x00040000UL -#define VELOCITY_FLAGS_WOL_ENABLED 0x00080000UL - -/* - * Flags for MII status - */ - -#define VELOCITY_LINK_FAIL 0x00000001UL -#define VELOCITY_SPEED_10 0x00000002UL -#define VELOCITY_SPEED_100 0x00000004UL -#define VELOCITY_SPEED_1000 0x00000008UL -#define VELOCITY_DUPLEX_FULL 0x00000010UL -#define VELOCITY_AUTONEG_ENABLE 0x00000020UL -#define VELOCITY_FORCED_BY_EEPROM 0x00000040UL - -/* - * For velocity_set_media_duplex - */ - -#define VELOCITY_LINK_CHANGE 0x00000001UL - -enum speed_opt { - SPD_DPX_AUTO = 0, - SPD_DPX_100_HALF = 1, - SPD_DPX_100_FULL = 2, - SPD_DPX_10_HALF = 3, - SPD_DPX_10_FULL = 4 -}; - -enum velocity_init_type { - VELOCITY_INIT_COLD = 0, - VELOCITY_INIT_RESET, - VELOCITY_INIT_WOL -}; - -enum velocity_flow_cntl_type { - FLOW_CNTL_DEFAULT = 1, - FLOW_CNTL_TX, - FLOW_CNTL_RX, - FLOW_CNTL_TX_RX, - FLOW_CNTL_DISABLE, -}; - -struct velocity_opt { - int numrx; /* Number of RX descriptors */ - int numtx; /* Number of TX descriptors */ - enum speed_opt spd_dpx; /* Media link mode */ - int vid; /* vlan id */ - int DMA_length; /* DMA length */ - int rx_thresh; /* RX_THRESH */ - int flow_cntl; - int wol_opts; /* Wake on lan options */ - int td_int_count; - int int_works; - int rx_bandwidth_hi; - int rx_bandwidth_lo; - int rx_bandwidth_en; - u32 flags; -}; - -#define RX_DESC_MIN 4 -#define RX_DESC_MAX 255 -#define RX_DESC_DEF RX_DESC_MIN - -#define TX_DESC_MIN 1 -#define TX_DESC_MAX 256 -#define TX_DESC_DEF TX_DESC_MIN - -static struct velocity_info { -// struct list_head list; - - struct pci_device *pdev; -// struct net_device *dev; -// struct net_device_stats stats; - -#ifdef CONFIG_PM - u32 pci_state[16]; -#endif - -// dma_addr_t rd_pool_dma; -// dma_addr_t td_pool_dma[TX_QUEUE_NO]; - -// dma_addr_t tx_bufs_dma; - u8 *tx_bufs; - - u8 ip_addr[4]; - enum chip_type chip_id; - - struct mac_regs *mac_regs; - unsigned long memaddr; - unsigned long ioaddr; - u32 io_size; - - u8 rev_id; - -#define AVAIL_TD(p,q) ((p)->options.numtx-((p)->td_used[(q)])) - - int num_txq; - - volatile int td_used[TX_QUEUE_NO]; - int td_curr; - int td_tail[TX_QUEUE_NO]; - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ - unsigned char *tx_buffs; - unsigned char *rx_buffs; - - unsigned char *txb; - unsigned char *rxb; - struct tx_desc *td_rings; - struct velocity_td_info *td_infos[TX_QUEUE_NO]; - - int rd_curr; - int rd_dirty; - u32 rd_filled; - struct rx_desc *rd_ring; - struct velocity_rd_info *rd_info; /* It's an array */ - -#define GET_RD_BY_IDX(vptr, idx) (vptr->rd_ring[idx]) - u32 mib_counter[MAX_HW_MIB_COUNTER]; - struct velocity_opt options; - - u32 int_mask; - - u32 flags; - - int rx_buf_sz; - u32 mii_status; - u32 phy_id; - int multicast_limit; - - u8 vCAMmask[(VCAM_SIZE / 8)]; - u8 mCAMmask[(MCAM_SIZE / 8)]; - -// spinlock_t lock; - - int wol_opts; - u8 wol_passwd[6]; - - struct velocity_context context; - - u32 ticks; - u32 rx_bytes; - -} vptx; - -static struct velocity_info *vptr; - -#ifdef LINUX -/** - * velocity_get_ip - find an IP address for the device - * @vptr: Velocity to query - * - * Dig out an IP address for this interface so that we can - * configure wakeup with WOL for ARP. If there are multiple IP - * addresses on this chain then we use the first - multi-IP WOL is not - * supported. - * - * CHECK ME: locking - */ - -inline static int velocity_get_ip(struct velocity_info *vptr) -{ - struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr; - struct in_ifaddr *ifa; - - if (in_dev != NULL) { - ifa = (struct in_ifaddr *) in_dev->ifa_list; - if (ifa != NULL) { - memcpy(vptr->ip_addr, &ifa->ifa_address, 4); - return 0; - } - } - return -ENOENT; -} - -/** - * velocity_update_hw_mibs - fetch MIB counters from chip - * @vptr: velocity to update - * - * The velocity hardware keeps certain counters in the hardware - * side. We need to read these when the user asks for statistics - * or when they overflow (causing an interrupt). The read of the - * statistic clears it, so we keep running master counters in user - * space. - */ - -static inline void velocity_update_hw_mibs(struct velocity_info *vptr) -{ - u32 tmp; - int i; - BYTE_REG_BITS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR)); - - while (BYTE_REG_BITS_IS_ON - (MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR))); - - BYTE_REG_BITS_ON(MIBCR_MPTRINI, &(vptr->mac_regs->MIBCR)); - for (i = 0; i < HW_MIB_SIZE; i++) { - tmp = readl(&(vptr->mac_regs->MIBData)) & 0x00FFFFFFUL; - vptr->mib_counter[i] += tmp; - } -} -#endif -/** - * init_flow_control_register - set up flow control - * @vptr: velocity to configure - * - * Configure the flow control registers for this velocity device. - */ - -static inline void init_flow_control_register(struct velocity_info *vptr) -{ - struct mac_regs *regs = vptr->mac_regs; - - /* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1} - depend on RD=64, and Turn on XNOEN in FlowCR1 */ - writel((CR0_XONEN | CR0_XHITH1 | CR0_XLTH1 | CR0_XLTH0), - ®s->CR0Set); - writel((CR0_FDXTFCEN | CR0_FDXRFCEN | CR0_HDXFCEN | CR0_XHITH0), - ®s->CR0Clr); - - /* Set TxPauseTimer to 0xFFFF */ - writew(0xFFFF, ®s->tx_pause_timer); - - /* Initialize RBRDU to Rx buffer count. */ - writew(vptr->options.numrx, ®s->RBRDU); -} - - -#endif diff --git a/roms/ipxe/src/drivers/net/wlan_compat.h b/roms/ipxe/src/drivers/net/wlan_compat.h index 9b7693bb4..5b7b2f3c8 100644 --- a/roms/ipxe/src/drivers/net/wlan_compat.h +++ b/roms/ipxe/src/drivers/net/wlan_compat.h @@ -39,7 +39,7 @@ * * -------------------------------------------------------------------- * -* Portions of the development of this software were funded by +* Portions of the development of this software were funded by * Intersil Corporation as part of PRISM(R) chipset product development. * * -------------------------------------------------------------------- @@ -109,7 +109,7 @@ FILE_LICENCE ( GPL2_ONLY ); /* Lets try to figure out what we've got. Kernel mode or User mode? */ #if defined(__KERNEL__) #define WLAN_OS WLAN_LINUX_KERNEL -#else +#else #define WLAN_OS WLAN_LINUX_USER #endif @@ -179,8 +179,8 @@ FILE_LICENCE ( GPL2_ONLY ); Linux/PPC on PowerMacs (PCI) Arm/Intel Xscale (PCI) - This may also affect PLX boards and other BE &| PPC platforms; - as new ones are discovered, add them below. + This may also affect PLX boards and other BE &| PPC platforms; + as new ones are discovered, add them below. */ #if (WLAN_HOSTIF == WLAN_PCI) @@ -226,28 +226,6 @@ FILE_LICENCE ( GPL2_ONLY ); #define BIT30 0x40000000 #define BIT31 0x80000000 -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned long UINT32; - -typedef signed char INT8; -typedef signed short INT16; -typedef signed long INT32; - -typedef unsigned int UINT; -typedef signed int INT; - -typedef unsigned long long UINT64; -typedef signed long long INT64; - -#define UINT8_MAX (0xffUL) -#define UINT16_MAX (0xffffUL) -#define UINT32_MAX (0xffffffffUL) - -#define INT8_MAX (0x7fL) -#define INT16_MAX (0x7fffL) -#define INT32_MAX (0x7fffffffL) - /*=============================================================*/ /*------ Compiler Portability Macros --------------------------*/ /*=============================================================*/ @@ -298,7 +276,7 @@ typedef signed long long INT64; int __i__; \ printk(KERN_DEBUG x ":"); \ for( __i__=0; __i__ < (n); __i__++) \ - printk( " %02x", ((UINT8*)(p))[__i__]); \ + printk( " %02x", ((uint8_t*)(p))[__i__]); \ printk("\n"); } #define DBFENTER { if ( WLAN_DBVAR >= 4 ){ WLAN_LOG_DEBUG0(3,"Enter\n"); } } @@ -312,11 +290,11 @@ typedef signed long long INT64; #define WLAN_LOG_DEBUG5(l,x,n1,n2,n3,n4,n5) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2), (n3), (n4), (n5)); #define WLAN_LOG_DEBUG6(l,x,n1,n2,n3,n4,n5,n6) if ( WLAN_DBVAR >= (l)) printk(KERN_DEBUG "%s: " x , __FUNCTION__ , (n1), (n2), (n3), (n4), (n5), (n6)); #else - #define WLAN_ASSERT(c) + #define WLAN_ASSERT(c) #define WLAN_HEX_DUMP( l, s, p, n) - #define DBFENTER - #define DBFEXIT + #define DBFENTER + #define DBFEXIT #define WLAN_LOG_DEBUG0(l, s) #define WLAN_LOG_DEBUG1(l, s,n) @@ -344,11 +322,11 @@ typedef signed long long INT64; #define WLAN_LOG_NOTICE3(s,n1,n2,n3) #define WLAN_LOG_NOTICE4(s,n1,n2,n3,n4) - #define WLAN_ASSERT(c) + #define WLAN_ASSERT(c) #define WLAN_HEX_DUMP( l, s, p, n) - #define DBFENTER - #define DBFEXIT + #define DBFENTER + #define DBFEXIT #define WLAN_LOG_INFO0(s) #define WLAN_LOG_INFO1(s,n) @@ -378,7 +356,7 @@ typedef signed long long INT64; #ifdef CONFIG_SMP #define __SMP__ 1 -#endif +#endif #ifndef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) diff --git a/roms/ipxe/src/hci/commands/autoboot_cmd.c b/roms/ipxe/src/hci/commands/autoboot_cmd.c index f3886b1f6..62235a278 100644 --- a/roms/ipxe/src/hci/commands/autoboot_cmd.c +++ b/roms/ipxe/src/hci/commands/autoboot_cmd.c @@ -33,10 +33,29 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** "autoboot" options */ +struct autoboot_options {}; + +/** "autoboot" option list */ +static struct option_descriptor autoboot_opts[] = {}; + +/** + * "autoboot" payload + * + * @v netdev Network device + * @v opts Command options + * @ret rc Return status code + */ +static int autoboot_payload ( struct net_device *netdev, + struct autoboot_options *opts __unused ) { + return netboot ( netdev ); +} + /** "autoboot" command descriptor */ -static struct command_descriptor autoboot_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); +static struct ifcommon_command_descriptor autoboot_cmd = + IFCOMMON_COMMAND_DESC ( struct autoboot_options, autoboot_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + autoboot_payload, 0 ); /** * "autoboot" command @@ -46,7 +65,7 @@ static struct command_descriptor autoboot_cmd = * @ret rc Return status code */ static int autoboot_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &autoboot_cmd, netboot, 0 ); + return ifcommon_exec ( argc, argv, &autoboot_cmd ); } /** Booting commands */ diff --git a/roms/ipxe/src/hci/commands/config_cmd.c b/roms/ipxe/src/hci/commands/config_cmd.c index f1fb567c2..b81c866ff 100644 --- a/roms/ipxe/src/hci/commands/config_cmd.c +++ b/roms/ipxe/src/hci/commands/config_cmd.c @@ -45,28 +45,6 @@ static struct command_descriptor config_cmd = COMMAND_DESC ( struct config_options, config_opts, 0, 1, "[<scope>]" ); /** - * Parse settings scope name - * - * @v text Text - * @ret value Integer value - * @ret rc Return status code - */ -static int parse_settings ( const char *text, struct settings **value ) { - - /* Sanity check */ - assert ( text != NULL ); - - /* Parse scope name */ - *value = find_settings ( text ); - if ( ! *value ) { - printf ( "\"%s\": no such scope\n", text ); - return -EINVAL; - } - - return 0; -} - -/** * "config" command * * @v argc Argument count diff --git a/roms/ipxe/src/hci/commands/console_cmd.c b/roms/ipxe/src/hci/commands/console_cmd.c new file mode 100644 index 000000000..d2eae59f0 --- /dev/null +++ b/roms/ipxe/src/hci/commands/console_cmd.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Console management commands + * + */ + +#include <string.h> +#include <getopt.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <ipxe/console.h> +#include <ipxe/image.h> +#include <ipxe/pixbuf.h> +#include <ipxe/ansiesc.h> +#include <ipxe/ansicol.h> +#include <usr/imgmgmt.h> + +/** "console" options */ +struct console_options { + /** Console configuration */ + struct console_configuration config; + /** Picture URI */ + char *picture; + /** Keep picture after configuration */ + int keep; +}; + +/** "console" option list */ +static struct option_descriptor console_opts[] = { + OPTION_DESC ( "x", 'x', required_argument, + struct console_options, config.width, parse_integer ), + OPTION_DESC ( "y", 'y', required_argument, + struct console_options, config.height, parse_integer ), + OPTION_DESC ( "left", 'l', required_argument, + struct console_options, config.left, parse_integer ), + OPTION_DESC ( "right", 'r', required_argument, + struct console_options, config.right, parse_integer ), + OPTION_DESC ( "top", 't', required_argument, + struct console_options, config.top, parse_integer ), + OPTION_DESC ( "bottom", 'b', required_argument, + struct console_options, config.bottom, parse_integer ), + OPTION_DESC ( "depth", 'd', required_argument, + struct console_options, config.depth, parse_integer ), + OPTION_DESC ( "picture", 'p', required_argument, + struct console_options, picture, parse_string ), + OPTION_DESC ( "keep", 'k', no_argument, + struct console_options, keep, parse_flag ), +}; + +/** "console" command descriptor */ +static struct command_descriptor console_cmd = + COMMAND_DESC ( struct console_options, console_opts, 0, 0, NULL ); + +/** + * "console" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int console_exec ( int argc, char **argv ) { + struct console_options opts; + struct image *image = NULL; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &console_cmd, &opts ) ) != 0 ) + goto err_parse; + + /* Handle background picture, if applicable */ + if ( opts.picture ) { + + /* Acquire image */ + if ( ( rc = imgacquire ( opts.picture, 0, &image ) ) != 0 ) + goto err_acquire; + + /* Convert to pixel buffer */ + if ( ( rc = image_pixbuf ( image, &opts.config.pixbuf ) ) != 0){ + printf ( "Could not use picture: %s\n", + strerror ( rc ) ); + goto err_pixbuf; + } + + /* Apply image's width and height if none specified */ + if ( ! opts.config.width ) + opts.config.width = opts.config.pixbuf->width; + if ( ! opts.config.height ) + opts.config.height = opts.config.pixbuf->height; + } + + /* Configure console */ + if ( ( rc = console_configure ( &opts.config ) ) != 0 ) { + printf ( "Could not configure console: %s\n", strerror ( rc ) ); + goto err_configure; + } + + /* Reapply default colour pair and clear screen */ + ansicol_set_pair ( CPAIR_DEFAULT ); + printf ( CSI "2J" CSI "H" ); + + err_configure: + pixbuf_put ( opts.config.pixbuf ); + err_pixbuf: + /* Discard image unless --keep was specified */ + if ( image && ( ! opts.keep ) ) + unregister_image ( image ); + err_acquire: + err_parse: + return rc; +} + +/** "colour" options */ +struct colour_options { + /** Basic colour */ + unsigned int basic; + /** 24-bit RGB value */ + unsigned int rgb; +}; + +/** "colour" option list */ +static struct option_descriptor colour_opts[] = { + OPTION_DESC ( "basic", 'b', required_argument, + struct colour_options, basic, parse_integer ), + OPTION_DESC ( "rgb", 'r', required_argument, + struct colour_options, rgb, parse_integer ), +}; + +/** "colour" command descriptor */ +static struct command_descriptor colour_cmd = + COMMAND_DESC ( struct colour_options, colour_opts, 1, 1, "<colour>" ); + +/** + * "colour" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int colour_exec ( int argc, char **argv ) { + struct colour_options opts; + unsigned int colour; + int rc; + + /* Initialise options */ + memset ( &opts, 0, sizeof ( opts ) ); + opts.basic = COLOUR_DEFAULT; + opts.rgb = ANSICOL_NO_RGB; + + /* Parse options */ + if ( ( rc = reparse_options ( argc, argv, &colour_cmd, &opts ) ) != 0 ) + return rc; + + /* Parse colour index */ + if ( ( rc = parse_integer ( argv[optind], &colour ) ) != 0 ) + return rc; + + /* Define colour */ + if ( ( rc = ansicol_define ( colour, opts.basic, opts.rgb ) ) != 0 ) { + printf ( "Could not define colour: %s\n", strerror ( rc ) ); + return rc; + } + + /* Reapply default colour pair, in case definition has changed */ + ansicol_set_pair ( CPAIR_DEFAULT ); + + return 0; +} + +/** "cpair" options */ +struct cpair_options { + /** Foreground colour */ + unsigned int foreground; + /** Background colour */ + unsigned int background; +}; + +/** "cpair" option list */ +static struct option_descriptor cpair_opts[] = { + OPTION_DESC ( "foreground", 'f', required_argument, + struct cpair_options, foreground, parse_integer ), + OPTION_DESC ( "background", 'b', required_argument, + struct cpair_options, background, parse_integer ), +}; + +/** "cpair" command descriptor */ +static struct command_descriptor cpair_cmd = + COMMAND_DESC ( struct cpair_options, cpair_opts, 1, 1, "<cpair>" ); + +/** + * "cpair" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int cpair_exec ( int argc, char **argv ) { + struct cpair_options opts; + unsigned int cpair; + int rc; + + /* Initialise options */ + memset ( &opts, 0, sizeof ( opts ) ); + opts.foreground = COLOUR_DEFAULT; + opts.background = COLOUR_DEFAULT; + + /* Parse options */ + if ( ( rc = reparse_options ( argc, argv, &cpair_cmd, &opts ) ) != 0 ) + return rc; + + /* Parse colour pair index */ + if ( ( rc = parse_integer ( argv[optind], &cpair ) ) != 0 ) + return rc; + + /* Define colour pair */ + if ( ( rc = ansicol_define_pair ( cpair, opts.foreground, + opts.background ) ) != 0 ) { + printf ( "Could not define colour pair: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Reapply default colour pair, in case definition has changed */ + ansicol_set_pair ( CPAIR_DEFAULT ); + + return 0; +} + +/** Console management commands */ +struct command console_commands[] __command = { + { + .name = "console", + .exec = console_exec, + }, + { + .name = "colour", + .exec = colour_exec, + }, + { + .name = "cpair", + .exec = cpair_exec, + }, +}; diff --git a/roms/ipxe/src/hci/commands/dhcp_cmd.c b/roms/ipxe/src/hci/commands/dhcp_cmd.c index 279620c32..feeb55ee5 100644 --- a/roms/ipxe/src/hci/commands/dhcp_cmd.c +++ b/roms/ipxe/src/hci/commands/dhcp_cmd.c @@ -41,44 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** "dhcp" command descriptor */ -static struct command_descriptor dhcp_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); - -/** - * Execute "dhcp" command for a network device - * - * @v netdev Network device - * @ret rc Return status code - */ -static int dhcp_payload ( struct net_device *netdev ) { - int rc; - - if ( ( rc = dhcp ( netdev ) ) != 0 ) { - printf ( "Could not configure %s: %s\n", - netdev->name, strerror ( rc ) ); - - /* Close device on failure, to avoid memory exhaustion */ - netdev_close ( netdev ); - - return rc; - } - - return 0; -} - -/** - * The "dhcp" command - * - * @v argc Argument count - * @v argv Argument list - * @ret rc Return status code - */ -static int dhcp_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &dhcp_cmd, dhcp_payload, 1 ); -} - /** "pxebs" options */ struct pxebs_options {}; @@ -129,7 +91,7 @@ static int pxebs_exec ( int argc, char **argv ) { struct command dhcp_commands[] __command = { { .name = "dhcp", - .exec = dhcp_exec, + .exec = ifconf_exec, /* synonym for "ifconf" */ }, { .name = "pxebs", diff --git a/roms/ipxe/src/hci/commands/digest_cmd.c b/roms/ipxe/src/hci/commands/digest_cmd.c index 3cf2f1026..71308064f 100644 --- a/roms/ipxe/src/hci/commands/digest_cmd.c +++ b/roms/ipxe/src/hci/commands/digest_cmd.c @@ -77,7 +77,7 @@ static int digest_exec ( int argc, char **argv, for ( i = optind ; i < argc ; i++ ) { /* Acquire image */ - if ( ( rc = imgacquire ( argv[i], &image ) ) != 0 ) + if ( ( rc = imgacquire ( argv[i], 0, &image ) ) != 0 ) continue; offset = 0; len = image->len; diff --git a/roms/ipxe/src/hci/commands/fcmgmt_cmd.c b/roms/ipxe/src/hci/commands/fcmgmt_cmd.c index b7e38040c..1c199b5dc 100644 --- a/roms/ipxe/src/hci/commands/fcmgmt_cmd.c +++ b/roms/ipxe/src/hci/commands/fcmgmt_cmd.c @@ -43,7 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret port Fibre Channel port * @ret rc Return status code */ -static int parse_fc_port ( const char *text, struct fc_port **port ) { +static int parse_fc_port ( char *text, struct fc_port **port ) { /* Sanity check */ assert ( text != NULL ); @@ -65,7 +65,7 @@ static int parse_fc_port ( const char *text, struct fc_port **port ) { * @ret port_id Fibre Channel port ID * @ret rc Return status code */ -static int parse_fc_port_id ( const char *text, struct fc_port_id *port_id ) { +static int parse_fc_port_id ( char *text, struct fc_port_id *port_id ) { int rc; /* Sanity check */ @@ -87,8 +87,7 @@ static int parse_fc_port_id ( const char *text, struct fc_port_id *port_id ) { * @ret handler Fibre Channel ELS handler * @ret rc Return status code */ -static int parse_fc_els_handler ( const char *text, - struct fc_els_handler **handler ) { +static int parse_fc_els_handler ( char *text, struct fc_els_handler **handler ){ for_each_table_entry ( (*handler), FC_ELS_HANDLERS ) { if ( strcasecmp ( (*handler)->name, text ) == 0 ) @@ -107,7 +106,7 @@ static struct option_descriptor fcstat_opts[] = {}; /** "fcstat" command descriptor */ static struct command_descriptor fcstat_cmd = - COMMAND_DESC ( struct fcstat_options, fcstat_opts, 0, 0, "" ); + COMMAND_DESC ( struct fcstat_options, fcstat_opts, 0, 0, NULL ); /** * The "fcstat" command @@ -152,8 +151,7 @@ static struct option_descriptor fcels_opts[] = { /** "fcels" command descriptor */ static struct command_descriptor fcels_cmd = - COMMAND_DESC ( struct fcels_options, fcels_opts, 1, 1, - "[--port <port>] [--id <peer port id>] <request>" ); + COMMAND_DESC ( struct fcels_options, fcels_opts, 1, 1, "<request>" ); /** * The "fcels" command diff --git a/roms/ipxe/src/hci/commands/ifmgmt_cmd.c b/roms/ipxe/src/hci/commands/ifmgmt_cmd.c index 3f3f6b51c..5307c9423 100644 --- a/roms/ipxe/src/hci/commands/ifmgmt_cmd.c +++ b/roms/ipxe/src/hci/commands/ifmgmt_cmd.c @@ -34,9 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** "if<xxx>" command options */ -struct option_descriptor ifcommon_opts[0]; - /** * Execute if<xxx> command * @@ -48,26 +45,24 @@ struct option_descriptor ifcommon_opts[0]; * @ret rc Return status code */ int ifcommon_exec ( int argc, char **argv, - struct command_descriptor *cmd, - int ( * payload ) ( struct net_device * ), - int stop_on_first_success ) { - struct ifcommon_options opts; + struct ifcommon_command_descriptor *ifcmd ) { + struct command_descriptor *cmd = &ifcmd->cmd; + uint8_t opts[cmd->len]; struct net_device *netdev; + int i; int rc; /* Parse options */ - if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 ) + if ( ( rc = parse_options ( argc, argv, cmd, opts ) ) != 0 ) return rc; if ( optind != argc ) { /* Treat arguments as a list of interfaces to try */ - while ( optind != argc ) { - if ( ( rc = parse_netdev ( argv[optind++], - &netdev ) ) != 0 ) { + for ( i = optind ; i < argc ; i++ ) { + if ( ( rc = parse_netdev ( argv[i], &netdev ) ) != 0 ) continue; - } - if ( ( ( rc = payload ( netdev ) ) == 0 ) && - stop_on_first_success ) { + if ( ( ( rc = ifcmd->payload ( netdev, opts ) ) == 0 ) + && ifcmd->stop_on_first_success ) { return 0; } } @@ -75,8 +70,8 @@ int ifcommon_exec ( int argc, char **argv, /* Try all interfaces */ rc = -ENODEV; for_each_netdev ( netdev ) { - if ( ( ( rc = payload ( netdev ) ) == 0 ) && - stop_on_first_success ) { + if ( ( ( rc = ifcmd->payload ( netdev, opts ) ) == 0 ) + && ifcmd->stop_on_first_success ) { return 0; } } @@ -85,21 +80,30 @@ int ifcommon_exec ( int argc, char **argv, return rc; } -/** "ifopen" command descriptor */ -static struct command_descriptor ifopen_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); +/** "ifopen" options */ +struct ifopen_options {}; + +/** "ifopen" option list */ +static struct option_descriptor ifopen_opts[] = {}; /** * "ifopen" payload * * @v netdev Network device + * @v opts Command options * @ret rc Return status code */ -static int ifopen_payload ( struct net_device *netdev ) { +static int ifopen_payload ( struct net_device *netdev, + struct ifopen_options *opts __unused ) { return ifopen ( netdev ); } +/** "ifopen" command descriptor */ +static struct ifcommon_command_descriptor ifopen_cmd = + IFCOMMON_COMMAND_DESC ( struct ifopen_options, ifopen_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + ifopen_payload, 0 ); + /** * The "ifopen" command * @@ -108,25 +112,34 @@ static int ifopen_payload ( struct net_device *netdev ) { * @ret rc Return status code */ static int ifopen_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &ifopen_cmd, ifopen_payload, 0 ); + return ifcommon_exec ( argc, argv, &ifopen_cmd ); } -/** "ifclose" command descriptor */ -static struct command_descriptor ifclose_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); +/** "ifclose" options */ +struct ifclose_options {}; + +/** "ifclose" option list */ +static struct option_descriptor ifclose_opts[] = {}; /** * "ifclose" payload * * @v netdev Network device + * @v opts Command options * @ret rc Return status code */ -static int ifclose_payload ( struct net_device *netdev ) { +static int ifclose_payload ( struct net_device *netdev, + struct ifclose_options *opts __unused ) { ifclose ( netdev ); return 0; } +/** "ifclose" command descriptor */ +static struct ifcommon_command_descriptor ifclose_cmd = + IFCOMMON_COMMAND_DESC ( struct ifclose_options, ifclose_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + ifclose_payload, 0 ); + /** * The "ifclose" command * @@ -135,25 +148,34 @@ static int ifclose_payload ( struct net_device *netdev ) { * @ret rc Return status code */ static int ifclose_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &ifclose_cmd, ifclose_payload, 0 ); + return ifcommon_exec ( argc, argv, &ifclose_cmd ); } -/** "ifstat" command descriptor */ -static struct command_descriptor ifstat_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); +/** "ifstat" options */ +struct ifstat_options {}; + +/** "ifstat" option list */ +static struct option_descriptor ifstat_opts[] = {}; /** * "ifstat" payload * * @v netdev Network device + * @v opts Command options * @ret rc Return status code */ -static int ifstat_payload ( struct net_device *netdev ) { +static int ifstat_payload ( struct net_device *netdev, + struct ifstat_options *opts __unused ) { ifstat ( netdev ); return 0; } +/** "ifstat" command descriptor */ +static struct ifcommon_command_descriptor ifstat_cmd = + IFCOMMON_COMMAND_DESC ( struct ifstat_options, ifstat_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + ifstat_payload, 0 ); + /** * The "ifstat" command * @@ -162,7 +184,60 @@ static int ifstat_payload ( struct net_device *netdev ) { * @ret rc Return status code */ static int ifstat_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &ifstat_cmd, ifstat_payload, 0 ); + return ifcommon_exec ( argc, argv, &ifstat_cmd ); +} + +/** "ifconf" options */ +struct ifconf_options { + /** Configurator */ + struct net_device_configurator *configurator; +}; + +/** "ifconf" option list */ +static struct option_descriptor ifconf_opts[] = { + OPTION_DESC ( "configurator", 'c', required_argument, + struct ifconf_options, configurator, + parse_netdev_configurator ), +}; + +/** + * "ifconf" payload + * + * @v netdev Network device + * @v opts Command options + * @ret rc Return status code + */ +static int ifconf_payload ( struct net_device *netdev, + struct ifconf_options *opts ) { + int rc; + + /* Attempt configuration */ + if ( ( rc = ifconf ( netdev, opts->configurator ) ) != 0 ) { + + /* Close device on failure, to avoid memory exhaustion */ + netdev_close ( netdev ); + + return rc; + } + + return 0; +} + +/** "ifconf" command descriptor */ +static struct ifcommon_command_descriptor ifconf_cmd = + IFCOMMON_COMMAND_DESC ( struct ifconf_options, ifconf_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + ifconf_payload, 1 ); + +/** + * The "ifconf" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +int ifconf_exec ( int argc, char **argv ) { + return ifcommon_exec ( argc, argv, &ifconf_cmd ); } /** Interface management commands */ @@ -179,4 +254,8 @@ struct command ifmgmt_commands[] __command = { .name = "ifstat", .exec = ifstat_exec, }, + { + .name = "ifconf", + .exec = ifconf_exec, + }, }; diff --git a/roms/ipxe/src/hci/commands/image_cmd.c b/roms/ipxe/src/hci/commands/image_cmd.c index 6f51a6ba2..a9e831bf5 100644 --- a/roms/ipxe/src/hci/commands/image_cmd.c +++ b/roms/ipxe/src/hci/commands/image_cmd.c @@ -39,7 +39,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** "img{single}" options */ struct imgsingle_options { /** Image name */ - const char *name; + char *name; + /** Download timeout */ + unsigned long timeout; /** Replace image */ int replace; /** Free image after execution */ @@ -47,28 +49,33 @@ struct imgsingle_options { }; /** "img{single}" option list */ -static struct option_descriptor imgsingle_opts[] = { - OPTION_DESC ( "name", 'n', required_argument, - struct imgsingle_options, name, parse_string ), - OPTION_DESC ( "replace", 'r', no_argument, - struct imgsingle_options, replace, parse_flag ), - OPTION_DESC ( "autofree", 'a', no_argument, - struct imgsingle_options, autofree, parse_flag ), +static union { + /* "imgexec" takes all three options */ + struct option_descriptor imgexec[4]; + /* Other "img{single}" commands take only --name, --timeout, + * and --autofree + */ + struct option_descriptor imgsingle[3]; +} opts = { + .imgexec = { + OPTION_DESC ( "name", 'n', required_argument, + struct imgsingle_options, name, parse_string ), + OPTION_DESC ( "timeout", 't', required_argument, + struct imgsingle_options, timeout, parse_timeout), + OPTION_DESC ( "autofree", 'a', no_argument, + struct imgsingle_options, autofree, parse_flag ), + OPTION_DESC ( "replace", 'r', no_argument, + struct imgsingle_options, replace, parse_flag ), + }, }; -/** "img{single}" command descriptor */ -static struct command_descriptor imgsingle_cmd = - COMMAND_DESC ( struct imgsingle_options, imgsingle_opts, - 1, MAX_ARGUMENTS, - "[--name <name>] [--autofree] " - "<uri|image> [<arguments>...]" ); - /** An "img{single}" family command descriptor */ struct imgsingle_descriptor { /** Command descriptor */ struct command_descriptor *cmd; /** Function to use to acquire the image */ - int ( * acquire ) ( const char *name, struct image **image ); + int ( * acquire ) ( const char *name, unsigned long timeout, + struct image **image ); /** Pre-action to take upon image, or NULL */ void ( * preaction ) ( struct image *image ); /** Action to take upon image, or NULL */ @@ -114,7 +121,8 @@ static int imgsingle_exec ( int argc, char **argv, /* Acquire the image */ if ( name_uri ) { - if ( ( rc = desc->acquire ( name_uri, &image ) ) != 0 ) + if ( ( rc = desc->acquire ( name_uri, opts.timeout, + &image ) ) != 0 ) goto err_acquire; } else { image = image_find_selected(); @@ -174,9 +182,8 @@ static int imgsingle_exec ( int argc, char **argv, /** "imgfetch" command descriptor */ static struct command_descriptor imgfetch_cmd = - COMMAND_DESC ( struct imgsingle_options, imgsingle_opts, - 1, MAX_ARGUMENTS, - "[--name <name>] [--autofree] <uri> [<arguments>...]" ); + COMMAND_DESC ( struct imgsingle_options, opts.imgsingle, + 1, MAX_ARGUMENTS, "<uri> [<arguments>...]" ); /** "imgfetch" family command descriptor */ struct imgsingle_descriptor imgfetch_desc = { @@ -207,9 +214,14 @@ static int imgselect ( struct image *image, return image_select ( image ); } +/** "imgselect" command descriptor */ +static struct command_descriptor imgselect_cmd = + COMMAND_DESC ( struct imgsingle_options, opts.imgsingle, + 1, MAX_ARGUMENTS, "<uri|image> [<arguments>...]" ); + /** "imgselect" family command descriptor */ struct imgsingle_descriptor imgselect_desc = { - .cmd = &imgsingle_cmd, + .cmd = &imgselect_cmd, .acquire = imgacquire, .action = imgselect, .verb = "select", @@ -228,10 +240,8 @@ static int imgselect_exec ( int argc, char **argv ) { /** "imgexec" command descriptor */ static struct command_descriptor imgexec_cmd = - COMMAND_DESC ( struct imgsingle_options, imgsingle_opts, - 0, MAX_ARGUMENTS, - "[--autofree] [--replace] " - "[<uri|image> [<arguments>...]]" ); + COMMAND_DESC ( struct imgsingle_options, opts.imgexec, + 0, MAX_ARGUMENTS, "[<uri|image> [<arguments>...]]" ); /** * "imgexec" command action @@ -282,9 +292,14 @@ static int imgexec_exec ( int argc, char **argv) { return imgsingle_exec ( argc, argv, &imgexec_desc ); } +/** "imgargs" command descriptor */ +static struct command_descriptor imgargs_cmd = + COMMAND_DESC ( struct imgsingle_options, opts.imgsingle, + 1, MAX_ARGUMENTS, "<uri|image> [<arguments>...]" ); + /** "imgargs" family command descriptor */ struct imgsingle_descriptor imgargs_desc = { - .cmd = &imgsingle_cmd, + .cmd = &imgargs_cmd, .acquire = imgacquire, .preaction = image_clear_cmdline, }; diff --git a/roms/ipxe/src/hci/commands/image_trust_cmd.c b/roms/ipxe/src/hci/commands/image_trust_cmd.c index e7a2bf122..ca59a858a 100644 --- a/roms/ipxe/src/hci/commands/image_trust_cmd.c +++ b/roms/ipxe/src/hci/commands/image_trust_cmd.c @@ -52,8 +52,7 @@ static struct option_descriptor imgtrust_opts[] = { /** "imgtrust" command descriptor */ static struct command_descriptor imgtrust_cmd = - COMMAND_DESC ( struct imgtrust_options, imgtrust_opts, 0, 0, - "[--allow] [--permanent]" ); + COMMAND_DESC ( struct imgtrust_options, imgtrust_opts, 0, 0, NULL ); /** * The "imgtrust" command @@ -84,9 +83,11 @@ static int imgtrust_exec ( int argc, char **argv ) { /** "imgverify" options */ struct imgverify_options { /** Required signer common name */ - const char *signer; + char *signer; /** Keep signature after verification */ int keep; + /** Download timeout */ + unsigned long timeout; }; /** "imgverify" option list */ @@ -95,13 +96,14 @@ static struct option_descriptor imgverify_opts[] = { struct imgverify_options, signer, parse_string ), OPTION_DESC ( "keep", 'k', no_argument, struct imgverify_options, keep, parse_flag ), + OPTION_DESC ( "timeout", 't', required_argument, + struct imgverify_options, timeout, parse_timeout), }; /** "imgverify" command descriptor */ static struct command_descriptor imgverify_cmd = COMMAND_DESC ( struct imgverify_options, imgverify_opts, 2, 2, - "[--signer <signer>] [--keep] <uri|image> " - "<signature uri|image>" ); + "<uri|image> <signature uri|image>" ); /** * The "imgverify" command @@ -129,11 +131,12 @@ static int imgverify_exec ( int argc, char **argv ) { signature_name_uri = argv[ optind + 1 ]; /* Acquire the image */ - if ( ( rc = imgacquire ( image_name_uri, &image ) ) != 0 ) + if ( ( rc = imgacquire ( image_name_uri, opts.timeout, &image ) ) != 0 ) goto err_acquire_image; /* Acquire the signature image */ - if ( ( rc = imgacquire ( signature_name_uri, &signature ) ) != 0 ) + if ( ( rc = imgacquire ( signature_name_uri, opts.timeout, + &signature ) ) != 0 ) goto err_acquire_signature; /* Verify image */ diff --git a/roms/ipxe/src/hci/commands/ipstat_cmd.c b/roms/ipxe/src/hci/commands/ipstat_cmd.c new file mode 100644 index 000000000..d565dc0ae --- /dev/null +++ b/roms/ipxe/src/hci/commands/ipstat_cmd.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <getopt.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <usr/ipstat.h> + +/** @file + * + * IP statistics commands + * + */ + +/** "ipstat" options */ +struct ipstat_options {}; + +/** "ipstat" option list */ +static struct option_descriptor ipstat_opts[] = {}; + +/** "ipstat" command descriptor */ +static struct command_descriptor ipstat_cmd = + COMMAND_DESC ( struct ipstat_options, ipstat_opts, 0, 0, NULL ); + +/** + * The "ipstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int ipstat_exec ( int argc, char **argv ) { + struct ipstat_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &ipstat_cmd, &opts ) ) != 0 ) + return rc; + + ipstat(); + + return 0; +} + +/** Routing table management commands */ +struct command ipstat_commands[] __command = { + { + .name = "ipstat", + .exec = ipstat_exec, + }, +}; diff --git a/roms/ipxe/src/hci/commands/iwmgmt_cmd.c b/roms/ipxe/src/hci/commands/iwmgmt_cmd.c index d91ad1e34..b61ee8c7b 100644 --- a/roms/ipxe/src/hci/commands/iwmgmt_cmd.c +++ b/roms/ipxe/src/hci/commands/iwmgmt_cmd.c @@ -32,18 +32,21 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** "iwstat" command descriptor */ -static struct command_descriptor iwstat_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); +/** "iwstat" options */ +struct iwstat_options {}; + +/** "iwstat" option list */ +static struct option_descriptor iwstat_opts[] = {}; /** * "iwstat" payload * * @v netdev Network device + * @v opts Command options * @ret rc Return status code */ -static int iwstat_payload ( struct net_device *netdev ) { +static int iwstat_payload ( struct net_device *netdev, + struct iwstat_options *opts __unused ) { struct net80211_device *dev = net80211_get ( netdev ); if ( dev ) @@ -52,6 +55,12 @@ static int iwstat_payload ( struct net_device *netdev ) { return 0; } +/** "iwstat" command descriptor */ +static struct ifcommon_command_descriptor iwstat_cmd = + IFCOMMON_COMMAND_DESC ( struct iwstat_options, iwstat_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + iwstat_payload, 0 ); + /** * The "iwstat" command * @@ -60,21 +69,24 @@ static int iwstat_payload ( struct net_device *netdev ) { * @ret rc Return status code */ static int iwstat_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &iwstat_cmd, iwstat_payload, 0 ); + return ifcommon_exec ( argc, argv, &iwstat_cmd ); } -/** "iwlist" command descriptor */ -static struct command_descriptor iwlist_cmd = - COMMAND_DESC ( struct ifcommon_options, ifcommon_opts, 0, MAX_ARGUMENTS, - "[<interface>...]" ); +/** "iwlist" options */ +struct iwlist_options {}; + +/** "iwlist" option list */ +static struct option_descriptor iwlist_opts[] = {}; /** * "iwlist" payload * * @v netdev Network device + * @v opts Command options * @ret rc Return status code */ -static int iwlist_payload ( struct net_device *netdev ) { +static int iwlist_payload ( struct net_device *netdev, + struct iwlist_options *opts __unused ) { struct net80211_device *dev = net80211_get ( netdev ); if ( dev ) @@ -83,6 +95,12 @@ static int iwlist_payload ( struct net_device *netdev ) { return 0; } +/** "iwlist" command descriptor */ +static struct ifcommon_command_descriptor iwlist_cmd = + IFCOMMON_COMMAND_DESC ( struct iwlist_options, iwlist_opts, + 0, MAX_ARGUMENTS, "[<interface>...]", + iwlist_payload, 0 ); + /** * The "iwlist" command * @@ -91,7 +109,7 @@ static int iwlist_payload ( struct net_device *netdev ) { * @ret rc Return status code */ static int iwlist_exec ( int argc, char **argv ) { - return ifcommon_exec ( argc, argv, &iwlist_cmd, iwlist_payload, 0 ); + return ifcommon_exec ( argc, argv, &iwlist_cmd ); } /** Wireless interface management commands */ diff --git a/roms/ipxe/src/hci/commands/login_cmd.c b/roms/ipxe/src/hci/commands/login_cmd.c index bc23e6ff5..f5db427d5 100644 --- a/roms/ipxe/src/hci/commands/login_cmd.c +++ b/roms/ipxe/src/hci/commands/login_cmd.c @@ -39,7 +39,7 @@ static struct option_descriptor login_opts[] = {}; /** "login" command descriptor */ static struct command_descriptor login_cmd = - COMMAND_DESC ( struct login_options, login_opts, 0, 0, "" ); + COMMAND_DESC ( struct login_options, login_opts, 0, 0, NULL ); /** * "login" command diff --git a/roms/ipxe/src/hci/commands/lotest_cmd.c b/roms/ipxe/src/hci/commands/lotest_cmd.c index 92f08887a..0fa031bcb 100644 --- a/roms/ipxe/src/hci/commands/lotest_cmd.c +++ b/roms/ipxe/src/hci/commands/lotest_cmd.c @@ -50,8 +50,7 @@ static struct option_descriptor lotest_opts[] = { /** "lotest" command descriptor */ static struct command_descriptor lotest_cmd = COMMAND_DESC ( struct lotest_options, lotest_opts, 2, 2, - "[--mtu <mtu>] <sending interface> " - "<receiving interface>" ); + "<sending interface> <receiving interface>" ); /** * "lotest" command diff --git a/roms/ipxe/src/hci/commands/menu_cmd.c b/roms/ipxe/src/hci/commands/menu_cmd.c index 10966db27..66a6262e6 100644 --- a/roms/ipxe/src/hci/commands/menu_cmd.c +++ b/roms/ipxe/src/hci/commands/menu_cmd.c @@ -41,7 +41,7 @@ FEATURE ( FEATURE_MISC, "Menu", DHCP_EB_FEATURE_MENU, 1 ); /** "menu" options */ struct menu_options { /** Name */ - const char *name; + char *name; /** Delete */ int delete; }; @@ -57,7 +57,7 @@ static struct option_descriptor menu_opts[] = { /** "menu" command descriptor */ static struct command_descriptor menu_cmd = COMMAND_DESC ( struct menu_options, menu_opts, 0, MAX_ARGUMENTS, - "[--name <name>] [--delete] [<title>]" ); + "[<title>]" ); /** * The "menu" command @@ -107,7 +107,7 @@ static int menu_exec ( int argc, char **argv ) { /** "item" options */ struct item_options { /** Menu name */ - const char *menu; + char *menu; /** Shortcut key */ unsigned int key; /** Use as default */ @@ -131,8 +131,7 @@ static struct option_descriptor item_opts[] = { /** "item" command descriptor */ static struct command_descriptor item_cmd = COMMAND_DESC ( struct item_options, item_opts, 0, MAX_ARGUMENTS, - "[--menu <menu>] [--key <key>] [--default] " - "[<label>|--gap [<text>]]" ); + "[<label> [<text>]]" ); /** * The "item" command @@ -192,11 +191,11 @@ static int item_exec ( int argc, char **argv ) { /** "choose" options */ struct choose_options { /** Menu name */ - const char *menu; + char *menu; /** Timeout */ - unsigned int timeout; + unsigned long timeout; /** Default selection */ - const char *select; + char *select; /** Keep menu */ int keep; }; @@ -208,16 +207,14 @@ static struct option_descriptor choose_opts[] = { OPTION_DESC ( "default", 'd', required_argument, struct choose_options, select, parse_string ), OPTION_DESC ( "timeout", 't', required_argument, - struct choose_options, timeout, parse_integer ), + struct choose_options, timeout, parse_timeout ), OPTION_DESC ( "keep", 'k', no_argument, struct choose_options, keep, parse_flag ), }; /** "choose" command descriptor */ static struct command_descriptor choose_cmd = - COMMAND_DESC ( struct choose_options, choose_opts, 1, 1, - "[--menu <menu>] [--default <label>] " - "[--timeout <timeout>] [--keep] <setting>" ); + COMMAND_DESC ( struct choose_options, choose_opts, 1, 1, "<setting>" ); /** * The "choose" command @@ -228,9 +225,9 @@ static struct command_descriptor choose_cmd = */ static int choose_exec ( int argc, char **argv ) { struct choose_options opts; + struct named_setting setting; struct menu *menu; struct menu_item *item; - const char *setting; int rc; /* Parse options */ @@ -238,7 +235,9 @@ static int choose_exec ( int argc, char **argv ) { goto err_parse_options; /* Parse setting name */ - setting = argv[optind]; + if ( ( rc = parse_autovivified_setting ( argv[optind], + &setting ) ) != 0 ) + goto err_parse_setting; /* Identify menu */ if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 ) @@ -248,11 +247,15 @@ static int choose_exec ( int argc, char **argv ) { if ( ( rc = show_menu ( menu, opts.timeout, opts.select, &item ) ) != 0) goto err_show_menu; + /* Apply default type if necessary */ + if ( ! setting.setting.type ) + setting.setting.type = &setting_type_string; + /* Store setting */ - if ( ( rc = storef_named_setting ( setting, &setting_type_string, - item->label ) ) != 0 ) { + if ( ( rc = storef_setting ( setting.settings, &setting.setting, + item->label ) ) != 0 ) { printf ( "Could not store \"%s\": %s\n", - setting, strerror ( rc ) ); + setting.setting.name, strerror ( rc ) ); goto err_store; } @@ -265,6 +268,7 @@ static int choose_exec ( int argc, char **argv ) { if ( ! opts.keep ) destroy_menu ( menu ); err_parse_menu: + err_parse_setting: err_parse_options: return rc; } diff --git a/roms/ipxe/src/hci/commands/neighbour_cmd.c b/roms/ipxe/src/hci/commands/neighbour_cmd.c new file mode 100644 index 000000000..a1e052439 --- /dev/null +++ b/roms/ipxe/src/hci/commands/neighbour_cmd.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Neighbour management commands + * + */ + +#include <getopt.h> +#include <ipxe/parseopt.h> +#include <ipxe/command.h> +#include <usr/neighmgmt.h> + +/** "nstat" options */ +struct nstat_options {}; + +/** "nstat" option list */ +static struct option_descriptor nstat_opts[] = {}; + +/** "nstat" command descriptor */ +static struct command_descriptor nstat_cmd = + COMMAND_DESC ( struct nstat_options, nstat_opts, 0, 0, NULL ); + +/** + * The "nstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int nstat_exec ( int argc, char **argv ) { + struct nstat_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &nstat_cmd, &opts ) ) != 0) + return rc; + + nstat(); + + return 0; +} + +/** Neighbour management commands */ +struct command neighbour_commands[] __command = { + { + .name = "nstat", + .exec = nstat_exec, + }, +}; diff --git a/roms/ipxe/src/hci/commands/nvo_cmd.c b/roms/ipxe/src/hci/commands/nvo_cmd.c index f255bbf57..e63dab08e 100644 --- a/roms/ipxe/src/hci/commands/nvo_cmd.c +++ b/roms/ipxe/src/hci/commands/nvo_cmd.c @@ -23,6 +23,7 @@ #include <string.h> #include <errno.h> #include <getopt.h> +#include <byteswap.h> #include <ipxe/settings.h> #include <ipxe/command.h> #include <ipxe/parseopt.h> @@ -55,31 +56,43 @@ static struct command_descriptor show_cmd = */ static int show_exec ( int argc, char **argv ) { struct show_options opts; - const char *name; + struct named_setting setting; + struct settings *origin; + struct setting fetched; char name_buf[32]; - char value_buf[256]; + char *value; + int len; int rc; /* Parse options */ if ( ( rc = parse_options ( argc, argv, &show_cmd, &opts ) ) != 0 ) - return rc; + goto err_parse_options; /* Parse setting name */ - name = argv[optind]; + if ( ( rc = parse_existing_setting ( argv[optind], &setting ) ) != 0 ) + goto err_parse_setting; - /* Fetch setting */ - if ( ( rc = fetchf_named_setting ( name, name_buf, sizeof ( name_buf ), - value_buf, - sizeof ( value_buf ) ) ) < 0 ) { + /* Fetch formatted setting value */ + if ( ( len = fetchf_setting_copy ( setting.settings, &setting.setting, + &origin, &fetched, &value ) ) < 0 ) { + rc = len; printf ( "Could not find \"%s\": %s\n", - name, strerror ( rc ) ); - return rc; + setting.setting.name, strerror ( rc ) ); + goto err_fetchf; } /* Print setting value */ - printf ( "%s = %s\n", name_buf, value_buf ); + setting_name ( origin, &fetched, name_buf, sizeof ( name_buf ) ); + printf ( "%s = %s\n", name_buf, value ); - return 0; + /* Success */ + rc = 0; + + free ( value ); + err_fetchf: + err_parse_setting: + err_parse_options: + return rc; } /** "set", "clear", and "read" options */ @@ -109,10 +122,10 @@ static struct command_descriptor clear_read_cmd = */ static int set_core_exec ( int argc, char **argv, struct command_descriptor *cmd, - int ( * get_value ) ( const char *name, + int ( * get_value ) ( struct named_setting *setting, char **args, char **value ) ) { struct set_core_options opts; - const char *name; + struct named_setting setting; char *value; int rc; @@ -121,26 +134,30 @@ static int set_core_exec ( int argc, char **argv, goto err_parse_options; /* Parse setting name */ - name = argv[optind]; + if ( ( rc = parse_autovivified_setting ( argv[optind], + &setting ) ) != 0 ) + goto err_parse_setting; /* Parse setting value */ - if ( ( rc = get_value ( name, &argv[ optind + 1 ], &value ) ) != 0 ) + if ( ( rc = get_value ( &setting, &argv[ optind + 1 ], &value ) ) != 0 ) goto err_get_value; - /* Determine total length of command line */ - if ( ( rc = storef_named_setting ( name, &setting_type_string, - value ) ) != 0 ) { - printf ( "Could not %s \"%s\": %s\n", - argv[0], name, strerror ( rc ) ); + /* Apply default type if necessary */ + if ( ! setting.setting.type ) + setting.setting.type = &setting_type_string; + + /* Store setting */ + if ( ( rc = storef_setting ( setting.settings, &setting.setting, + value ) ) != 0 ) { + printf ( "Could not store \"%s\": %s\n", + setting.setting.name, strerror ( rc ) ); goto err_store; } - free ( value ); - return 0; - err_store: free ( value ); err_get_value: + err_parse_setting: err_parse_options: return rc; } @@ -148,12 +165,13 @@ static int set_core_exec ( int argc, char **argv, /** * Get setting value for "set" command * - * @v name Setting name + * @v setting Named setting * @v args Remaining arguments * @ret value Setting value * @ret rc Return status code */ -static int set_value ( const char *name __unused, char **args, char **value ) { +static int set_value ( struct named_setting *setting __unused, + char **args, char **value ) { *value = concat_args ( args ); if ( ! *value ) @@ -176,13 +194,13 @@ static int set_exec ( int argc, char **argv ) { /** * Get setting value for "clear" command * - * @v name Setting name + * @v setting Named setting * @v args Remaining arguments * @ret value Setting value * @ret rc Return status code */ -static int clear_value ( const char *name __unused, char **args __unused, - char **value ) { +static int clear_value ( struct named_setting *setting __unused, + char **args __unused, char **value ) { *value = NULL; return 0; @@ -202,29 +220,28 @@ static int clear_exec ( int argc, char **argv ) { /** * Get setting value for "read" command * - * @v name Setting name + * @v setting Named setting * @v args Remaining arguments * @ret value Setting value * @ret rc Return status code */ -static int read_value ( const char *name, char **args __unused, char **value ) { +static int read_value ( struct named_setting *setting, char **args __unused, + char **value ) { char *existing; int rc; - /* Read existing value */ - if ( ( rc = fetchf_named_setting_copy ( name, &existing ) ) < 0 ) - goto err_existing; + /* Read existing value, treating errors as equivalent to an + * empty initial setting. + */ + fetchf_setting_copy ( setting->settings, &setting->setting, + NULL, &setting->setting, &existing ); /* Read new value */ if ( ( rc = readline_history ( NULL, existing, NULL, value ) ) != 0 ) - goto err_new; - - /* Success */ - rc = 0; + goto err_readline; - err_new: + err_readline: free ( existing ); - err_existing: return rc; } @@ -239,6 +256,72 @@ static int read_exec ( int argc, char **argv ) { return set_core_exec ( argc, argv, &clear_read_cmd, read_value ); } +/** "inc" options */ +struct inc_options {}; + +/** "inc" option list */ +static struct option_descriptor inc_opts[] = {}; + +/** "inc" command descriptor */ +static struct command_descriptor inc_cmd = + COMMAND_DESC ( struct inc_options, inc_opts, 1, 2, + "<setting> [<increment>]" ); + +/** + * "inc" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int inc_exec ( int argc, char **argv ) { + struct inc_options opts; + struct named_setting setting; + unsigned int increment = 1; + unsigned long value; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &inc_cmd, &opts ) ) != 0 ) + goto err_parse_options; + + /* Parse setting name */ + if ( ( rc = parse_existing_setting ( argv[optind], &setting ) ) != 0 ) + goto err_parse_setting; + + /* Parse increment (if present) */ + if ( ( ( optind + 1 ) < argc ) && + ( ( rc = parse_integer ( argv[ optind + 1 ], &increment ) ) != 0)) + goto err_parse_increment; + + /* Read existing value, treating errors as equivalent to a + * zero-valued :int32 initial setting. + */ + if ( ( rc = fetchn_setting ( setting.settings, &setting.setting, + NULL, &setting.setting, &value ) ) != 0 ) { + value = 0; + if ( ! setting.setting.type ) + setting.setting.type = &setting_type_int32; + } + + /* Increment value */ + value += increment; + + /* Store updated setting value */ + if ( ( rc = storen_setting ( setting.settings, &setting.setting, + value ) ) != 0 ) { + printf ( "Could not store \"%s\": %s\n", + setting.setting.name, strerror ( rc ) ); + goto err_store; + } + + err_store: + err_parse_increment: + err_parse_setting: + err_parse_options: + return rc; +} + /** Non-volatile option commands */ struct command nvo_commands[] __command = { { @@ -257,4 +340,8 @@ struct command nvo_commands[] __command = { .name = "read", .exec = read_exec, }, + { + .name = "inc", + .exec = inc_exec, + }, }; diff --git a/roms/ipxe/src/hci/commands/param_cmd.c b/roms/ipxe/src/hci/commands/param_cmd.c new file mode 100644 index 000000000..6cf096d00 --- /dev/null +++ b/roms/ipxe/src/hci/commands/param_cmd.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Form parameter commands + * + */ + +#include <stdlib.h> +#include <errno.h> +#include <getopt.h> +#include <ipxe/params.h> +#include <ipxe/parseopt.h> +#include <ipxe/command.h> + +/** "params" options */ +struct params_options { + /** Name */ + char *name; + /** Delete */ + int delete; +}; + +/** "params" option list */ +static struct option_descriptor params_opts[] = { + OPTION_DESC ( "name", 'n', required_argument, + struct params_options, name, parse_string ), + OPTION_DESC ( "delete", 'd', no_argument, + struct params_options, delete, parse_flag ), +}; + +/** "params" command descriptor */ +static struct command_descriptor params_cmd = + COMMAND_DESC ( struct params_options, params_opts, 0, 0, NULL ); + +/** + * The "params" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int params_exec ( int argc, char **argv ) { + struct params_options opts; + struct parameters *params; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, ¶ms_cmd, &opts ) ) != 0) + return rc; + + /* Create parameter list */ + params = create_parameters ( opts.name ); + if ( ! params ) + return -ENOMEM; + + /* Destroy parameter list, if applicable */ + if ( opts.delete ) { + claim_parameters ( params ); + params_put ( params ); + } + + return 0; +} + +/** "param" options */ +struct param_options { + /** Parameter list name */ + char *params; +}; + +/** "param" option list */ +static struct option_descriptor param_opts[] = { + OPTION_DESC ( "params", 'p', required_argument, + struct param_options, params, parse_string ), +}; + +/** "param" command descriptor */ +static struct command_descriptor param_cmd = + COMMAND_DESC ( struct param_options, param_opts, 1, MAX_ARGUMENTS, + "<key> [<value>]" ); + +/** + * The "param" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int param_exec ( int argc, char **argv ) { + struct param_options opts; + char *key; + char *value; + struct parameters *params; + struct parameter *param; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, ¶m_cmd, &opts ) ) != 0 ) + goto err_parse_options; + + /* Parse key */ + key = argv[optind]; + + /* Parse value */ + value = concat_args ( &argv[ optind + 1 ] ); + if ( ! value ) { + rc = -ENOMEM; + goto err_parse_value; + } + + /* Identify parameter list */ + if ( ( rc = parse_parameters ( opts.params, ¶ms ) ) != 0 ) + goto err_parse_parameters; + + /* Add parameter */ + param = add_parameter ( params, key, value ); + if ( ! param ) { + rc = -ENOMEM; + goto err_add_parameter; + } + + /* Success */ + rc = 0; + + err_add_parameter: + err_parse_parameters: + free ( value ); + err_parse_value: + err_parse_options: + return rc; +} + +/** Form parameter commands */ +struct command param_commands[] __command = { + { + .name = "params", + .exec = params_exec, + }, + { + .name = "param", + .exec = param_exec, + }, +}; diff --git a/roms/ipxe/src/hci/commands/pci_cmd.c b/roms/ipxe/src/hci/commands/pci_cmd.c new file mode 100644 index 000000000..f5145fb35 --- /dev/null +++ b/roms/ipxe/src/hci/commands/pci_cmd.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdio.h> +#include <getopt.h> +#include <ipxe/pci.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * PCI commands + * + */ + +/** "pciscan" options */ +struct pciscan_options {}; + +/** "pciscan" option list */ +static struct option_descriptor pciscan_opts[] = {}; + +/** "pciscan" command descriptor */ +static struct command_descriptor pciscan_cmd = + COMMAND_DESC ( struct pciscan_options, pciscan_opts, 1, 1, + "<setting>" ); + +/** + * "pciscan" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int pciscan_exec ( int argc, char **argv ) { + struct pciscan_options opts; + struct named_setting setting; + struct pci_device pci; + unsigned long prev; + int next; + int len; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &pciscan_cmd, &opts ) ) != 0 ) + goto err_parse_options; + + /* Parse setting name */ + if ( ( rc = parse_autovivified_setting ( argv[optind], + &setting ) ) != 0 ) + goto err_parse_setting; + + /* Determine starting bus:dev.fn address */ + if ( ( len = fetchn_setting ( setting.settings, &setting.setting, + NULL, &setting.setting, &prev ) ) < 0 ) { + /* Setting not yet defined: start searching from 00:00.0 */ + prev = 0; + } else { + /* Setting is defined: start searching from next location */ + prev++; + } + + /* Find next existent PCI device */ + if ( ( next = pci_find_next ( &pci, prev ) ) < 0 ) { + rc = next; + goto err_find_next; + } + + /* Apply default type if necessary. Use ":uint16" rather than + * ":busdevfn" to allow for easy inclusion within a + * "${pci/${location}.x.y}" constructed setting. + */ + if ( ! setting.setting.type ) + setting.setting.type = &setting_type_uint16; + + /* Store setting */ + if ( ( rc = storen_setting ( setting.settings, &setting.setting, + next ) ) != 0 ) { + printf ( "Could not store \"%s\": %s\n", + setting.setting.name, strerror ( rc ) ); + goto err_store; + } + + err_store: + err_find_next: + err_parse_setting: + err_parse_options: + return rc; +} + +/** PCI commands */ +struct command pci_commands[] __command = { + { + .name = "pciscan", + .exec = pciscan_exec, + }, +}; diff --git a/roms/ipxe/src/hci/commands/ping_cmd.c b/roms/ipxe/src/hci/commands/ping_cmd.c new file mode 100644 index 000000000..d514a2a27 --- /dev/null +++ b/roms/ipxe/src/hci/commands/ping_cmd.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <ipxe/timer.h> +#include <usr/pingmgmt.h> + +/** @file + * + * Ping command + * + */ + +/** Default payload length */ +#define PING_DEFAULT_SIZE 64 + +/** Default timeout */ +#define PING_DEFAULT_TIMEOUT TICKS_PER_SEC + +/** "ping" options */ +struct ping_options { + /** Payload length */ + unsigned int size; + /** Timeout (in ms) */ + unsigned long timeout; +}; + +/** "ping" option list */ +static struct option_descriptor ping_opts[] = { + OPTION_DESC ( "size", 's', required_argument, + struct ping_options, size, parse_integer ), + OPTION_DESC ( "timeout", 't', required_argument, + struct ping_options, timeout, parse_timeout ), +}; + +/** "ping" command descriptor */ +static struct command_descriptor ping_cmd = + COMMAND_DESC ( struct ping_options, ping_opts, 1, 1, "<host>" ); + +/** + * The "ping" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int ping_exec ( int argc, char **argv ) { + struct ping_options opts; + const char *hostname; + int rc; + + /* Initialise options */ + memset ( &opts, 0, sizeof ( opts ) ); + opts.size = PING_DEFAULT_SIZE; + opts.timeout = PING_DEFAULT_TIMEOUT; + + /* Parse options */ + if ( ( rc = reparse_options ( argc, argv, &ping_cmd, &opts ) ) != 0 ) + return rc; + + /* Parse hostname */ + hostname = argv[optind]; + + /* Ping */ + if ( ( rc = ping ( hostname, opts.timeout, opts.size ) ) != 0 ) + return rc; + + return 0; +} + +/** Ping command */ +struct command ping_command __command = { + .name = "ping", + .exec = ping_exec, +}; diff --git a/roms/ipxe/src/hci/commands/poweroff_cmd.c b/roms/ipxe/src/hci/commands/poweroff_cmd.c new file mode 100644 index 000000000..9d487d330 --- /dev/null +++ b/roms/ipxe/src/hci/commands/poweroff_cmd.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <ipxe/reboot.h> + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Power off command + * + */ + +/** "poweroff" options */ +struct poweroff_options {}; + +/** "poweroff" option list */ +static struct option_descriptor poweroff_opts[] = {}; + +/** "poweroff" command descriptor */ +static struct command_descriptor poweroff_cmd = + COMMAND_DESC ( struct poweroff_options, poweroff_opts, 0, 0, NULL ); + +/** + * The "poweroff" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int poweroff_exec ( int argc, char **argv ) { + struct poweroff_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &poweroff_cmd, &opts ) ) != 0 ) + return rc; + + /* Power off system */ + rc = poweroff(); + if ( rc != 0 ) + printf ( "Could not power off: %s\n", strerror ( rc ) ); + + return rc; +} + +/** "poweroff" command */ +struct command poweroff_command __command = { + .name = "poweroff", + .exec = poweroff_exec, +}; diff --git a/roms/ipxe/src/hci/commands/profstat_cmd.c b/roms/ipxe/src/hci/commands/profstat_cmd.c new file mode 100644 index 000000000..e4c9e5a24 --- /dev/null +++ b/roms/ipxe/src/hci/commands/profstat_cmd.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <getopt.h> +#include <ipxe/command.h> +#include <ipxe/parseopt.h> +#include <usr/profstat.h> + +/** @file + * + * Profiling commands + * + */ + +/** "profstat" options */ +struct profstat_options {}; + +/** "profstat" option list */ +static struct option_descriptor profstat_opts[] = {}; + +/** "profstat" command descriptor */ +static struct command_descriptor profstat_cmd = + COMMAND_DESC ( struct profstat_options, profstat_opts, 0, 0, NULL ); + +/** + * The "profstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int profstat_exec ( int argc, char **argv ) { + struct profstat_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &profstat_cmd, &opts ) ) != 0 ) + return rc; + + profstat(); + + return 0; +} + +/** Profiling commands */ +struct command profstat_commands[] __command = { + { + .name = "profstat", + .exec = profstat_exec, + }, +}; diff --git a/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c b/roms/ipxe/src/hci/commands/reboot_cmd.c index 74c69c94e..485939e42 100644 --- a/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c +++ b/roms/ipxe/src/hci/commands/reboot_cmd.c @@ -17,9 +17,10 @@ * 02110-1301, USA. */ -#include <realmode.h> +#include <getopt.h> #include <ipxe/command.h> #include <ipxe/parseopt.h> +#include <ipxe/reboot.h> FILE_LICENCE ( GPL2_OR_LATER ); @@ -30,14 +31,20 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ /** "reboot" options */ -struct reboot_options {}; +struct reboot_options { + /** Perform a warm reboot */ + int warm; +}; /** "reboot" option list */ -static struct option_descriptor reboot_opts[] = {}; +static struct option_descriptor reboot_opts[] = { + OPTION_DESC ( "warm", 'w', no_argument, + struct reboot_options, warm, parse_flag ), +}; /** "reboot" command descriptor */ static struct command_descriptor reboot_cmd = - COMMAND_DESC ( struct reboot_options, reboot_opts, 0, 0, "" ); + COMMAND_DESC ( struct reboot_options, reboot_opts, 0, 0, NULL ); /** * The "reboot" command @@ -55,7 +62,7 @@ static int reboot_exec ( int argc, char **argv ) { return rc; /* Reboot system */ - __asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) : : ); + reboot ( opts.warm ); return 0; } diff --git a/roms/ipxe/src/hci/commands/route_cmd.c b/roms/ipxe/src/hci/commands/route_cmd.c index 3b51f06b0..cc5ffc2f2 100644 --- a/roms/ipxe/src/hci/commands/route_cmd.c +++ b/roms/ipxe/src/hci/commands/route_cmd.c @@ -39,7 +39,7 @@ static struct option_descriptor route_opts[] = {}; /** "route" command descriptor */ static struct command_descriptor route_cmd = - COMMAND_DESC ( struct route_options, route_opts, 0, 0, "" ); + COMMAND_DESC ( struct route_options, route_opts, 0, 0, NULL ); /** * The "route" command diff --git a/roms/ipxe/src/hci/commands/sanboot_cmd.c b/roms/ipxe/src/hci/commands/sanboot_cmd.c index 14055a8c4..5954b6326 100644 --- a/roms/ipxe/src/hci/commands/sanboot_cmd.c +++ b/roms/ipxe/src/hci/commands/sanboot_cmd.c @@ -46,30 +46,38 @@ struct sanboot_options { }; /** "sanboot" option list */ -static struct option_descriptor sanboot_opts[] = { - OPTION_DESC ( "drive", 'd', required_argument, - struct sanboot_options, drive, parse_integer ), - OPTION_DESC ( "no-describe", 'n', no_argument, - struct sanboot_options, no_describe, parse_flag ), - OPTION_DESC ( "keep", 'k', no_argument, - struct sanboot_options, keep, parse_flag ), +static union { + /* "sanboot" takes all three options */ + struct option_descriptor sanboot[3]; + /* "sanhook" takes only --drive and --no-describe */ + struct option_descriptor sanhook[2]; + /* "sanunhook" takes only --drive */ + struct option_descriptor sanunhook[1]; +} opts = { + .sanboot = { + OPTION_DESC ( "drive", 'd', required_argument, + struct sanboot_options, drive, parse_integer ), + OPTION_DESC ( "no-describe", 'n', no_argument, + struct sanboot_options, no_describe, parse_flag ), + OPTION_DESC ( "keep", 'k', no_argument, + struct sanboot_options, keep, parse_flag ), + }, }; + /** "sanhook" command descriptor */ static struct command_descriptor sanhook_cmd = - COMMAND_DESC ( struct sanboot_options, sanboot_opts, 1, 1, - "[--drive <drive>] [--no-describe] <root-path>" ); + COMMAND_DESC ( struct sanboot_options, opts.sanhook, 1, 1, + "<root-path>" ); /** "sanboot" command descriptor */ static struct command_descriptor sanboot_cmd = - COMMAND_DESC ( struct sanboot_options, sanboot_opts, 0, 1, - "[--drive <drive>] [--no-describe] [--keep] " + COMMAND_DESC ( struct sanboot_options, opts.sanboot, 0, 1, "[<root-path>]" ); /** "sanunhook" command descriptor */ static struct command_descriptor sanunhook_cmd = - COMMAND_DESC ( struct sanboot_options, sanboot_opts, 0, 0, - "[--drive <drive>]" ); + COMMAND_DESC ( struct sanboot_options, opts.sanunhook, 0, 0, NULL ); /** * The "sanboot", "sanhook" and "sanunhook" commands diff --git a/roms/ipxe/src/hci/commands/sync_cmd.c b/roms/ipxe/src/hci/commands/sync_cmd.c index 221e87395..adf7e3cc6 100644 --- a/roms/ipxe/src/hci/commands/sync_cmd.c +++ b/roms/ipxe/src/hci/commands/sync_cmd.c @@ -24,8 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <getopt.h> #include <ipxe/command.h> #include <ipxe/parseopt.h> -#include <ipxe/timer.h> -#include <ipxe/pending.h> +#include <usr/sync.h> /** @file * @@ -36,19 +35,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** "sync" options */ struct sync_options { /** Timeout */ - unsigned int timeout; + unsigned long timeout; }; /** "sync" option list */ static struct option_descriptor sync_opts[] = { OPTION_DESC ( "timeout", 't', required_argument, - struct sync_options, timeout, parse_integer ), + struct sync_options, timeout, parse_timeout ), }; /** "sync" command descriptor */ static struct command_descriptor sync_cmd = - COMMAND_DESC ( struct sync_options, sync_opts, 0, 0, - "[--timeout <timeout>]" ); + COMMAND_DESC ( struct sync_options, sync_opts, 0, 0, NULL ); /** * "sync" command @@ -59,7 +57,6 @@ static struct command_descriptor sync_cmd = */ static int sync_exec ( int argc, char **argv ) { struct sync_options opts; - unsigned long timeout; int rc; /* Parse options */ @@ -67,8 +64,7 @@ static int sync_exec ( int argc, char **argv ) { return rc; /* Wait for pending operations to complete */ - timeout = ( ( opts.timeout * TICKS_PER_SEC ) / 1000 ); - if ( ( rc = pending_wait ( timeout ) ) != 0 ) { + if ( ( rc = sync ( opts.timeout ) ) != 0 ) { printf ( "Operations did not complete: %s\n", strerror ( rc ) ); return rc; } diff --git a/roms/ipxe/src/hci/commands/vlan_cmd.c b/roms/ipxe/src/hci/commands/vlan_cmd.c index 822e5dcf3..5d7298220 100644 --- a/roms/ipxe/src/hci/commands/vlan_cmd.c +++ b/roms/ipxe/src/hci/commands/vlan_cmd.c @@ -53,7 +53,6 @@ static struct option_descriptor vcreate_opts[] = { /** "vcreate" command descriptor */ static struct command_descriptor vcreate_cmd = COMMAND_DESC ( struct vcreate_options, vcreate_opts, 1, 1, - "--tag <tag> [--priority <priority>] " "<trunk interface>" ); /** diff --git a/roms/ipxe/src/hci/linux_args.c b/roms/ipxe/src/hci/linux_args.c index 0bce4af9c..58eeb063e 100644 --- a/roms/ipxe/src/hci/linux_args.c +++ b/roms/ipxe/src/hci/linux_args.c @@ -45,9 +45,9 @@ __asmcall void save_args(int argc, char **argv) /** Supported command-line options */ static struct option options[] = { - {"net", 1, 0, 'n'}, - {"settings", 1, 0, 's'}, - {0, 0, 0, 0} + {"net", 1, NULL, 'n'}, + {"settings", 1, NULL, 's'}, + {NULL, 0, NULL, 0} }; /** diff --git a/roms/ipxe/src/hci/mucurses/ansi_screen.c b/roms/ipxe/src/hci/mucurses/ansi_screen.c index d952e5f2a..1d3143f89 100644 --- a/roms/ipxe/src/hci/mucurses/ansi_screen.c +++ b/roms/ipxe/src/hci/mucurses/ansi_screen.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <curses.h> +#include <ipxe/ansicol.h> #include <ipxe/console.h> FILE_LICENCE ( GPL2_OR_LATER ); @@ -9,17 +10,29 @@ static void ansiscr_movetoyx(struct _curses_screen *scr, unsigned int y, unsigned int x) __nonnull; static void ansiscr_putc(struct _curses_screen *scr, chtype c) __nonnull; -unsigned short _COLS = 80; -unsigned short _LINES = 24; - static unsigned int saved_usage; +static void ansiscr_attrs ( struct _curses_screen *scr, attr_t attrs ) { + int bold = ( attrs & A_BOLD ); + attr_t cpair = PAIR_NUMBER ( attrs ); + + if ( scr->attrs != attrs ) { + scr->attrs = attrs; + /* Reset attributes and set/clear bold as appropriate */ + printf ( "\033[0;%dm", ( bold ? 1 : 22 ) ); + /* Set foreground and background colours */ + ansicol_set_pair ( cpair ); + } +} + static void ansiscr_reset ( struct _curses_screen *scr ) { /* Reset terminal attributes and clear screen */ scr->attrs = 0; scr->curs_x = 0; scr->curs_y = 0; - printf ( "\033[0m" ); + printf ( "\0330m" ); + ansicol_set_pair ( CPAIR_DEFAULT ); + printf ( "\033[2J" ); } static void ansiscr_init ( struct _curses_screen *scr ) { @@ -32,6 +45,11 @@ static void ansiscr_exit ( struct _curses_screen *scr ) { console_set_usage ( saved_usage ); } +static void ansiscr_erase ( struct _curses_screen *scr, attr_t attrs ) { + ansiscr_attrs ( scr, attrs ); + printf ( "\033[2J" ); +} + static void ansiscr_movetoyx ( struct _curses_screen *scr, unsigned int y, unsigned int x ) { if ( ( x != scr->curs_x ) || ( y != scr->curs_y ) ) { @@ -45,24 +63,15 @@ static void ansiscr_movetoyx ( struct _curses_screen *scr, static void ansiscr_putc ( struct _curses_screen *scr, chtype c ) { unsigned int character = ( c & A_CHARTEXT ); attr_t attrs = ( c & ( A_ATTRIBUTES | A_COLOR ) ); - int bold = ( attrs & A_BOLD ); - attr_t cpair = PAIR_NUMBER ( attrs ); - short fcol; - short bcol; /* Update attributes if changed */ - if ( attrs != scr->attrs ) { - scr->attrs = attrs; - pair_content ( cpair, &fcol, &bcol ); - /* ANSI escape sequence to update character attributes */ - printf ( "\033[0;%d;3%d;4%dm", ( bold ? 1 : 22 ), fcol, bcol ); - } + ansiscr_attrs ( scr, attrs ); /* Print the actual character */ putchar ( character ); /* Update expected cursor position */ - if ( ++(scr->curs_x) == _COLS ) { + if ( ++(scr->curs_x) == COLS ) { scr->curs_x = 0; ++scr->curs_y; } @@ -76,11 +85,18 @@ static bool ansiscr_peek ( struct _curses_screen *scr __unused ) { return iskey(); } +static void ansiscr_cursor ( struct _curses_screen *scr __unused, + int visibility ) { + printf ( "\033[?25%c", ( visibility ? 'h' : 'l' ) ); +} + SCREEN _ansi_screen = { .init = ansiscr_init, .exit = ansiscr_exit, + .erase = ansiscr_erase, .movetoyx = ansiscr_movetoyx, .putc = ansiscr_putc, .getc = ansiscr_getc, .peek = ansiscr_peek, + .cursor = ansiscr_cursor, }; diff --git a/roms/ipxe/src/hci/mucurses/clear.c b/roms/ipxe/src/hci/mucurses/clear.c index 79b296cfe..f5e52ca20 100644 --- a/roms/ipxe/src/hci/mucurses/clear.c +++ b/roms/ipxe/src/hci/mucurses/clear.c @@ -88,3 +88,13 @@ int werase ( WINDOW *win ) { wclrtobot( win ); return OK; } + +/** + * Completely clear the screen + * + * @ret rc return status code + */ +int erase ( void ) { + stdscr->scr->erase( stdscr->scr, stdscr->attrs ); + return OK; +} diff --git a/roms/ipxe/src/hci/mucurses/kb.c b/roms/ipxe/src/hci/mucurses/kb.c index cada72917..b38c8c146 100644 --- a/roms/ipxe/src/hci/mucurses/kb.c +++ b/roms/ipxe/src/hci/mucurses/kb.c @@ -88,7 +88,7 @@ int wgetnstr ( WINDOW *win, char *str, int n ) { int c; if ( n == 0 ) { - str = '\0'; + *str = '\0'; return OK; } diff --git a/roms/ipxe/src/hci/mucurses/mucurses.c b/roms/ipxe/src/hci/mucurses/mucurses.c index ab9a6535f..b67445baf 100644 --- a/roms/ipxe/src/hci/mucurses/mucurses.c +++ b/roms/ipxe/src/hci/mucurses/mucurses.c @@ -75,7 +75,7 @@ void _wputch ( WINDOW *win, chtype ch, int wrap ) { * @v wrap wrap "switch" */ void _wputc ( WINDOW *win, char c, int wrap ) { - _wputch ( win, ( c | win->attrs ), wrap ); + _wputch ( win, ( ( ( unsigned char ) c ) | win->attrs ), wrap ); } /** @@ -144,3 +144,13 @@ int wmove ( WINDOW *win, int y, int x ) { _wupdcurs(win); return OK; } + +/** + * Set cursor visibility + * + * @v visibility cursor visibility + */ +int curs_set ( int visibility ) { + stdscr->scr->cursor ( stdscr->scr, visibility ); + return OK; +} diff --git a/roms/ipxe/src/hci/mucurses/wininit.c b/roms/ipxe/src/hci/mucurses/wininit.c index 782e7b5c6..b75abba44 100644 --- a/roms/ipxe/src/hci/mucurses/wininit.c +++ b/roms/ipxe/src/hci/mucurses/wininit.c @@ -31,6 +31,7 @@ WINDOW *initscr ( void ) { int endwin ( void ) { attrset ( 0 ); color_set ( 0, NULL ); + curs_set ( 1 ); mvprintw ( ( LINES - 1 ), 0, "\n" ); stdscr->scr->exit( stdscr->scr ); return OK; diff --git a/roms/ipxe/src/hci/shell.c b/roms/ipxe/src/hci/shell.c index b62086769..c1a543849 100644 --- a/roms/ipxe/src/hci/shell.c +++ b/roms/ipxe/src/hci/shell.c @@ -107,7 +107,7 @@ static struct option_descriptor shell_opts[] = {}; /** "shell" command descriptor */ static struct command_descriptor shell_cmd = - COMMAND_DESC ( struct shell_options, shell_opts, 0, 0, "" ); + COMMAND_DESC ( struct shell_options, shell_opts, 0, 0, NULL ); /** * "shell" command diff --git a/roms/ipxe/src/hci/tui/login_ui.c b/roms/ipxe/src/hci/tui/login_ui.c index 52ab0e360..996b68a0a 100644 --- a/roms/ipxe/src/hci/tui/login_ui.c +++ b/roms/ipxe/src/hci/tui/login_ui.c @@ -32,21 +32,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/settings.h> #include <ipxe/editbox.h> #include <ipxe/keys.h> +#include <ipxe/ansicol.h> #include <ipxe/login_ui.h> -#include <config/colour.h> - -/* Colour pairs */ -#define CPAIR_NORMAL 1 -#define CPAIR_EDIT 2 /* Screen layout */ -#define USERNAME_LABEL_ROW 8 -#define USERNAME_ROW 10 -#define PASSWORD_LABEL_ROW 14 -#define PASSWORD_ROW 16 -#define LABEL_COL 36 -#define EDITBOX_COL 30 -#define EDITBOX_WIDTH 20 +#define USERNAME_LABEL_ROW ( ( LINES / 2U ) - 4U ) +#define USERNAME_ROW ( ( LINES / 2U ) - 2U ) +#define PASSWORD_LABEL_ROW ( ( LINES / 2U ) + 2U ) +#define PASSWORD_ROW ( ( LINES / 2U ) + 4U ) +#define LABEL_COL ( ( COLS / 2U ) - 4U ) +#define EDITBOX_COL ( ( COLS / 2U ) - 10U ) +#define EDITBOX_WIDTH 20U int login_ui ( void ) { char username[64]; @@ -66,8 +62,6 @@ int login_ui ( void ) { /* Initialise UI */ initscr(); start_color(); - init_pair ( CPAIR_NORMAL, COLOR_NORMAL_FG, COLOR_NORMAL_BG ); - init_pair ( CPAIR_EDIT, COLOR_EDIT_FG, COLOR_EDIT_BG ); init_editbox ( &username_box, username, sizeof ( username ), NULL, USERNAME_ROW, EDITBOX_COL, EDITBOX_WIDTH, 0 ); init_editbox ( &password_box, password, sizeof ( password ), NULL, diff --git a/roms/ipxe/src/hci/tui/menu_ui.c b/roms/ipxe/src/hci/tui/menu_ui.c index dfa1d2e76..0a9566def 100644 --- a/roms/ipxe/src/hci/tui/menu_ui.c +++ b/roms/ipxe/src/hci/tui/menu_ui.c @@ -31,28 +31,23 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/keys.h> #include <ipxe/timer.h> #include <ipxe/console.h> +#include <ipxe/ansicol.h> #include <ipxe/menu.h> -#include <config/colour.h> - -/* Colour pairs */ -#define CPAIR_NORMAL 1 -#define CPAIR_SELECT 2 -#define CPAIR_SEPARATOR 3 /* Screen layout */ -#define TITLE_ROW 1 -#define MENU_ROW 3 -#define MENU_COL 1 -#define MENU_ROWS 18 -#define MENU_COLS 78 -#define MENU_PAD 2 +#define TITLE_ROW 1U +#define MENU_ROW 3U +#define MENU_COL 1U +#define MENU_ROWS ( LINES - 2U - MENU_ROW ) +#define MENU_COLS ( COLS - 2U ) +#define MENU_PAD 2U /** A menu user interface */ struct menu_ui { /** Menu */ struct menu *menu; /** Number of menu items */ - int count; + unsigned int count; /** Currently selected item */ int selected; /** First visible item */ @@ -247,12 +242,17 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { i = 0; list_for_each_entry ( item, &ui->menu->items, list ) { - if ( item->shortcut == key ) { - ui->selected = i; + if ( ! ( item->shortcut && + ( item->shortcut == key ) ) ) { + i++; + continue; + } + ui->selected = i; + if ( item->label ) { chosen = 1; - break; + } else { + move = +1; } - i++; } break; } @@ -264,7 +264,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { if ( ui->selected < 0 ) { ui->selected = 0; move = +1; - } else if ( ui->selected >= ui->count ) { + } else if ( ui->selected >= ( int ) ui->count ) { ui->selected = ( ui->count - 1 ); move = -1; } @@ -283,12 +283,10 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { draw_menu_item ( ui, ui->selected ); } - /* Refuse to choose unlabelled items (i.e. separators) */ - item = menu_item ( ui->menu, ui->selected ); - if ( ! item->label ) - chosen = 0; - /* Record selection */ + item = menu_item ( ui->menu, ui->selected ); + assert ( item != NULL ); + assert ( item->label != NULL ); *selected = item; } while ( ( rc == 0 ) && ! chosen ); @@ -300,11 +298,11 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { * Show menu * * @v menu Menu - * @v wait_ms Time to wait, in milliseconds (0=indefinite) + * @v timeout Timeout period, in ticks (0=indefinite) * @ret selected Selected item * @ret rc Return status code */ -int show_menu ( struct menu *menu, unsigned int timeout_ms, +int show_menu ( struct menu *menu, unsigned long timeout, const char *select, struct menu_item **selected ) { struct menu_item *item; struct menu_ui ui; @@ -315,7 +313,7 @@ int show_menu ( struct menu *menu, unsigned int timeout_ms, /* Initialise UI */ memset ( &ui, 0, sizeof ( ui ) ); ui.menu = menu; - ui.timeout = ( ( timeout_ms * TICKS_PER_SEC ) / 1000 ); + ui.timeout = timeout; list_for_each_entry ( item, &menu->items, list ) { if ( item->label ) { if ( ! labelled_count ) @@ -342,10 +340,8 @@ int show_menu ( struct menu *menu, unsigned int timeout_ms, /* Initialise screen */ initscr(); start_color(); - init_pair ( CPAIR_NORMAL, COLOR_NORMAL_FG, COLOR_NORMAL_BG ); - init_pair ( CPAIR_SELECT, COLOR_SELECT_FG, COLOR_SELECT_BG ); - init_pair ( CPAIR_SEPARATOR, COLOR_SEPARATOR_FG, COLOR_SEPARATOR_BG ); color_set ( CPAIR_NORMAL, NULL ); + curs_set ( 0 ); erase(); /* Draw initial content */ diff --git a/roms/ipxe/src/hci/tui/settings_ui.c b/roms/ipxe/src/hci/tui/settings_ui.c index 403d12453..221839730 100644 --- a/roms/ipxe/src/hci/tui/settings_ui.c +++ b/roms/ipxe/src/hci/tui/settings_ui.c @@ -28,8 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/settings.h> #include <ipxe/editbox.h> #include <ipxe/keys.h> +#include <ipxe/ansicol.h> #include <ipxe/settings_ui.h> -#include <config/colour.h> /** @file * @@ -37,33 +37,31 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/* Colour pairs */ -#define CPAIR_NORMAL 1 -#define CPAIR_SELECT 2 -#define CPAIR_EDIT 3 -#define CPAIR_ALERT 4 -#define CPAIR_URL 5 - /* Screen layout */ -#define TITLE_ROW 1 -#define SETTINGS_LIST_ROW 3 -#define SETTINGS_LIST_COL 1 -#define SETTINGS_LIST_ROWS 15 -#define INFO_ROW 19 -#define ALERT_ROW 22 -#define INSTRUCTION_ROW 22 +#define TITLE_ROW 1U +#define SETTINGS_LIST_ROW 3U +#define SETTINGS_LIST_COL 1U +#define SETTINGS_LIST_ROWS ( LINES - 6U - SETTINGS_LIST_ROW ) +#define INFO_ROW ( LINES - 5U ) +#define ALERT_ROW ( LINES - 2U ) +#define INSTRUCTION_ROW ( LINES - 2U ) #define INSTRUCTION_PAD " " /** Layout of text within a setting widget */ -struct setting_row_text { - char start[0]; - char pad1[1]; - char name[15]; - char pad2[1]; - char value[60]; - char pad3[1]; - char nul; -} __attribute__ (( packed )); +#define SETTING_ROW_TEXT( cols ) struct { \ + char start[0]; \ + char pad1[1]; \ + union { \ + char settings[ cols - 1 - 1 - 1 - 1 ]; \ + struct { \ + char name[15]; \ + char pad2[1]; \ + char value[ cols - 1 - 15 - 1 - 1 - 1 - 1 ]; \ + } setting; \ + } u; \ + char pad3[1]; \ + char nul; \ +} __attribute__ (( packed )) /** A setting row widget */ struct setting_row_widget { @@ -72,11 +70,16 @@ struct setting_row_widget { * Valid only for rows that lead to new settings blocks. */ struct settings *settings; + /** Configuration setting origin + * + * Valid only for rows that represent individual settings. + */ + struct settings *origin; /** Configuration setting * * Valid only for rows that represent individual settings. */ - struct setting *setting; + struct setting setting; /** Screen row */ unsigned int row; /** Screen column */ @@ -85,8 +88,6 @@ struct setting_row_widget { struct edit_box editbox; /** Editing in progress flag */ int editing; - /** Setting originates from this block flag */ - int originates_here; /** Buffer for setting's value */ char value[256]; /* enough size for a DHCP string */ }; @@ -114,9 +115,10 @@ struct setting_widget { */ static unsigned int select_setting_row ( struct setting_widget *widget, unsigned int index ) { + SETTING_ROW_TEXT ( COLS ) *text; struct settings *settings; - struct settings *origin; struct setting *setting; + struct setting *previous = NULL; unsigned int count = 0; /* Initialise structure */ @@ -144,21 +146,23 @@ static unsigned int select_setting_row ( struct setting_widget *widget, /* Include any applicable settings */ for_each_table_entry ( setting, SETTINGS ) { + + /* Skip inapplicable settings */ if ( ! setting_applies ( widget->settings, setting ) ) continue; - if ( count++ == index ) { - widget->row.setting = setting; - /* Read current setting value */ - fetchf_setting ( widget->settings, widget->row.setting, + /* Skip duplicate settings */ + if ( previous && ( setting_cmp ( setting, previous ) == 0 ) ) + continue; + previous = setting; + + /* Read current setting value and origin */ + if ( count++ == index ) { + fetchf_setting ( widget->settings, setting, + &widget->row.origin, + &widget->row.setting, widget->row.value, sizeof ( widget->row.value ) ); - - /* Check setting's origin */ - origin = fetch_setting_origin ( widget->settings, - widget->row.setting ); - widget->row.originates_here = - ( origin == widget->settings ); } } @@ -166,13 +170,20 @@ static unsigned int select_setting_row ( struct setting_widget *widget, init_editbox ( &widget->row.editbox, widget->row.value, sizeof ( widget->row.value ), NULL, widget->row.row, ( widget->row.col + - offsetof ( struct setting_row_text, value ) ), - sizeof ( ( ( struct setting_row_text * ) NULL )->value ), - 0 ); + offsetof ( typeof ( *text ), u.setting.value ) ), + sizeof ( text->u.setting.value ), 0 ); return count; } +/** + * Copy string without NUL termination + * + * @v dest Destination + * @v src Source + * @v len Maximum length of destination + * @ret len Length of (unterminated) string + */ static size_t string_copy ( char *dest, const char *src, size_t len ) { size_t src_len; @@ -189,7 +200,7 @@ static size_t string_copy ( char *dest, const char *src, size_t len ) { * @v widget Setting widget */ static void draw_setting_row ( struct setting_widget *widget ) { - struct setting_row_text text; + SETTING_ROW_TEXT ( COLS ) text; unsigned int curs_offset; char *value; @@ -201,29 +212,33 @@ static void draw_setting_row ( struct setting_widget *widget ) { if ( widget->row.settings ) { /* Construct space-padded name */ - curs_offset = ( offsetof ( typeof ( text ), name ) + - string_copy ( text.name, widget->row.value, - sizeof ( text.name ) ) ); + curs_offset = ( offsetof ( typeof ( text ), u.settings ) + + string_copy ( text.u.settings, + widget->row.value, + sizeof ( text.u.settings ) ) ); } else { /* Construct dot-padded name */ - memset ( text.name, '.', sizeof ( text.name ) ); - string_copy ( text.name, widget->row.setting->name, - sizeof ( text.name ) ); + memset ( text.u.setting.name, '.', + sizeof ( text.u.setting.name ) ); + string_copy ( text.u.setting.name, widget->row.setting.name, + sizeof ( text.u.setting.name ) ); /* Construct space-padded value */ value = widget->row.value; if ( ! *value ) value = "<not specified>"; - curs_offset = ( offsetof ( typeof ( text ), value ) + - string_copy ( text.value, value, - sizeof ( text.value ) ) ); + curs_offset = ( offsetof ( typeof ( text ), u.setting.value ) + + string_copy ( text.u.setting.value, value, + sizeof ( text.u.setting.value ))); } /* Print row */ - if ( widget->row.originates_here || widget->row.settings ) + if ( ( widget->row.origin == widget->settings ) || + ( widget->row.settings != NULL ) ) { attron ( A_BOLD ); + } mvprintw ( widget->row.row, widget->row.col, "%s", text.start ); attroff ( A_BOLD ); move ( widget->row.row, widget->row.col + curs_offset ); @@ -237,7 +252,7 @@ static void draw_setting_row ( struct setting_widget *widget ) { * @ret key Key returned to application, or zero */ static int edit_setting ( struct setting_widget *widget, int key ) { - assert ( widget->row.setting != NULL ); + assert ( widget->row.setting.name != NULL ); widget->row.editing = 1; return edit_editbox ( &widget->row.editbox, key ); } @@ -248,8 +263,8 @@ static int edit_setting ( struct setting_widget *widget, int key ) { * @v widget Setting widget */ static int save_setting ( struct setting_widget *widget ) { - assert ( widget->row.setting != NULL ); - return storef_setting ( widget->settings, widget->row.setting, + assert ( widget->row.setting.name != NULL ); + return storef_setting ( widget->settings, &widget->row.setting, widget->row.value ); } @@ -344,28 +359,26 @@ static void draw_title_row ( struct setting_widget *widget ) { * @v widget Setting widget */ static void draw_info_row ( struct setting_widget *widget ) { - struct settings *origin; char buf[32]; /* Draw nothing unless this row represents a setting */ clearmsg ( INFO_ROW ); clearmsg ( INFO_ROW + 1 ); - if ( ! widget->row.setting ) + if ( ! widget->row.setting.name ) return; /* Determine a suitable setting name */ - origin = fetch_setting_origin ( widget->settings, widget->row.setting ); - if ( ! origin ) - origin = widget->settings; - setting_name ( origin, widget->row.setting, buf, sizeof ( buf ) ); + setting_name ( ( widget->row.origin ? + widget->row.origin : widget->settings ), + &widget->row.setting, buf, sizeof ( buf ) ); /* Draw row */ attron ( A_BOLD ); - msg ( INFO_ROW, "%s - %s", buf, widget->row.setting->description ); + msg ( INFO_ROW, "%s - %s", buf, widget->row.setting.description ); attroff ( A_BOLD ); color_set ( CPAIR_URL, NULL ); msg ( ( INFO_ROW + 1 ), "http://ipxe.org/cfg/%s", - widget->row.setting->name ); + widget->row.setting.name ); color_set ( CPAIR_NORMAL, NULL ); } @@ -384,7 +397,7 @@ static void draw_instruction_row ( struct setting_widget *widget ) { } else { msg ( INSTRUCTION_ROW, "%sCtrl-X - exit configuration utility", - ( widget->row.originates_here ? + ( ( widget->row.origin == widget->settings ) ? "Ctrl-D - delete setting" INSTRUCTION_PAD : "" ) ); } } @@ -441,7 +454,7 @@ static void reveal_setting_row ( struct setting_widget *widget, static void init_widget ( struct setting_widget *widget, struct settings *settings ) { - widget->settings = settings; + widget->settings = settings_target ( settings ); widget->num_rows = select_setting_row ( widget, 0 ); widget->first_visible = SETTINGS_LIST_ROWS; draw_title_row ( widget ); @@ -472,13 +485,14 @@ static int main_loop ( struct settings *settings ) { CPAIR_EDIT : CPAIR_SELECT ), NULL ); draw_setting_row ( &widget ); color_set ( CPAIR_NORMAL, NULL ); + curs_set ( widget.row.editing ); redraw = 0; } if ( widget.row.editing ) { /* Sanity check */ - assert ( widget.row.setting != NULL ); + assert ( widget.row.setting.name != NULL ); /* Redraw edit box */ color_set ( CPAIR_EDIT, NULL ); @@ -508,19 +522,31 @@ static int main_loop ( struct settings *settings ) { key = getkey ( 0 ); move = 0; switch ( key ) { + case KEY_UP: + move = -1; + break; case KEY_DOWN: - if ( widget.current < ( widget.num_rows - 1 ) ) - move = +1; + move = +1; break; - case KEY_UP: - if ( widget.current > 0 ) - move = -1; + case KEY_PPAGE: + move = ( widget.first_visible - + widget.current - 1 ); + break; + case KEY_NPAGE: + move = ( widget.first_visible - widget.current + + SETTINGS_LIST_ROWS ); + break; + case KEY_HOME: + move = -widget.num_rows; + break; + case KEY_END: + move = +widget.num_rows; break; case CTRL_D: - if ( ! widget.row.setting ) + if ( ! widget.row.setting.name ) break; if ( ( rc = delete_setting ( widget.settings, - widget.row.setting ) ) != 0 ) { + &widget.row.setting ) ) != 0 ) { alert ( " %s ", strerror ( rc ) ); } select_setting_row ( &widget, widget.current ); @@ -537,7 +563,7 @@ static int main_loop ( struct settings *settings ) { } /* Fall through */ default: - if ( widget.row.setting ) { + if ( widget.row.setting.name ) { edit_setting ( &widget, key ); redraw = 1; } @@ -545,10 +571,16 @@ static int main_loop ( struct settings *settings ) { } if ( move ) { next = ( widget.current + move ); - draw_setting_row ( &widget ); - redraw = 1; - reveal_setting_row ( &widget, next ); - select_setting_row ( &widget, next ); + if ( ( int ) next < 0 ) + next = 0; + if ( next >= widget.num_rows ) + next = ( widget.num_rows - 1 ); + if ( next != widget.current ) { + draw_setting_row ( &widget ); + redraw = 1; + reveal_setting_row ( &widget, next ); + select_setting_row ( &widget, next ); + } } } } @@ -559,12 +591,8 @@ int settings_ui ( struct settings *settings ) { initscr(); start_color(); - init_pair ( CPAIR_NORMAL, COLOR_NORMAL_FG, COLOR_NORMAL_BG ); - init_pair ( CPAIR_SELECT, COLOR_SELECT_FG, COLOR_SELECT_BG ); - init_pair ( CPAIR_EDIT, COLOR_EDIT_FG, COLOR_EDIT_BG ); - init_pair ( CPAIR_ALERT, COLOR_ALERT_FG, COLOR_ALERT_BG ); - init_pair ( CPAIR_URL, COLOR_URL_FG, COLOR_URL_BG ); color_set ( CPAIR_NORMAL, NULL ); + curs_set ( 0 ); erase(); rc = main_loop ( settings ); diff --git a/roms/ipxe/src/image/efi_image.c b/roms/ipxe/src/image/efi_image.c index bee966e71..5de915b0a 100644 --- a/roms/ipxe/src/image/efi_image.c +++ b/roms/ipxe/src/image/efi_image.c @@ -21,7 +21,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> #include <stdlib.h> +#include <wchar.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_snp.h> +#include <ipxe/efi/efi_download.h> +#include <ipxe/efi/efi_file.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/efi_strings.h> #include <ipxe/image.h> #include <ipxe/init.h> #include <ipxe/features.h> @@ -29,84 +35,96 @@ FILE_LICENCE ( GPL2_OR_LATER ); FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 ); +/* Disambiguate the various error causes */ +#define EINFO_EEFI_LOAD \ + __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \ + "Could not load image" ) +#define EINFO_EEFI_LOAD_PROHIBITED \ + __einfo_platformify ( EINFO_EEFI_LOAD, EFI_SECURITY_VIOLATION, \ + "Image prohibited by security policy" ) +#define EEFI_LOAD_PROHIBITED \ + __einfo_error ( EINFO_EEFI_LOAD_PROHIBITED ) +#define EEFI_LOAD( efirc ) EPLATFORM ( EINFO_EEFI_LOAD, efirc, \ + EEFI_LOAD_PROHIBITED ) +#define EINFO_EEFI_START \ + __einfo_uniqify ( EINFO_EPLATFORM, 0x02, \ + "Could not start image" ) +#define EEFI_START( efirc ) EPLATFORM ( EINFO_EEFI_START, efirc ) + /** EFI loaded image protocol GUID */ static EFI_GUID efi_loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; /** - * Create a Unicode command line for the image + * Create device path for image + * + * @v image EFI image + * @v parent Parent device path + * @ret path Device path, or NULL on failure + * + * The caller must eventually free() the device path. + */ +static EFI_DEVICE_PATH_PROTOCOL * +efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) { + EFI_DEVICE_PATH_PROTOCOL *path; + FILEPATH_DEVICE_PATH *filepath; + EFI_DEVICE_PATH_PROTOCOL *end; + size_t name_len; + size_t prefix_len; + size_t filepath_len; + size_t len; + + /* Calculate device path lengths */ + end = efi_devpath_end ( parent ); + prefix_len = ( ( void * ) end - ( void * ) parent ); + name_len = strlen ( image->name ); + filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ); + len = ( prefix_len + filepath_len + sizeof ( *end ) ); + + /* Allocate device path */ + path = zalloc ( len ); + if ( ! path ) + return NULL; + + /* Construct device path */ + memcpy ( path, parent, prefix_len ); + filepath = ( ( ( void * ) path ) + prefix_len ); + filepath->Header.Type = MEDIA_DEVICE_PATH; + filepath->Header.SubType = MEDIA_FILEPATH_DP; + filepath->Header.Length[0] = ( filepath_len & 0xff ); + filepath->Header.Length[1] = ( filepath_len >> 8 ); + efi_snprintf ( filepath->PathName, ( name_len + 1 /* NUL */ ), + "%s", image->name ); + end = ( ( ( void * ) filepath ) + filepath_len ); + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + return path; +} + +/** + * Create command line for image * * @v image EFI image - * @v devpath_out Device path to pass to image (output) - * @v cmdline_out Unicode command line (output) - * @v cmdline_len_out Length of command line in bytes (output) - * @ret rc Return status code + * @ret cmdline Command line, or NULL on failure */ -static int efi_image_make_cmdline ( struct image *image, - EFI_DEVICE_PATH **devpath_out, - VOID **cmdline_out, - UINT32 *cmdline_len_out ) { - char *uri; - size_t uri_len; - FILEPATH_DEVICE_PATH *devpath; - EFI_DEVICE_PATH *endpath; - size_t devpath_len; - CHAR16 *cmdline; - UINT32 cmdline_len; - size_t args_len = 0; - UINT32 i; - - /* Get the URI string of the image */ - uri_len = unparse_uri ( NULL, 0, image->uri, URI_ALL ) + 1; - - /* Compute final command line length */ - if ( image->cmdline ) { - args_len = strlen ( image->cmdline ) + 1; - } - cmdline_len = args_len + uri_len; +static wchar_t * efi_image_cmdline ( struct image *image ) { + wchar_t *cmdline; + size_t len; - /* Allocate space for the uri, final command line and device path */ - cmdline = malloc ( cmdline_len * sizeof ( CHAR16 ) + uri_len - + SIZE_OF_FILEPATH_DEVICE_PATH - + uri_len * sizeof ( CHAR16 ) - + sizeof ( EFI_DEVICE_PATH ) ); + len = ( strlen ( image->name ) + + ( image->cmdline ? + ( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) ); + cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) ); if ( ! cmdline ) - return -ENOMEM; - uri = (char *) ( cmdline + cmdline_len ); - devpath = (FILEPATH_DEVICE_PATH *) ( uri + uri_len ); - endpath = (EFI_DEVICE_PATH *) ( (char *) devpath - + SIZE_OF_FILEPATH_DEVICE_PATH - + uri_len * sizeof ( CHAR16 ) ); - - /* Build the iPXE device path */ - devpath->Header.Type = MEDIA_DEVICE_PATH; - devpath->Header.SubType = MEDIA_FILEPATH_DP; - devpath_len = SIZE_OF_FILEPATH_DEVICE_PATH - + uri_len * sizeof ( CHAR16 ); - devpath->Header.Length[0] = devpath_len & 0xFF; - devpath->Header.Length[1] = devpath_len >> 8; - endpath->Type = END_DEVICE_PATH_TYPE; - endpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - endpath->Length[0] = 4; - endpath->Length[1] = 0; - unparse_uri ( uri, uri_len, image->uri, URI_ALL ); - - /* Convert to Unicode */ - for ( i = 0 ; i < uri_len ; i++ ) { - cmdline[i] = uri[i]; - devpath->PathName[i] = uri[i]; - } - if ( image->cmdline ) { - cmdline[uri_len - 1] = ' '; - } - for ( i = 0 ; i < args_len ; i++ ) { - cmdline[i + uri_len] = image->cmdline[i]; - } - - *devpath_out = &devpath->Header; - *cmdline_out = cmdline; - *cmdline_len_out = cmdline_len * sizeof ( CHAR16 ); - return 0; + return NULL; + efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s", + image->name, + ( image->cmdline ? " " : "" ), + ( image->cmdline ? image->cmdline : "" ) ); + return cmdline; } /** @@ -117,25 +135,66 @@ static int efi_image_make_cmdline ( struct image *image, */ static int efi_image_exec ( struct image *image ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_snp_device *snpdev; + EFI_DEVICE_PATH_PROTOCOL *path; union { EFI_LOADED_IMAGE_PROTOCOL *image; void *interface; } loaded; EFI_HANDLE handle; - EFI_HANDLE device_handle = NULL; - UINTN exit_data_size; - CHAR16 *exit_data; + wchar_t *cmdline; EFI_STATUS efirc; int rc; + /* Find an appropriate device handle to use */ + snpdev = last_opened_snpdev(); + if ( ! snpdev ) { + DBGC ( image, "EFIIMAGE %p could not identify SNP device\n", + image ); + rc = -ENODEV; + goto err_no_snpdev; + } + + /* Install file I/O protocols */ + if ( ( rc = efi_file_install ( &snpdev->handle ) ) != 0 ) { + DBGC ( image, "EFIIMAGE %p could not install file protocol: " + "%s\n", image, strerror ( rc ) ); + goto err_file_install; + } + + /* Install iPXE download protocol */ + if ( ( rc = efi_download_install ( &snpdev->handle ) ) != 0 ) { + DBGC ( image, "EFIIMAGE %p could not install iPXE download " + "protocol: %s\n", image, strerror ( rc ) ); + goto err_download_install; + } + + /* Create device path for image */ + path = efi_image_path ( image, &snpdev->path ); + if ( ! path ) { + DBGC ( image, "EFIIMAGE %p could not create device path\n", + image ); + rc = -ENOMEM; + goto err_image_path; + } + + /* Create command line for image */ + cmdline = efi_image_cmdline ( image ); + if ( ! cmdline ) { + DBGC ( image, "EFIIMAGE %p could not create command line\n", + image ); + rc = -ENOMEM; + goto err_cmdline; + } + /* Attempt loading image */ - if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL, + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path, user_to_virt ( image->data, 0 ), image->len, &handle ) ) != 0 ) { /* Not an EFI image */ + rc = -EEFI_LOAD ( efirc ); DBGC ( image, "EFIIMAGE %p could not load: %s\n", - image, efi_strerror ( efirc ) ); - rc = -ENOEXEC; + image, strerror ( rc ) ); goto err_load_image; } @@ -145,29 +204,29 @@ static int efi_image_exec ( struct image *image ) { NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if ( efirc ) { /* Should never happen */ - rc = EFIRC_TO_RC ( efirc ); + rc = -EEFI ( efirc ); goto err_open_protocol; } - /* Pass an iPXE download protocol to the image */ - if ( ( rc = efi_download_install ( &device_handle ) ) != 0 ) { - DBGC ( image, "EFIIMAGE %p could not install iPXE download " - "protocol: %s\n", image, strerror ( rc ) ); - goto err_download_install; - } - loaded.image->DeviceHandle = device_handle; - loaded.image->ParentHandle = efi_loaded_image; - if ( ( rc = efi_image_make_cmdline ( image, &loaded.image->FilePath, - &loaded.image->LoadOptions, - &loaded.image->LoadOptionsSize ) ) != 0 ) - goto err_make_cmdline; + /* Sanity checks */ + assert ( loaded.image->ParentHandle == efi_image_handle ); + assert ( loaded.image->DeviceHandle == snpdev->handle ); + assert ( loaded.image->LoadOptionsSize == 0 ); + assert ( loaded.image->LoadOptions == NULL ); + + /* Set command line */ + loaded.image->LoadOptions = cmdline; + loaded.image->LoadOptionsSize = + ( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) ); + + /* Release network devices for use via SNP */ + efi_snp_release(); /* Start the image */ - if ( ( efirc = bs->StartImage ( handle, &exit_data_size, - &exit_data ) ) != 0 ) { + if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) { + rc = -EEFI_START ( efirc ); DBGC ( image, "EFIIMAGE %p returned with status %s\n", - image, efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + image, strerror ( rc ) ); goto err_start_image; } @@ -175,17 +234,26 @@ static int efi_image_exec ( struct image *image ) { rc = 0; err_start_image: - free ( loaded.image->LoadOptions ); - err_make_cmdline: - efi_download_uninstall ( device_handle ); - err_download_install: + efi_snp_claim(); err_open_protocol: /* Unload the image. We can't leave it loaded, because we * have no "unload" operation. */ - bs->UnloadImage ( handle ); + if ( ( efirc = bs->UnloadImage ( handle ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( image, "EFIIMAGE %p could not unload: %s\n", + image, strerror ( rc ) ); + } err_load_image: - + free ( cmdline ); + err_cmdline: + free ( path ); + err_image_path: + efi_download_uninstall ( snpdev->handle ); + err_download_install: + efi_file_uninstall ( snpdev->handle ); + err_file_install: + err_no_snpdev: return rc; } @@ -199,15 +267,17 @@ static int efi_image_probe ( struct image *image ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE handle; EFI_STATUS efirc; + int rc; /* Attempt loading image */ if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL, user_to_virt ( image->data, 0 ), image->len, &handle ) ) != 0 ) { /* Not an EFI image */ + rc = -EEFI_LOAD ( efirc ); DBGC ( image, "EFIIMAGE %p could not load: %s\n", - image, efi_strerror ( efirc ) ); - return -ENOEXEC; + image, strerror ( rc ) ); + return rc; } /* Unload the image. We can't leave it loaded, because we diff --git a/roms/ipxe/src/image/png.c b/roms/ipxe/src/image/png.c new file mode 100644 index 000000000..c14608553 --- /dev/null +++ b/roms/ipxe/src/image/png.c @@ -0,0 +1,1007 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/umalloc.h> +#include <ipxe/pixbuf.h> +#include <ipxe/deflate.h> +#include <ipxe/png.h> + +/** @file + * + * Portable Network Graphics (PNG) format + * + * The PNG format is defined in RFC 2083. + */ + +/** PNG context */ +struct png_context { + /** Offset within image */ + size_t offset; + + /** Pixel buffer */ + struct pixel_buffer *pixbuf; + + /** Bit depth */ + unsigned int depth; + /** Colour type */ + unsigned int colour_type; + /** Number of channels */ + unsigned int channels; + /** Number of interlace passes */ + unsigned int passes; + /** Palette, in iPXE's pixel buffer format */ + uint32_t palette[PNG_PALETTE_COUNT]; + + /** Decompression buffer for raw PNG data */ + struct deflate_chunk raw; + /** Decompressor */ + struct deflate deflate; +}; + +/** A PNG interlace pass */ +struct png_interlace { + /** Pass number */ + unsigned int pass; + /** X starting indent */ + unsigned int x_indent; + /** Y starting indent */ + unsigned int y_indent; + /** X stride */ + unsigned int x_stride; + /** Y stride */ + unsigned int y_stride; + /** Width */ + unsigned int width; + /** Height */ + unsigned int height; +}; + +/** PNG file signature */ +static struct png_signature png_signature = PNG_SIGNATURE; + +/** Number of interlacing passes */ +static uint8_t png_interlace_passes[] = { + [PNG_INTERLACE_NONE] = 1, + [PNG_INTERLACE_ADAM7] = 7, +}; + +/** + * Transcribe PNG chunk type name (for debugging) + * + * @v type Chunk type + * @ret name Chunk type name + */ +static const char * png_type_name ( uint32_t type ) { + static union { + uint32_t type; + char name[ sizeof ( uint32_t ) + 1 /* NUL */ ]; + } u; + + u.type = type; + return u.name; +} + +/** + * Calculate PNG interlace pass parameters + * + * @v png PNG context + * @v pass Pass number (0=first pass) + * @v interlace Interlace pass to fill in + */ +static void png_interlace ( struct png_context *png, unsigned int pass, + struct png_interlace *interlace ) { + unsigned int grid_width_log2; + unsigned int grid_height_log2; + unsigned int x_indent; + unsigned int y_indent; + unsigned int x_stride_log2; + unsigned int y_stride_log2; + unsigned int x_stride; + unsigned int y_stride; + unsigned int width; + unsigned int height; + + /* Sanity check */ + assert ( png->passes > 0 ); + + /* Store pass number */ + interlace->pass = pass; + + /* Calculate interlace grid dimensions */ + grid_width_log2 = ( png->passes / 2 ); + grid_height_log2 = ( ( png->passes - 1 ) / 2 ); + + /* Calculate starting indents */ + interlace->x_indent = x_indent = + ( ( pass & 1 ) ? + ( 1 << ( grid_width_log2 - ( pass / 2 ) - 1 ) ) : 0 ); + interlace->y_indent = y_indent = + ( ( pass && ! ( pass & 1 ) ) ? + ( 1 << ( grid_height_log2 - ( ( pass - 1 ) / 2 ) - 1 ) ) : 0); + + /* Calculate strides */ + x_stride_log2 = ( grid_width_log2 - ( pass / 2 ) ); + y_stride_log2 = + ( grid_height_log2 - ( pass ? ( ( pass - 1 ) / 2 ) : 0 ) ); + interlace->x_stride = x_stride = ( 1 << x_stride_log2 ); + interlace->y_stride = y_stride = ( 1 << y_stride_log2 ); + + /* Calculate pass dimensions */ + width = png->pixbuf->width; + height = png->pixbuf->height; + interlace->width = + ( ( width - x_indent + x_stride - 1 ) >> x_stride_log2 ); + interlace->height = + ( ( height - y_indent + y_stride - 1 ) >> y_stride_log2 ); +} + +/** + * Calculate PNG pixel length + * + * @v png PNG context + * @ret pixel_len Pixel length + */ +static unsigned int png_pixel_len ( struct png_context *png ) { + + return ( ( ( png->channels * png->depth ) + 7 ) / 8 ); +} + +/** + * Calculate PNG scanline length + * + * @v png PNG context + * @v interlace Interlace pass + * @ret scanline_len Scanline length (including filter byte) + */ +static size_t png_scanline_len ( struct png_context *png, + struct png_interlace *interlace ) { + + return ( 1 /* Filter byte */ + + ( ( interlace->width * png->channels * png->depth ) + 7 ) / 8); +} + +/** + * Handle PNG image header chunk + * + * @v image PNG image + * @v png PNG context + * @v len Chunk length + * @ret rc Return status code + */ +static int png_image_header ( struct image *image, struct png_context *png, + size_t len ) { + struct png_image_header ihdr; + struct png_interlace interlace; + unsigned int pass; + + /* Sanity check */ + if ( len != sizeof ( ihdr ) ) { + DBGC ( image, "PNG %s invalid IHDR length %zd\n", + image->name, len ); + return -EINVAL; + } + if ( png->pixbuf ) { + DBGC ( image, "PNG %s duplicate IHDR\n", image->name ); + return -EINVAL; + } + + /* Extract image header */ + copy_from_user ( &ihdr, image->data, png->offset, len ); + DBGC ( image, "PNG %s %dx%d depth %d type %d compression %d filter %d " + "interlace %d\n", image->name, ntohl ( ihdr.width ), + ntohl ( ihdr.height ), ihdr.depth, ihdr.colour_type, + ihdr.compression, ihdr.filter, ihdr.interlace ); + + /* Sanity checks */ + if ( ihdr.compression >= PNG_COMPRESSION_UNKNOWN ) { + DBGC ( image, "PNG %s unknown compression method %d\n", + image->name, ihdr.compression ); + return -ENOTSUP; + } + if ( ihdr.filter >= PNG_FILTER_UNKNOWN ) { + DBGC ( image, "PNG %s unknown filter method %d\n", + image->name, ihdr.filter ); + return -ENOTSUP; + } + if ( ihdr.interlace >= PNG_INTERLACE_UNKNOWN ) { + DBGC ( image, "PNG %s unknown interlace method %d\n", + image->name, ihdr.interlace ); + return -ENOTSUP; + } + + /* Allocate pixel buffer */ + png->pixbuf = alloc_pixbuf ( ntohl ( ihdr.width ), + ntohl ( ihdr.height ) ); + if ( ! png->pixbuf ) { + DBGC ( image, "PNG %s could not allocate pixel buffer\n", + image->name ); + return -ENOMEM; + } + + /* Extract bit depth */ + png->depth = ihdr.depth; + if ( ( png->depth == 0 ) || + ( ( png->depth & ( png->depth - 1 ) ) != 0 ) ) { + DBGC ( image, "PNG %s invalid depth %d\n", + image->name, png->depth ); + return -EINVAL; + } + + /* Calculate number of channels */ + png->colour_type = ihdr.colour_type; + png->channels = 1; + if ( ! ( ihdr.colour_type & PNG_COLOUR_TYPE_PALETTE ) ) { + if ( ihdr.colour_type & PNG_COLOUR_TYPE_RGB ) + png->channels += 2; + if ( ihdr.colour_type & PNG_COLOUR_TYPE_ALPHA ) + png->channels += 1; + } + + /* Calculate number of interlace passes */ + png->passes = png_interlace_passes[ihdr.interlace]; + + /* Calculate length of raw data buffer */ + for ( pass = 0 ; pass < png->passes ; pass++ ) { + png_interlace ( png, pass, &interlace ); + if ( interlace.width == 0 ) + continue; + png->raw.len += ( interlace.height * + png_scanline_len ( png, &interlace ) ); + } + + /* Allocate raw data buffer */ + png->raw.data = umalloc ( png->raw.len ); + if ( ! png->raw.data ) { + DBGC ( image, "PNG %s could not allocate data buffer\n", + image->name ); + return -ENOMEM; + } + + return 0; +} + +/** + * Handle PNG palette chunk + * + * @v image PNG image + * @v png PNG context + * @v len Chunk length + * @ret rc Return status code + */ +static int png_palette ( struct image *image, struct png_context *png, + size_t len ) { + size_t offset = png->offset; + struct png_palette_entry palette; + unsigned int i; + + /* Populate palette */ + for ( i = 0 ; i < ( sizeof ( png->palette ) / + sizeof ( png->palette[0] ) ) ; i++ ) { + + /* Stop when we run out of palette data */ + if ( len < sizeof ( palette ) ) + break; + + /* Extract palette entry */ + copy_from_user ( &palette, image->data, offset, + sizeof ( palette ) ); + png->palette[i] = ( ( palette.red << 16 ) | + ( palette.green << 8 ) | + ( palette.blue << 0 ) ); + DBGC2 ( image, "PNG %s palette entry %d is %#06x\n", + image->name, i, png->palette[i] ); + + /* Move to next entry */ + offset += sizeof ( palette ); + len -= sizeof ( palette ); + } + + return 0; +} + +/** + * Handle PNG image data chunk + * + * @v image PNG image + * @v png PNG context + * @v len Chunk length + * @ret rc Return status code + */ +static int png_image_data ( struct image *image, struct png_context *png, + size_t len ) { + struct deflate_chunk in; + int rc; + + /* Deflate this chunk */ + deflate_chunk_init ( &in, image->data, png->offset, + ( png->offset + len ) ); + if ( ( rc = deflate_inflate ( &png->deflate, &in, &png->raw ) ) != 0 ) { + DBGC ( image, "PNG %s could not decompress: %s\n", + image->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Unfilter byte using the "None" filter + * + * @v current Filtered current byte + * @v left Unfiltered left byte + * @v above Unfiltered above byte + * @v above_left Unfiltered above-left byte + * @ret current Unfiltered current byte + */ +static unsigned int png_unfilter_none ( unsigned int current, + unsigned int left __unused, + unsigned int above __unused, + unsigned int above_left __unused ) { + + return current; +} + +/** + * Unfilter byte using the "Sub" filter + * + * @v current Filtered current byte + * @v left Unfiltered left byte + * @v above Unfiltered above byte + * @v above_left Unfiltered above-left byte + * @ret current Unfiltered current byte + */ +static unsigned int png_unfilter_sub ( unsigned int current, + unsigned int left, + unsigned int above __unused, + unsigned int above_left __unused ) { + + return ( current + left ); +} + +/** + * Unfilter byte using the "Up" filter + * + * @v current Filtered current byte + * @v left Unfiltered left byte + * @v above Unfiltered above byte + * @v above_left Unfiltered above-left byte + * @ret current Unfiltered current byte + */ +static unsigned int png_unfilter_up ( unsigned int current, + unsigned int left __unused, + unsigned int above, + unsigned int above_left __unused ) { + + return ( current + above ); +} + +/** + * Unfilter byte using the "Average" filter + * + * @v current Filtered current byte + * @v left Unfiltered left byte + * @v above Unfiltered above byte + * @v above_left Unfiltered above-left byte + * @ret current Unfiltered current byte + */ +static unsigned int png_unfilter_average ( unsigned int current, + unsigned int left, + unsigned int above, + unsigned int above_left __unused ) { + + return ( current + ( ( above + left ) >> 1 ) ); +} + +/** + * Paeth predictor function (defined in RFC 2083) + * + * @v a Pixel A + * @v b Pixel B + * @v c Pixel C + * @ret predictor Predictor pixel + */ +static unsigned int png_paeth_predictor ( unsigned int a, unsigned int b, + unsigned int c ) { + unsigned int p; + unsigned int pa; + unsigned int pb; + unsigned int pc; + + /* Algorithm as defined in RFC 2083 section 6.6 */ + p = ( a + b - c ); + pa = abs ( p - a ); + pb = abs ( p - b ); + pc = abs ( p - c ); + if ( ( pa <= pb ) && ( pa <= pc ) ) { + return a; + } else if ( pb <= pc ) { + return b; + } else { + return c; + } +} + +/** + * Unfilter byte using the "Paeth" filter + * + * @v current Filtered current byte + * @v above_left Unfiltered above-left byte + * @v above Unfiltered above byte + * @v left Unfiltered left byte + * @ret current Unfiltered current byte + */ +static unsigned int png_unfilter_paeth ( unsigned int current, + unsigned int left, + unsigned int above, + unsigned int above_left ) { + + return ( current + png_paeth_predictor ( left, above, above_left ) ); +} + +/** A PNG filter */ +struct png_filter { + /** + * Unfilter byte + * + * @v current Filtered current byte + * @v left Unfiltered left byte + * @v above Unfiltered above byte + * @v above_left Unfiltered above-left byte + * @ret current Unfiltered current byte + */ + unsigned int ( * unfilter ) ( unsigned int current, + unsigned int left, + unsigned int above, + unsigned int above_left ); +}; + +/** PNG filter types */ +static struct png_filter png_filters[] = { + [PNG_FILTER_BASIC_NONE] = { png_unfilter_none }, + [PNG_FILTER_BASIC_SUB] = { png_unfilter_sub }, + [PNG_FILTER_BASIC_UP] = { png_unfilter_up }, + [PNG_FILTER_BASIC_AVERAGE] = { png_unfilter_average }, + [PNG_FILTER_BASIC_PAETH] = { png_unfilter_paeth }, +}; + +/** + * Unfilter one interlace pass of PNG raw data + * + * @v image PNG image + * @v png PNG context + * @v interlace Interlace pass + * @ret rc Return status code + * + * This routine may assume that it is impossible to overrun the raw + * data buffer, since the size is determined by the image dimensions. + */ +static int png_unfilter_pass ( struct image *image, struct png_context *png, + struct png_interlace *interlace ) { + size_t offset = png->raw.offset; + size_t pixel_len = png_pixel_len ( png ); + size_t scanline_len = png_scanline_len ( png, interlace ); + struct png_filter *filter; + unsigned int scanline; + unsigned int byte; + uint8_t filter_type; + uint8_t left; + uint8_t above; + uint8_t above_left; + uint8_t current; + + /* On the first scanline of a pass, above bytes are assumed to + * be zero. + */ + above = 0; + + /* Iterate over each scanline in turn */ + for ( scanline = 0 ; scanline < interlace->height ; scanline++ ) { + + /* Extract filter byte and determine filter type */ + copy_from_user ( &filter_type, png->raw.data, offset++, + sizeof ( filter_type ) ); + if ( filter_type >= ( sizeof ( png_filters ) / + sizeof ( png_filters[0] ) ) ) { + DBGC ( image, "PNG %s unknown filter type %d\n", + image->name, filter_type ); + return -ENOTSUP; + } + filter = &png_filters[filter_type]; + assert ( filter->unfilter != NULL ); + DBGC2 ( image, "PNG %s pass %d scanline %d filter type %d\n", + image->name, interlace->pass, scanline, filter_type ); + + /* At the start of a line, both above-left and left + * bytes are taken to be zero. + */ + left = 0; + above_left = 0; + + /* Iterate over each byte (not pixel) in turn */ + for ( byte = 0 ; byte < ( scanline_len - 1 ) ; byte++ ) { + + /* Extract predictor bytes, if applicable */ + if ( byte >= pixel_len ) { + copy_from_user ( &left, png->raw.data, + ( offset - pixel_len ), + sizeof ( left ) ); + } + if ( scanline > 0 ) { + copy_from_user ( &above, png->raw.data, + ( offset - scanline_len ), + sizeof ( above ) ); + } + if ( ( scanline > 0 ) && ( byte >= pixel_len ) ) { + copy_from_user ( &above_left, png->raw.data, + ( offset - scanline_len - + pixel_len ), + sizeof ( above_left ) ); + } + + /* Unfilter current byte */ + copy_from_user ( ¤t, png->raw.data, + offset, sizeof ( current ) ); + current = filter->unfilter ( current, left, above, + above_left ); + copy_to_user ( png->raw.data, offset++, + ¤t, sizeof ( current ) ); + } + } + + /* Update offset */ + png->raw.offset = offset; + + return 0; +} + +/** + * Unfilter PNG raw data + * + * @v image PNG image + * @v png PNG context + * @ret rc Return status code + * + * This routine may assume that it is impossible to overrun the raw + * data buffer, since the size is determined by the image dimensions. + */ +static int png_unfilter ( struct image *image, struct png_context *png ) { + struct png_interlace interlace; + unsigned int pass; + int rc; + + /* Process each interlace pass */ + png->raw.offset = 0; + for ( pass = 0 ; pass < png->passes ; pass++ ) { + + /* Calculate interlace pass parameters */ + png_interlace ( png, pass, &interlace ); + + /* Skip zero-width rows (which have no filter bytes) */ + if ( interlace.width == 0 ) + continue; + + /* Unfilter this pass */ + if ( ( rc = png_unfilter_pass ( image, png, + &interlace ) ) != 0 ) + return rc; + } + assert ( png->raw.offset == png->raw.len ); + + return 0; +} + +/** + * Calculate PNG pixel component value + * + * @v raw Raw component value + * @v alpha Alpha value + * @v max Maximum raw/alpha value + * @ret value Component value in range 0-255 + */ +static inline unsigned int png_pixel ( unsigned int raw, unsigned int alpha, + unsigned int max ) { + + /* The basic calculation is 255*(raw/max)*(value/max). We use + * fixed-point arithmetic (scaling up to the maximum range for + * a 32-bit integer), in order to get the same results for + * alpha blending as the test cases (produced using + * ImageMagick). + */ + return ( ( ( ( ( 0xff00 * raw * alpha ) / max ) / max ) + 0x80 ) >> 8 ); +} + +/** + * Fill one interlace pass of PNG pixels + * + * @v image PNG image + * @v png PNG context + * @v interlace Interlace pass + * + * This routine may assume that it is impossible to overrun either the + * raw data buffer or the pixel buffer, since the sizes of both are + * determined by the image dimensions. + */ +static void png_pixels_pass ( struct image *image, + struct png_context *png, + struct png_interlace *interlace ) { + size_t raw_offset = png->raw.offset; + uint8_t channel[png->channels]; + int is_indexed = ( png->colour_type & PNG_COLOUR_TYPE_PALETTE ); + int is_rgb = ( png->colour_type & PNG_COLOUR_TYPE_RGB ); + int has_alpha = ( png->colour_type & PNG_COLOUR_TYPE_ALPHA ); + size_t pixbuf_y_offset; + size_t pixbuf_offset; + size_t pixbuf_x_stride; + size_t pixbuf_y_stride; + size_t raw_stride; + unsigned int y; + unsigned int x; + unsigned int c; + unsigned int bits; + unsigned int depth; + unsigned int max; + unsigned int alpha; + unsigned int raw; + unsigned int value; + uint8_t current = 0; + uint32_t pixel; + + /* We only ever use the top byte of 16-bit pixels. Model this + * as a bit depth of 8 with a stride of more than one. + */ + depth = png->depth; + raw_stride = ( ( depth + 7 ) / 8 ); + if ( depth > 8 ) + depth = 8; + max = ( ( 1 << depth ) - 1 ); + + /* Calculate pixel buffer offset and strides */ + pixbuf_y_offset = ( ( ( interlace->y_indent * png->pixbuf->width ) + + interlace->x_indent ) * sizeof ( pixel ) ); + pixbuf_x_stride = ( interlace->x_stride * sizeof ( pixel ) ); + pixbuf_y_stride = ( interlace->y_stride * png->pixbuf->width * + sizeof ( pixel ) ); + DBGC2 ( image, "PNG %s pass %d %dx%d at (%d,%d) stride (%d,%d)\n", + image->name, interlace->pass, interlace->width, + interlace->height, interlace->x_indent, interlace->y_indent, + interlace->x_stride, interlace->y_stride ); + + /* Iterate over each scanline in turn */ + for ( y = 0 ; y < interlace->height ; y++ ) { + + /* Skip filter byte */ + raw_offset++; + + /* Iterate over each pixel in turn */ + bits = depth; + pixbuf_offset = pixbuf_y_offset; + for ( x = 0 ; x < interlace->width ; x++ ) { + + /* Extract sample value */ + for ( c = 0 ; c < png->channels ; c++ ) { + + /* Get sample value into high bits of current */ + current <<= depth; + bits -= depth; + if ( ! bits ) { + copy_from_user ( ¤t, + png->raw.data, + raw_offset, + sizeof ( current ) ); + raw_offset += raw_stride; + bits = 8; + } + + /* Extract sample value */ + channel[c] = ( current >> ( 8 - depth ) ); + } + + /* Convert to native pixel format */ + if ( is_indexed ) { + + /* Indexed */ + pixel = png->palette[channel[0]]; + + } else { + + /* Determine alpha value */ + alpha = ( has_alpha ? + channel[ png->channels - 1 ] : max ); + + /* Convert to RGB value */ + pixel = 0; + for ( c = 0 ; c < 3 ; c++ ) { + raw = channel[ is_rgb ? c : 0 ]; + value = png_pixel ( raw, alpha, max ); + assert ( value <= 255 ); + pixel = ( ( pixel << 8 ) | value ); + } + } + + /* Store pixel */ + copy_to_user ( png->pixbuf->data, pixbuf_offset, + &pixel, sizeof ( pixel ) ); + pixbuf_offset += pixbuf_x_stride; + } + + /* Move to next output row */ + pixbuf_y_offset += pixbuf_y_stride; + } + + /* Update offset */ + png->raw.offset = raw_offset; +} + +/** + * Fill PNG pixels + * + * @v image PNG image + * @v png PNG context + * + * This routine may assume that it is impossible to overrun either the + * raw data buffer or the pixel buffer, since the sizes of both are + * determined by the image dimensions. + */ +static void png_pixels ( struct image *image, struct png_context *png ) { + struct png_interlace interlace; + unsigned int pass; + + /* Process each interlace pass */ + png->raw.offset = 0; + for ( pass = 0 ; pass < png->passes ; pass++ ) { + + /* Calculate interlace pass parameters */ + png_interlace ( png, pass, &interlace ); + + /* Skip zero-width rows (which have no filter bytes) */ + if ( interlace.width == 0 ) + continue; + + /* Unfilter this pass */ + png_pixels_pass ( image, png, &interlace ); + } + assert ( png->raw.offset == png->raw.len ); +} + +/** + * Handle PNG image end chunk + * + * @v image PNG image + * @v png PNG context + * @v len Chunk length + * @ret rc Return status code + */ +static int png_image_end ( struct image *image, struct png_context *png, + size_t len ) { + int rc; + + /* Sanity checks */ + if ( len != 0 ) { + DBGC ( image, "PNG %s invalid IEND length %zd\n", + image->name, len ); + return -EINVAL; + } + if ( ! png->pixbuf ) { + DBGC ( image, "PNG %s missing pixel buffer (no IHDR?)\n", + image->name ); + return -EINVAL; + } + if ( ! deflate_finished ( &png->deflate ) ) { + DBGC ( image, "PNG %s decompression not complete\n", + image->name ); + return -EINVAL; + } + if ( png->raw.offset != png->raw.len ) { + DBGC ( image, "PNG %s incorrect decompressed length (expected " + "%zd, got %zd)\n", image->name, png->raw.len, + png->raw.offset ); + return -EINVAL; + } + + /* Unfilter raw data */ + if ( ( rc = png_unfilter ( image, png ) ) != 0 ) + return rc; + + /* Fill pixel buffer */ + png_pixels ( image, png ); + + return 0; +} + +/** A PNG chunk handler */ +struct png_chunk_handler { + /** Chunk type */ + uint32_t type; + /** + * Handle chunk + * + * @v image PNG image + * @v png PNG context + * @v len Chunk length + * @ret rc Return status code + */ + int ( * handle ) ( struct image *image, struct png_context *png, + size_t len ); +}; + +/** PNG chunk handlers */ +static struct png_chunk_handler png_chunk_handlers[] = { + { htonl ( PNG_TYPE_IHDR ), png_image_header }, + { htonl ( PNG_TYPE_PLTE ), png_palette }, + { htonl ( PNG_TYPE_IDAT ), png_image_data }, + { htonl ( PNG_TYPE_IEND ), png_image_end }, +}; + +/** + * Handle PNG chunk + * + * @v image PNG image + * @v png PNG context + * @v type Chunk type + * @v len Chunk length + * @ret rc Return status code + */ +static int png_chunk ( struct image *image, struct png_context *png, + uint32_t type, size_t len ) { + struct png_chunk_handler *handler; + unsigned int i; + + DBGC ( image, "PNG %s chunk type %s offset %zd length %zd\n", + image->name, png_type_name ( type ), png->offset, len ); + + /* Handle according to chunk type */ + for ( i = 0 ; i < ( sizeof ( png_chunk_handlers ) / + sizeof ( png_chunk_handlers[0] ) ) ; i++ ) { + handler = &png_chunk_handlers[i]; + if ( handler->type == type ) + return handler->handle ( image, png, len ); + } + + /* Fail if unknown chunk type is critical */ + if ( ! ( type & htonl ( PNG_CHUNK_ANCILLARY ) ) ) { + DBGC ( image, "PNG %s unknown critical chunk type %s\n", + image->name, png_type_name ( type ) ); + return -ENOTSUP; + } + + /* Ignore non-critical unknown chunk types */ + return 0; +} + +/** + * Convert PNG image to pixel buffer + * + * @v image PNG image + * @v pixbuf Pixel buffer to fill in + * @ret rc Return status code + */ +static int png_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) { + struct png_context *png; + struct png_chunk_header header; + struct png_chunk_footer footer; + size_t remaining; + size_t chunk_len; + int rc; + + /* Allocate and initialise context */ + png = zalloc ( sizeof ( *png ) ); + if ( ! png ) { + rc = -ENOMEM; + goto err_alloc; + } + png->offset = sizeof ( struct png_signature ); + deflate_init ( &png->deflate, DEFLATE_ZLIB ); + + /* Process chunks */ + do { + + /* Extract chunk header */ + remaining = ( image->len - png->offset ); + if ( remaining < sizeof ( header ) ) { + DBGC ( image, "PNG %s truncated chunk header at offset " + "%zd\n", image->name, png->offset ); + rc = -EINVAL; + goto err_truncated; + } + copy_from_user ( &header, image->data, png->offset, + sizeof ( header ) ); + png->offset += sizeof ( header ); + + /* Validate chunk length */ + chunk_len = ntohl ( header.len ); + if ( remaining < ( sizeof ( header ) + chunk_len + + sizeof ( footer ) ) ) { + DBGC ( image, "PNG %s truncated chunk data/footer at " + "offset %zd\n", image->name, png->offset ); + rc = -EINVAL; + goto err_truncated; + } + + /* Handle chunk */ + if ( ( rc = png_chunk ( image, png, header.type, + chunk_len ) ) != 0 ) + goto err_chunk; + + /* Move to next chunk */ + png->offset += ( chunk_len + sizeof ( footer ) ); + + } while ( png->offset < image->len ); + + /* Check that we finished with an IEND chunk */ + if ( header.type != htonl ( PNG_TYPE_IEND ) ) { + DBGC ( image, "PNG %s did not finish with IEND\n", + image->name ); + rc = -EINVAL; + goto err_iend; + } + + /* Return pixel buffer */ + *pixbuf = pixbuf_get ( png->pixbuf ); + + /* Success */ + rc = 0; + + err_iend: + err_chunk: + err_truncated: + pixbuf_put ( png->pixbuf ); + ufree ( png->raw.data ); + free ( png ); + err_alloc: + return rc; +} + +/** + * Probe PNG image + * + * @v image PNG image + * @ret rc Return status code + */ +static int png_probe ( struct image *image ) { + struct png_signature signature; + + /* Sanity check */ + if ( image->len < sizeof ( signature ) ) { + DBGC ( image, "PNG %s is too short\n", image->name ); + return -ENOEXEC; + } + + /* Check signature */ + copy_from_user ( &signature, image->data, 0, sizeof ( signature ) ); + if ( memcmp ( &signature, &png_signature, sizeof ( signature ) ) != 0 ){ + DBGC ( image, "PNG %s has invalid signature\n", image->name ); + return -ENOEXEC; + } + + return 0; +} + +/** PNG image type */ +struct image_type png_image_type __image_type ( PROBE_NORMAL ) = { + .name = "PNG", + .probe = png_probe, + .pixbuf = png_pixbuf, +}; diff --git a/roms/ipxe/src/image/pnm.c b/roms/ipxe/src/image/pnm.c new file mode 100644 index 000000000..af9e571a2 --- /dev/null +++ b/roms/ipxe/src/image/pnm.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Portable anymap format (PNM) + * + */ + +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <ipxe/image.h> +#include <ipxe/pixbuf.h> +#include <ipxe/pnm.h> + +/** + * Extract PNM ASCII value + * + * @v image PNM image + * @v pnm PNM context + * @ret value Value, or negative error + */ +static int pnm_ascii ( struct image *image, struct pnm_context *pnm ) { + char buf[ pnm->ascii_len + 1 /* NUL */ ]; + char *endp; + size_t len; + int value; + int in_comment = 0; + + /* Skip any leading whitespace and comments */ + for ( ; pnm->offset < image->len ; pnm->offset++ ) { + copy_from_user ( &buf[0], image->data, pnm->offset, + sizeof ( buf[0] ) ); + if ( in_comment ) { + if ( buf[0] == '\n' ) + in_comment = 0; + } else { + if ( buf[0] == '#' ) { + in_comment = 1; + } else if ( ! isspace ( buf[0] ) ) { + break; + } + } + } + + /* Fail if no value is present */ + len = ( image->len - pnm->offset ); + if ( len == 0 ) { + DBGC ( image, "PNM %s ran out of ASCII data\n", image->name ); + return -EINVAL; + } + + /* Copy ASCII value to buffer and ensure string is NUL-terminated */ + if ( len > ( sizeof ( buf ) - 1 /* NUL */ ) ) + len = ( sizeof ( buf ) - 1 /* NUL */ ); + copy_from_user ( buf, image->data, pnm->offset, len ); + buf[len] = '\0'; + + /* Parse value and update offset */ + value = strtoul ( buf, &endp, 0 ); + pnm->offset += ( endp - buf ); + + /* Check and skip terminating whitespace character, if present */ + if ( ( pnm->offset != image->len ) && ( *endp != '\0' ) ) { + if ( ! isspace ( *endp ) ) { + DBGC ( image, "PNM %s invalid ASCII integer\n", + image->name ); + return -EINVAL; + } + pnm->offset++; + } + + return value; +} + +/** + * Extract PNM binary value + * + * @v image PNM image + * @v pnm PNM context + * @ret value Value, or negative error + */ +static int pnm_binary ( struct image *image, struct pnm_context *pnm ) { + uint8_t value; + + /* Sanity check */ + if ( pnm->offset == image->len ) { + DBGC ( image, "PNM %s ran out of binary data\n", + image->name ); + return -EINVAL; + } + + /* Extract value */ + copy_from_user ( &value, image->data, pnm->offset, sizeof ( value ) ); + pnm->offset++; + + return value; +} + +/** + * Scale PNM scalar value + * + * @v image PNM image + * @v pnm PNM context + * @v value Raw value + * @ret value Scaled value (in range 0-255) + */ +static int pnm_scale ( struct image *image, struct pnm_context *pnm, + unsigned int value ) { + + if ( value > pnm->max ) { + DBGC ( image, "PNM %s has out-of-range value %d (max %d)\n", + image->name, value, pnm->max ); + return -EINVAL; + } + return ( ( 255 * value ) / pnm->max ); +} + +/** + * Convert PNM bitmap composite value to RGB + * + * @v composite Composite value + * @v index Pixel index within this composite value + * @ret rgb 24-bit RGB value + */ +static uint32_t pnm_bitmap ( uint32_t composite, unsigned int index ) { + + /* Composite value is an 8-bit bitmask */ + return ( ( ( composite << index ) & 0x80 ) ? 0x000000 : 0xffffff ); +} + +/** + * Convert PNM greymap composite value to RGB + * + * @v composite Composite value + * @v index Pixel index within this composite value + * @ret rgb 24-bit RGB value + */ +static uint32_t pnm_greymap ( uint32_t composite, unsigned int index __unused ){ + + /* Composite value is an 8-bit greyscale value */ + return ( ( composite << 16 ) | ( composite << 8 ) | composite ); +} + +/** + * Convert PNM pixmap composite value to RGB + * + * @v composite Composite value + * @v index Pixel index within this composite value + * @ret rgb 24-bit RGB value + */ +static uint32_t pnm_pixmap ( uint32_t composite, unsigned int index __unused ) { + + /* Composite value is already an RGB value */ + return composite; +} + +/** + * Extract PNM pixel data + * + * @v image PNM image + * @v pnm PNM context + * @v pixbuf Pixel buffer + * @ret rc Return status code + */ +static int pnm_data ( struct image *image, struct pnm_context *pnm, + struct pixel_buffer *pixbuf ) { + struct pnm_type *type = pnm->type; + size_t offset = 0; + unsigned int xpos = 0; + int scalar; + uint32_t composite; + uint32_t rgb; + unsigned int i; + + /* Fill pixel buffer */ + while ( offset < pixbuf->len ) { + + /* Extract a scaled composite scalar value from the file */ + composite = 0; + for ( i = 0 ; i < type->depth ; i++ ) { + scalar = type->scalar ( image, pnm ); + if ( scalar < 0 ) + return scalar; + scalar = pnm_scale ( image, pnm, scalar ); + if ( scalar < 0 ) + return scalar; + composite = ( ( composite << 8 ) | scalar ); + } + + /* Extract 24-bit RGB values from composite value */ + for ( i = 0 ; i < type->packing ; i++ ) { + if ( offset >= pixbuf->len ) { + DBGC ( image, "PNM %s has too many pixels\n", + image->name ); + return -EINVAL; + } + rgb = type->rgb ( composite, i ); + copy_to_user ( pixbuf->data, offset, &rgb, + sizeof ( rgb ) ); + offset += sizeof ( rgb ); + if ( ++xpos == pixbuf->width ) { + xpos = 0; + break; + } + } + } + + return 0; +} + +/** PNM image types */ +static struct pnm_type pnm_types[] = { + { + .type = '1', + .depth = 1, + .packing = 1, + .flags = PNM_BITMAP, + .scalar = pnm_ascii, + .rgb = pnm_bitmap, + }, + { + .type = '2', + .depth = 1, + .packing = 1, + .scalar = pnm_ascii, + .rgb = pnm_greymap, + }, + { + .type = '3', + .depth = 3, + .packing = 1, + .scalar = pnm_ascii, + .rgb = pnm_pixmap, + }, + { + .type = '4', + .depth = 1, + .packing = 8, + .flags = PNM_BITMAP, + .scalar = pnm_binary, + .rgb = pnm_bitmap, + }, + { + .type = '5', + .depth = 1, + .packing = 1, + .scalar = pnm_binary, + .rgb = pnm_greymap, + }, + { + .type = '6', + .depth = 3, + .packing = 1, + .scalar = pnm_binary, + .rgb = pnm_pixmap, + }, +}; + +/** + * Determine PNM image type + * + * @v image PNM image + * @ret type PNM image type, or NULL if not found + */ +static struct pnm_type * pnm_type ( struct image *image ) { + struct pnm_signature signature; + struct pnm_type *type; + unsigned int i; + + /* Extract signature */ + assert ( image->len >= sizeof ( signature ) ); + copy_from_user ( &signature, image->data, 0, sizeof ( signature ) ); + + /* Check for supported types */ + for ( i = 0 ; i < ( sizeof ( pnm_types ) / + sizeof ( pnm_types[0] ) ) ; i++ ) { + type = &pnm_types[i]; + if ( type->type == signature.type ) + return type; + } + return NULL; +} + +/** + * Convert PNM image to pixel buffer + * + * @v image PNM image + * @v pixbuf Pixel buffer to fill in + * @ret rc Return status code + */ +static int pnm_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ) { + struct pnm_context pnm; + int width; + int height; + int max; + int rc; + + /* Initialise PNM context */ + pnm.type = pnm_type ( image ); + if ( ! pnm.type ) { + rc = -ENOTSUP; + goto err_type; + } + pnm.offset = sizeof ( struct pnm_signature ); + pnm.ascii_len = PNM_ASCII_LEN; + + /* Extract width */ + if ( ( width = pnm_ascii ( image, &pnm ) ) < 0 ) { + rc = width; + goto err_width; + } + + /* Extract height */ + if ( ( height = pnm_ascii ( image, &pnm ) ) < 0 ) { + rc = height; + goto err_height; + } + + /* Extract maximum scalar value, if not predefined */ + if ( pnm.type->flags & PNM_BITMAP ) { + pnm.max = ( ( 1 << pnm.type->packing ) - 1 ); + pnm.ascii_len = 1; + } else { + if ( ( max = pnm_ascii ( image, &pnm ) ) < 0 ) { + rc = max; + goto err_max; + } + pnm.max = max; + } + if ( pnm.max == 0 ) { + DBGC ( image, "PNM %s has invalid maximum value 0\n", + image->name ); + rc = -EINVAL; + goto err_max; + } + DBGC ( image, "PNM %s is type %c width %d height %d max %d\n", + image->name, pnm.type->type, width, height, pnm.max ); + + /* Allocate pixel buffer */ + *pixbuf = alloc_pixbuf ( width, height ); + if ( ! *pixbuf ) { + rc = -ENOMEM; + goto err_alloc_pixbuf; + } + + /* Extract pixel data */ + if ( ( rc = pnm_data ( image, &pnm, *pixbuf ) ) != 0 ) + goto err_data; + + return 0; + + err_data: + pixbuf_put ( *pixbuf ); + err_alloc_pixbuf: + err_max: + err_height: + err_width: + err_type: + return rc; +} + +/** + * Probe PNM image + * + * @v image PNM image + * @ret rc Return status code + */ +static int pnm_probe ( struct image *image ) { + struct pnm_signature signature; + + /* Sanity check */ + if ( image->len < sizeof ( signature ) ) { + DBGC ( image, "PNM %s is too short\n", image->name ); + return -ENOEXEC; + } + + /* Check signature */ + copy_from_user ( &signature, image->data, 0, sizeof ( signature ) ); + if ( ! ( ( signature.magic == PNM_MAGIC ) && + ( isdigit ( signature.type ) ) && + ( isspace ( signature.space ) ) ) ) { + DBGC ( image, "PNM %s has invalid signature\n", image->name ); + return -ENOEXEC; + } + DBGC ( image, "PNM %s is type %c\n", image->name, signature.type ); + + return 0; +} + +/** PNM image type */ +struct image_type pnm_image_type __image_type ( PROBE_NORMAL ) = { + .name = "PNM", + .probe = pnm_probe, + .pixbuf = pnm_pixbuf, +}; diff --git a/roms/ipxe/src/image/script.c b/roms/ipxe/src/image/script.c index e83180ab5..5328da8b4 100644 --- a/roms/ipxe/src/image/script.c +++ b/roms/ipxe/src/image/script.c @@ -55,44 +55,96 @@ static size_t script_offset; * @ret rc Return status code */ static int process_script ( struct image *image, - int ( * process_line ) ( const char *line ), + int ( * process_line ) ( struct image *image, + size_t offset, + const char *label, + const char *command ), int ( * terminate ) ( int rc ) ) { + size_t len = 0; + char *line = NULL; + size_t line_offset; + char *label; + char *command; off_t eol; - size_t len; - char *line; + size_t frag_len; + char *tmp; int rc; + /* Initialise script and line offsets */ script_offset = 0; + line_offset = 0; do { - + /* Find length of next line, excluding any terminating '\n' */ eol = memchr_user ( image->data, script_offset, '\n', ( image->len - script_offset ) ); if ( eol < 0 ) eol = image->len; - len = ( eol - script_offset ); + frag_len = ( eol - script_offset ); /* Allocate buffer for line */ - line = zalloc ( len + 1 /* NUL */ ); - if ( ! line ) - return -ENOMEM; + tmp = realloc ( line, ( len + frag_len + 1 /* NUL */ ) ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + line = tmp; /* Copy line */ - copy_from_user ( line, image->data, script_offset, len ); - DBG ( "$ %s\n", line ); - - /* Move to next line */ - script_offset += ( len + 1 ); + copy_from_user ( ( line + len ), image->data, script_offset, + frag_len ); + len += frag_len; + + /* Move to next line in script */ + script_offset += ( frag_len + 1 ); + + /* Strip trailing CR, if present */ + if ( len && ( line[ len - 1 ] == '\r' ) ) + len--; + + /* Handle backslash continuations */ + if ( len && ( line[ len - 1 ] == '\\' ) ) { + len--; + rc = -EINVAL; + continue; + } + + /* Terminate line */ + line[len] = '\0'; + + /* Split line into (optional) label and command */ + command = line; + while ( isspace ( *command ) ) + command++; + if ( *command == ':' ) { + label = ++command; + while ( *command && ! isspace ( *command ) ) + command++; + if ( *command ) + *(command++) = '\0'; + } else { + label = NULL; + } + + /* Process line */ + rc = process_line ( image, line_offset, label, command ); + if ( terminate ( rc ) ) + goto err_process; - /* Process and free line */ - rc = process_line ( line ); + /* Free line */ free ( line ); - if ( terminate ( rc ) ) - return rc; + line = NULL; + len = 0; + + /* Update line offset */ + line_offset = script_offset; } while ( script_offset < image->len ); + err_process: + err_alloc: + free ( line ); return rc; } @@ -111,18 +163,21 @@ static int terminate_on_exit_or_failure ( int rc ) { /** * Execute script line * - * @v line Line of script + * @v image Script + * @v offset Offset within script + * @v label Label, or NULL + * @v command Command * @ret rc Return status code */ -static int script_exec_line ( const char *line ) { +static int script_exec_line ( struct image *image, size_t offset, + const char *label __unused, + const char *command ) { int rc; - /* Skip label lines */ - if ( line[0] == ':' ) - return 0; + DBGC ( image, "[%04zx] $ %s\n", offset, command ); /* Execute command */ - if ( ( rc = system ( line ) ) != 0 ) + if ( ( rc = system ( command ) ) != 0 ) return rc; return 0; @@ -176,7 +231,7 @@ static int script_probe ( struct image *image ) { /* Sanity check */ if ( image->len < sizeof ( test ) ) { - DBG ( "Too short to be a script\n" ); + DBGC ( image, "Too short to be a script\n" ); return -ENOEXEC; } @@ -185,7 +240,7 @@ static int script_probe ( struct image *image ) { if ( ! ( ( ( memcmp ( test, ipxe_magic, sizeof ( test ) - 1 ) == 0 ) || ( memcmp ( test, gpxe_magic, sizeof ( test ) - 1 ) == 0 )) && isspace ( test[ sizeof ( test ) - 1 ] ) ) ) { - DBG ( "Invalid magic signature\n" ); + DBGC ( image, "Invalid magic signature\n" ); return -ENOEXEC; } @@ -219,20 +274,26 @@ static const char *goto_label; /** * Check for presence of label * - * @v line Script line + * @v image Script + * @v offset Offset within script + * @v label Label + * @v command Command * @ret rc Return status code */ -static int goto_find_label ( const char *line ) { - size_t len = strlen ( goto_label ); +static int goto_find_label ( struct image *image, size_t offset, + const char *label, const char *command __unused ) { - if ( line[0] != ':' ) + /* Check label exists */ + if ( ! label ) return -ENOENT; - if ( strncmp ( goto_label, &line[1], len ) != 0 ) + /* Check label matches */ + if ( strcmp ( goto_label, label ) != 0 ) return -ENOENT; - if ( line[ 1 + len ] && ! isspace ( line[ 1 + len ] ) ) - return -ENOENT; + /* Update script offset */ + script_offset = offset; + DBGC ( image, "[%04zx] Gone to :%s\n", offset, label ); return 0; } @@ -278,6 +339,8 @@ static int goto_exec ( int argc, char **argv ) { if ( ( rc = process_script ( current_image, goto_find_label, terminate_on_label_found ) ) != 0 ) { script_offset = saved_offset; + DBGC ( current_image, "[%04zx] No such label :%s\n", + script_offset, goto_label ); return rc; } @@ -298,7 +361,7 @@ struct prompt_options { /** Key to wait for */ unsigned int key; /** Timeout */ - unsigned int timeout; + unsigned long timeout; }; /** "prompt" option list */ @@ -306,13 +369,13 @@ static struct option_descriptor prompt_opts[] = { OPTION_DESC ( "key", 'k', required_argument, struct prompt_options, key, parse_key ), OPTION_DESC ( "timeout", 't', required_argument, - struct prompt_options, timeout, parse_integer ), + struct prompt_options, timeout, parse_timeout ), }; /** "prompt" command descriptor */ static struct command_descriptor prompt_cmd = COMMAND_DESC ( struct prompt_options, prompt_opts, 0, MAX_ARGUMENTS, - "[--key <key>] [--timeout <timeout>] [<text>]" ); + "[<text>]" ); /** * "prompt" command diff --git a/roms/ipxe/src/include/big_bswap.h b/roms/ipxe/src/include/big_bswap.h index 3775fac10..6c375a573 100644 --- a/roms/ipxe/src/include/big_bswap.h +++ b/roms/ipxe/src/include/big_bswap.h @@ -1,6 +1,8 @@ #ifndef ETHERBOOT_BIG_BSWAP_H #define ETHERBOOT_BIG_BSWAP_H +#define htonll(x) (x) +#define ntohll(x) (x) #define ntohl(x) (x) #define htonl(x) (x) #define ntohs(x) (x) diff --git a/roms/ipxe/src/include/bootp.h b/roms/ipxe/src/include/bootp.h deleted file mode 100644 index 0e65477ae..000000000 --- a/roms/ipxe/src/include/bootp.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef _BOOTP_H -#define _BOOTP_H - -#ifdef ALTERNATE_DHCP_PORTS_1067_1068 -#undef NON_STANDARD_BOOTP_SERVER -#define NON_STANDARD_BOOTP_SERVER 1067 -#undef NON_STANDARD_BOOTP_CLIENT -#define NON_STANDARD_BOOTP_CLIENT 1068 -#endif - -#ifdef NON_STANDARD_BOOTP_SERVER -#define BOOTP_SERVER NON_STANDARD_BOOTP_SERVER -#else -#define BOOTP_SERVER 67 -#endif -#ifdef NON_STANDARD_BOOTP_CLIENT -#define BOOTP_CLIENT NON_STANDARD_BOOTP_CLIENT -#else -#define BOOTP_CLIENT 68 -#endif -#define PROXYDHCP_SERVER 4011 /* For PXE */ - -#define BOOTP_REQUEST 1 -#define BOOTP_REPLY 2 - -#define TAG_LEN(p) (*((p)+1)) -#define RFC1533_COOKIE 99, 130, 83, 99 -#define RFC1533_PAD 0 -#define RFC1533_NETMASK 1 -#define RFC1533_TIMEOFFSET 2 -#define RFC1533_GATEWAY 3 -#define RFC1533_TIMESERVER 4 -#define RFC1533_IEN116NS 5 -#define RFC1533_DNS 6 -#define RFC1533_LOGSERVER 7 -#define RFC1533_COOKIESERVER 8 -#define RFC1533_LPRSERVER 9 -#define RFC1533_IMPRESSSERVER 10 -#define RFC1533_RESOURCESERVER 11 -#define RFC1533_HOSTNAME 12 -#define RFC1533_BOOTFILESIZE 13 -#define RFC1533_MERITDUMPFILE 14 -#define RFC1533_DOMAINNAME 15 -#define RFC1533_SWAPSERVER 16 -#define RFC1533_ROOTPATH 17 -#define RFC1533_EXTENSIONPATH 18 -#define RFC1533_IPFORWARDING 19 -#define RFC1533_IPSOURCEROUTING 20 -#define RFC1533_IPPOLICYFILTER 21 -#define RFC1533_IPMAXREASSEMBLY 22 -#define RFC1533_IPTTL 23 -#define RFC1533_IPMTU 24 -#define RFC1533_IPMTUPLATEAU 25 -#define RFC1533_INTMTU 26 -#define RFC1533_INTLOCALSUBNETS 27 -#define RFC1533_INTBROADCAST 28 -#define RFC1533_INTICMPDISCOVER 29 -#define RFC1533_INTICMPRESPOND 30 -#define RFC1533_INTROUTEDISCOVER 31 -#define RFC1533_INTROUTESOLICIT 32 -#define RFC1533_INTSTATICROUTES 33 -#define RFC1533_LLTRAILERENCAP 34 -#define RFC1533_LLARPCACHETMO 35 -#define RFC1533_LLETHERNETENCAP 36 -#define RFC1533_TCPTTL 37 -#define RFC1533_TCPKEEPALIVETMO 38 -#define RFC1533_TCPKEEPALIVEGB 39 -#define RFC1533_NISDOMAIN 40 -#define RFC1533_NISSERVER 41 -#define RFC1533_NTPSERVER 42 -#define RFC1533_VENDOR 43 -#define RFC1533_NBNS 44 -#define RFC1533_NBDD 45 -#define RFC1533_NBNT 46 -#define RFC1533_NBSCOPE 47 -#define RFC1533_XFS 48 -#define RFC1533_XDM 49 -#ifndef NO_DHCP_SUPPORT -#define RFC2132_REQ_ADDR 50 -#define RFC2132_MSG_TYPE 53 -#define RFC2132_SRV_ID 54 -#define RFC2132_PARAM_LIST 55 -#define RFC2132_MAX_SIZE 57 -#define RFC2132_VENDOR_CLASS_ID 60 -#define RFC2132_CLIENT_ID 61 -#define RFC2132_TFTP_SERVER_NAME 66 -#define RFC2132_BOOTFILE_NAME 67 -#define RFC3004_USER_CLASS 77 - -#ifdef PXE_DHCP_STRICT -/* - * The following options are acknowledged in RFC3679 because they are - * widely used by PXE implementations, but have never been properly - * allocated. Despite other PXE options being correctly packed in a - * vendor encapsulated field, these are exposed. Sigh. Note that the - * client UUID (option 97) is also noted in the PXE spec as using - * option 61. - */ -#define RFC3679_PXE_CLIENT_ARCH 93 -#define RFC3679_PXE_CLIENT_NDI 94 -#define RFC3679_PXE_CLIENT_UUID 97 - -/* The lengths are fixed. */ -#define RFC3679_PXE_CLIENT_ARCH_LENGTH 2 -#define RFC3679_PXE_CLIENT_NDI_LENGTH 3 -#define RFC3679_PXE_CLIENT_UUID_LENGTH 17 - -/* - * Values of RFC3679_PXE_CLIENT_ARCH can apparently be one of the - * following, according to the PXE spec. The spec only actually - * described the 2nd octet, not the first. Duh... assume 0. - */ -#define RFC3679_PXE_CLIENT_ARCH_IAX86PC 0,0 -#define RFC3679_PXE_CLIENT_ARCH_NECPC98 0,1 -#define RFC3679_PXE_CLIENT_ARCH_IA64PC 0,2 -#define RFC3679_PXE_CLIENT_ARCH_DECALPHA 0,3 -#define RFC3679_PXE_CLIENT_ARCH_ARCX86 0,4 -#define RFC3679_PXE_CLIENT_ARCH_INTELLEAN 0,5 - -/* - * Only one valid value of NDI type (must be 1) and UNDI version (must - * be 2.1) - */ -#define RFC3679_PXE_CLIENT_NDI_21 1,2,1 - -/* - * UUID - type must be 1 and then 16 octets of UID, as with the client ID. - * The value is a default for testing only - */ -#define RFC3679_PXE_CLIENT_UUID_TYPE 0 -#warning "UUID is a default for testing ONLY!" -#define RFC3679_PXE_CLIENT_UUID_DEFAULT \ - RFC3679_PXE_CLIENT_UUID_TYPE, \ - 0xDE,0xAD,0xBE,0xEF, \ - 0xDE,0xAD,0xBE,0xEF, \ - 0xDE,0xAD,0xBE,0xEF, \ - 0xDE,0xAD,0xBE,0xEF -/* - * The Vendor Class ID. Note that the Arch and UNDI version numbers - * are fixed and must be same as the ARCH and NDI above. - */ -#define RFC2132_VENDOR_CLASS_ID_PXE_LENGTH 32 -#define RFC2132_VENDOR_CLASS_ID_PXE \ - 'P','X','E','C','l','i','e','n','t',':', \ - 'A','r','c','h',':','0','0','0','0','0',':', \ - 'U','N','D','I',':','0','0','2','0','0','1' - -/* - * The following vendor options are required in the PXE spec to pull - * options for the *next* image. The PXE spec doesn't help us with - * this (like explaining why). - */ -#define RFC1533_VENDOR_PXE_OPT128 128 -#define RFC1533_VENDOR_PXE_OPT129 129 -#define RFC1533_VENDOR_PXE_OPT130 130 -#define RFC1533_VENDOR_PXE_OPT131 131 -#define RFC1533_VENDOR_PXE_OPT132 132 -#define RFC1533_VENDOR_PXE_OPT133 133 -#define RFC1533_VENDOR_PXE_OPT134 134 -#define RFC1533_VENDOR_PXE_OPT135 135 - -#endif /* PXE_DHCP_STRICT */ - -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPACK 5 -#endif /* NO_DHCP_SUPPORT */ - -#define RFC1533_VENDOR_MAJOR 0 -#define RFC1533_VENDOR_MINOR 0 - -#define RFC1533_VENDOR_MAGIC 128 -#define RFC1533_VENDOR_ADDPARM 129 -#define RFC1533_VENDOR_ETHDEV 130 -/* We should really apply for an official Etherboot encap option */ -#define RFC1533_VENDOR_ETHERBOOT_ENCAP 150 -/* I'll leave it to FREEBSD to decide if they want to renumber */ -#ifdef IMAGE_FREEBSD -#define RFC1533_VENDOR_HOWTO 132 -#define RFC1533_VENDOR_KERNEL_ENV 133 -#endif -#define RFC1533_VENDOR_NIC_DEV_ID 175 -#define RFC1533_VENDOR_ARCH 177 - -#define RFC1533_END 255 - -#define BOOTP_VENDOR_LEN 64 -#ifndef NO_DHCP_SUPPORT -#define DHCP_OPT_LEN 312 -#endif /* NO_DHCP_SUPPORT */ - -/* Format of a bootp packet */ -struct bootp_t { - uint8_t bp_op; - uint8_t bp_htype; - uint8_t bp_hlen; - uint8_t bp_hops; - uint32_t bp_xid; - uint16_t bp_secs; - uint16_t unused; - in_addr bp_ciaddr; - in_addr bp_yiaddr; - in_addr bp_siaddr; - in_addr bp_giaddr; - uint8_t bp_hwaddr[16]; - uint8_t bp_sname[64]; - char bp_file[128]; -#ifdef NO_DHCP_SUPPORT - uint8_t bp_vend[BOOTP_VENDOR_LEN]; -#else - uint8_t bp_vend[DHCP_OPT_LEN]; -#endif /* NO_DHCP_SUPPORT */ -}; - -/* Format of a bootp IP packet */ -struct bootpip_t -{ - struct iphdr ip; - struct udphdr udp; - struct bootp_t bp; -}; - -/* Format of bootp packet with extensions */ -struct bootpd_t { - struct bootp_t bootp_reply; - uint8_t bootp_extension[MAX_BOOTP_EXTLEN]; -}; - -#endif /* _BOOTP_H */ diff --git a/roms/ipxe/src/include/compiler.h b/roms/ipxe/src/include/compiler.h index ed9af237d..3f5c913a0 100644 --- a/roms/ipxe/src/include/compiler.h +++ b/roms/ipxe/src/include/compiler.h @@ -60,11 +60,15 @@ /** Provide a symbol within this object file */ #ifdef ASSEMBLY #define PROVIDE_SYMBOL( _sym ) \ + .section ".provided", "a", @nobits ; \ + .hidden _sym ; \ .globl _sym ; \ - .comm _sym, 0 + _sym: ; \ + .previous #else /* ASSEMBLY */ #define PROVIDE_SYMBOL( _sym ) \ - char _sym[0] + char _sym[0] \ + __attribute__ (( section ( ".provided" ) )) #endif /* ASSEMBLY */ /** Require a symbol within this object file @@ -246,16 +250,9 @@ REQUEST_EXPANDED ( CONFIG_SYMBOL ); * */ -/* - * If debug_OBJECT is set to a true value, the macro DBG(...) will - * expand to printf(...) when compiling OBJECT, and the symbol - * DEBUG_LEVEL will be inserted into the object file. - * - */ -#define DEBUG_SYMBOL PREFIX_OBJECT ( debug_ ) - -#if DEBUG_SYMBOL == 0 +#ifndef DBGLVL_MAX #define NDEBUG +#define DBGLVL_MAX 0 #endif #ifndef ASSEMBLY @@ -272,12 +269,6 @@ extern void dbg_md5_da ( unsigned long dispaddr, extern void dbg_pause ( void ); extern void dbg_more ( void ); -#if DEBUG_SYMBOL -#define DBGLVL_MAX DEBUG_SYMBOL -#else -#define DBGLVL_MAX 0 -#endif - /* Allow for selective disabling of enabled debug levels */ #if DBGLVL_MAX int __debug_disable; @@ -651,7 +642,7 @@ int __debug_disable; * be in the public domain. */ #define FILE_LICENCE_PUBLIC_DOMAIN \ - PROVIDE_SYMBOL ( __licence_public_domain ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__public_domain__ ) ) /** Declare a file as being under version 2 (or later) of the GNU GPL * @@ -660,7 +651,7 @@ int __debug_disable; * (at your option) any later version". */ #define FILE_LICENCE_GPL2_OR_LATER \ - PROVIDE_SYMBOL ( __licence_gpl2_or_later ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl2_or_later__ ) ) /** Declare a file as being under version 2 of the GNU GPL * @@ -669,7 +660,7 @@ int __debug_disable; * "or, at your option, any later version" clause. */ #define FILE_LICENCE_GPL2_ONLY \ - PROVIDE_SYMBOL ( __licence_gpl2_only ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl2_only__ ) ) /** Declare a file as being under any version of the GNU GPL * @@ -681,7 +672,7 @@ int __debug_disable; * version ever published by the Free Software Foundation". */ #define FILE_LICENCE_GPL_ANY \ - PROVIDE_SYMBOL ( __licence_gpl_any ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__gpl_any__ ) ) /** Declare a file as being under the three-clause BSD licence * @@ -706,7 +697,7 @@ int __debug_disable; * functionally equivalent to the standard three-clause BSD licence. */ #define FILE_LICENCE_BSD3 \ - PROVIDE_SYMBOL ( __licence_bsd3 ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd3__ ) ) /** Declare a file as being under the two-clause BSD licence * @@ -727,7 +718,7 @@ int __debug_disable; * functionally equivalent to the standard two-clause BSD licence. */ #define FILE_LICENCE_BSD2 \ - PROVIDE_SYMBOL ( __licence_bsd2 ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__bsd2__ ) ) /** Declare a file as being under the one-clause MIT-style licence * @@ -737,7 +728,7 @@ int __debug_disable; * permission notice appear in all copies. */ #define FILE_LICENCE_MIT \ - PROVIDE_SYMBOL ( __licence_mit ) + PROVIDE_SYMBOL ( PREFIX_OBJECT ( __licence__mit__ ) ) /** Declare a particular licence as applying to a file */ #define FILE_LICENCE( _licence ) FILE_LICENCE_ ## _licence diff --git a/roms/ipxe/src/include/ctype.h b/roms/ipxe/src/include/ctype.h index 9f5127bf1..e92ecb1c0 100644 --- a/roms/ipxe/src/include/ctype.h +++ b/roms/ipxe/src/include/ctype.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define islower(c) ((c) >= 'a' && (c) <= 'z') #define isupper(c) ((c) >= 'A' && (c) <= 'Z') #define isxdigit(c) (isdigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) +#define isprint(c) ((c) >= ' ' && (c) <= '~' ) static inline unsigned char tolower(unsigned char c) { diff --git a/roms/ipxe/src/include/curses.h b/roms/ipxe/src/include/curses.h index 206977904..f16f9d7d0 100644 --- a/roms/ipxe/src/include/curses.h +++ b/roms/ipxe/src/include/curses.h @@ -3,6 +3,7 @@ #include <stdint.h> #include <stdarg.h> +#include <ipxe/console.h> /** @file * @@ -38,6 +39,13 @@ typedef struct _curses_screen { void ( *init ) ( struct _curses_screen *scr ); void ( *exit ) ( struct _curses_screen *scr ); /** + * Erase screen + * + * @v scr screen on which to operate + * @v attrs attributes + */ + void ( * erase ) ( struct _curses_screen *scr, attr_t attrs ); + /** * Move cursor to position specified by x,y coords * * @v scr screen on which to operate @@ -68,6 +76,13 @@ typedef struct _curses_screen { * @ret FALSE no character waiting in stream */ bool ( *peek ) ( struct _curses_screen *scr ); + /** + * Set cursor visibility + * + * @v scr screen on which to operate + * @v visibility cursor visibility + */ + void ( * cursor ) ( struct _curses_screen *scr, int visibility ); } SCREEN; /** Curses Window struct */ @@ -91,12 +106,10 @@ typedef struct _curses_window { } WINDOW; extern WINDOW _stdscr; -extern unsigned short _COLS; -extern unsigned short _LINES; #define stdscr ( &_stdscr ) -#define COLS _COLS -#define LINES _LINES +#define COLS console_width +#define LINES console_height #define MUCURSES_BITS( mask, shift ) (( mask ) << (shift)) #define CPAIR_SHIFT 8 @@ -242,7 +255,7 @@ extern int echo ( void ); extern int echochar ( const chtype ); extern int endwin ( void ); extern char erasechar ( void ); -//extern int erase ( void ); +extern int erase ( void ); extern void filter ( void ); extern int flash ( void ); extern int flushinp ( void ); @@ -552,10 +565,6 @@ static inline int deleteln ( void ) { return wdeleteln( stdscr ); } -static inline int erase ( void ) { - return werase ( stdscr ); -} - static inline int getch ( void ) { return wgetch ( stdscr ); } diff --git a/roms/ipxe/src/include/errno.h b/roms/ipxe/src/include/errno.h index bd4ddaf41..bcc4a8816 100644 --- a/roms/ipxe/src/include/errno.h +++ b/roms/ipxe/src/include/errno.h @@ -30,16 +30,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); * maximum visibility into the source of an error even in an end-user * build with no debugging. They are constructed as follows: * - * Bits 7-0 : PXE error code + * Bits 7-0 : Platform-specific error code * - * This is the closest equivalent PXE error code - * (e.g. PXENV_STATUS_OUT_OF_RESOURCES), and is the only part of the - * error that will be returned via the PXE API, since PXE has - * predefined error codes. + * This is a losslessly compressed representation of the closest + * equivalent error code defined by the platform (e.g. BIOS/PXE or + * EFI). It is used to generate errors to be returned to external + * code. * * Bits 12-8 : Per-file disambiguator * - * When the same error number can be generated from multiple points + * When the same error code can be generated from multiple points * within a file, this field can be used to identify the unique * instance. * @@ -54,7 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * Bit 31 : Reserved * - * Errors are usually return as negative error numbers (e.g. -EINVAL); + * Errors are usually return as negative error codes (e.g. -EINVAL); * bit 31 is therefore unusable. * * @@ -63,9 +63,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * return -EINVAL; * - * By various bits of preprocessor magic, the PXE error code and file - * identifier are already incorporated into the definition of the - * POSIX error macro, which keeps the code relatively clean. + * By various bits of preprocessor magic, the platform-specific error + * code and file identifier are already incorporated into the + * definition of the POSIX error macro, which keeps the code + * relatively clean. * * * Functions that wish to return failures should be declared as @@ -99,6 +100,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Get definitions for platform-specific error codes */ +#define PLATFORM_ERRNO(_platform) <ipxe/errno/_platform.h> +#include PLATFORM_ERRNO(PLATFORM) + /* Get definitions for file identifiers */ #include <ipxe/errfile.h> @@ -110,37 +115,37 @@ FILE_LICENCE ( GPL2_OR_LATER ); #if ! ERRFILE extern char missing_errfile_declaration[] __attribute__ (( deprecated )); #undef ERRFILE -#define ERRFILE ( 0 * ( ( int ) missing_errfile_declaration ) ) +#define ERRFILE ( ( int ) ( 0 * ( ( intptr_t ) missing_errfile_declaration ) ) ) #endif /** * Declare error information * - * @v pxe PXE error number (0x00-0xff) - * @v posix POSIX error number (0x00-0x7f) + * @v platform Platform error code (uncompressed) + * @v posix POSIX error code (0x00-0x7f) * @v uniq Error disambiguator (0x00-0x1f) * @v desc Error description * @ret einfo Error information */ -#define __einfo( pxe, posix, uniq, desc ) ( pxe, posix, uniq, desc ) +#define __einfo( platform, posix, uniq, desc ) ( platform, posix, uniq, desc ) /** - * Get PXE error number + * Get platform error code * * @v einfo Error information - * @ret pxe PXE error number + * @ret platform Platform error code (uncompressed) */ -#define __einfo_pxe( einfo ) __einfo_extract_pxe einfo -#define __einfo_extract_pxe( pxe, posix, uniq, desc ) pxe +#define __einfo_platform( einfo ) __einfo_extract_platform einfo +#define __einfo_extract_platform( platform, posix, uniq, desc ) platform /** - * Get POSIX error number + * Get POSIX error code * * @v einfo Error information - * @ret posix POSIX error number + * @ret posix POSIX error code */ #define __einfo_posix( einfo ) __einfo_extract_posix einfo -#define __einfo_extract_posix( pxe, posix, uniq, desc ) posix +#define __einfo_extract_posix( platform, posix, uniq, desc ) posix /** * Get error disambiguator @@ -149,7 +154,7 @@ extern char missing_errfile_declaration[] __attribute__ (( deprecated )); * @ret uniq Error disambiguator */ #define __einfo_uniq( einfo ) __einfo_extract_uniq einfo -#define __einfo_extract_uniq( pxe, posix, uniq, desc ) uniq +#define __einfo_extract_uniq( platform, posix, uniq, desc ) uniq /** * Get error description @@ -158,37 +163,50 @@ extern char missing_errfile_declaration[] __attribute__ (( deprecated )); * @ret desc Error description */ #define __einfo_desc( einfo ) __einfo_extract_desc einfo -#define __einfo_extract_desc( pxe, posix, uniq, desc ) desc +#define __einfo_extract_desc( platform, posix, uniq, desc ) desc /** * Declare disambiguated error * * @v einfo_base Base error information - * @v uniq Error disambiguator + * @v uniq Error disambiguator (0x00-0x1f) * @v desc Error description * @ret einfo Error information */ #define __einfo_uniqify( einfo_base, uniq, desc ) \ - __einfo ( __einfo_pxe ( einfo_base ), \ + __einfo ( __einfo_platform ( einfo_base ), \ __einfo_posix ( einfo_base ), \ uniq, desc ) /** - * Get error number + * Declare platform-generated error + * + * @v einfo_base Base error information + * @v platform Platform error code (uncompressed) + * @v desc Error description + * @ret einfo Error information + */ +#define __einfo_platformify( einfo_base, platform, desc ) \ + __einfo ( platform, __einfo_posix ( einfo_base ), \ + __einfo_uniq ( einfo_base ), desc ) + +/** + * Get error code * * @v einfo Error information - * @ret errno Error number + * @ret errno Error code */ #define __einfo_errno( einfo ) \ - ( ( __einfo_posix ( einfo ) << 24 ) | ( ERRFILE ) | \ - ( __einfo_uniq ( einfo ) << 8 ) | \ - ( __einfo_pxe ( einfo ) << 0 ) ) + ( ( int ) \ + ( ( __einfo_posix ( einfo ) << 24 ) | ( ERRFILE ) | \ + ( __einfo_uniq ( einfo ) << 8 ) | \ + ( PLATFORM_TO_ERRNO ( __einfo_platform ( einfo ) ) << 0 ) ) ) /** * Disambiguate a base error based on non-constant information * - * @v error_base Base error - * @v uniq Error disambiguator + * @v einfo_base Base error information + * @v uniq Error disambiguator (0x00-0x1f) * @v ... List of expected possible disambiguated errors * @ret error Error * @@ -200,12 +218,36 @@ extern char missing_errfile_declaration[] __attribute__ (( deprecated )); * EUNIQ() should not be used for constant error disambiguators; use * __einfo_uniqify() instead. */ -#define EUNIQ( errno, uniq, ... ) ( { \ - euniq_discard ( 0, ##__VA_ARGS__); \ - ( ( int ) ( (errno) | ( (uniq) << 8 ) ) ); } ) +#define EUNIQ( einfo_base, uniq, ... ) ( { \ + euniq_discard ( 0, ##__VA_ARGS__ ); \ + ( ( int ) ( __einfo_error ( einfo_base ) | \ + ( (uniq) << 8 ) ) ); } ) static inline void euniq_discard ( int dummy __unused, ... ) {} /** + * Generate an error based on an external platform error code + * + * @v einfo_base Base error information + * @v platform Platform error code (uncompressed) + * @v ... List of expected possible platform-generated errors + * @ret error Error + * + * EPLATFORM() should be used when a platform error code resulting + * from an external platform API call is being incorporated into an + * error. For example, EFI code uses EPLATFORM() to generate errors + * resulting from calls to EFI APIs such as + * InstallMultipleProtocolInterfaces(). + * + * EPLATFORM() should not be used for constant platform-generated + * errors; use __einfo_platformify() instead. + */ +#define EPLATFORM( einfo_base, platform, ... ) ( { \ + eplatform_discard ( 0, ##__VA_ARGS__ ); \ + ( ( int ) ( __einfo_error ( einfo_base ) | \ + PLATFORM_TO_ERRNO ( platform ) ) ); } ) +static inline void eplatform_discard ( int dummy __unused, ... ) {} + +/** * Declare error * * @v einfo Error information @@ -225,125 +267,11 @@ static inline void euniq_discard ( int dummy __unused, ... ) {} ".align 8\n\t" \ "\n4:\n\t" \ ".previous\n\t" : : \ - "i" ( __einfo_errno ( einfo) ), \ + "i" ( __einfo_errno ( einfo ) ), \ "i" ( __LINE__ ) ); \ __einfo_errno ( einfo ); } ) /** - * @defgroup pxeerrors PXE error codes - * - * The names, meanings and values of these error codes are defined by - * the PXE specification. - * - * @{ - */ - -/* Generic errors */ -#define PXENV_STATUS_SUCCESS 0x0000 -#define PXENV_STATUS_FAILURE 0x0001 -#define PXENV_STATUS_BAD_FUNC 0x0002 -#define PXENV_STATUS_UNSUPPORTED 0x0003 -#define PXENV_STATUS_KEEP_UNDI 0x0004 -#define PXENV_STATUS_KEEP_ALL 0x0005 -#define PXENV_STATUS_OUT_OF_RESOURCES 0x0006 - -/* ARP errors (0x0010 to 0x001f) */ -#define PXENV_STATUS_ARP_TIMEOUT 0x0011 - -/* Base-Code state errors */ -#define PXENV_STATUS_UDP_CLOSED 0x0018 -#define PXENV_STATUS_UDP_OPEN 0x0019 -#define PXENV_STATUS_TFTP_CLOSED 0x001a -#define PXENV_STATUS_TFTP_OPEN 0x001b - -/* BIOS/system errors (0x0020 to 0x002f) */ -#define PXENV_STATUS_MCOPY_PROBLEM 0x0020 -#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x0021 -#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x0022 -#define PXENV_STATUS_BIS_INIT_FAILURE 0x0023 -#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x0024 -#define PXENV_STATUS_BIS_GBOA_FAILURE 0x0025 -#define PXENV_STATUS_BIS_FREE_FAILURE 0x0026 -#define PXENV_STATUS_BIS_GSI_FAILURE 0x0027 -#define PXENV_STATUS_BIS_BAD_CKSUM 0x0028 - -/* TFTP/MTFTP errors (0x0030 to 0x003f) */ -#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x0030 -#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x0032 -#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x0033 -#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x0035 -#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x0036 -#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x0038 -#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x0039 -#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x003a -#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x003b -#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x003c -#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x003d -#define PXENV_STATUS_TFTP_NO_FILESIZE 0x003e -#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x003f - -/* Reserved errors 0x0040 to 0x004f) */ - -/* DHCP/BOOTP errors (0x0050 to 0x005f) */ -#define PXENV_STATUS_DHCP_TIMEOUT 0x0051 -#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x0052 -#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x0053 -#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x0054 - -/* Driver errors (0x0060 to 0x006f) */ -#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x0060 -#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x0061 -#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x0062 -#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x0063 -#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x0064 -#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x0065 -#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x0066 -#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x0067 -#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x0068 -#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x0069 -#define PXENV_STATUS_UNDI_INVALID_STATE 0x006a -#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x006b -#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x006c - -/* ROM and NBP bootstrap errors (0x0070 to 0x007f) */ -#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x0074 -#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x0076 -#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x0077 -#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x0078 -#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x0079 - -/* Environment NBP errors (0x0080 to 0x008f) */ - -/* Reserved errors (0x0090 to 0x009f) */ - -/* Miscellaneous errors (0x00a0 to 0x00af) */ -#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0x00a0 -#define PXENV_STATUS_BINL_NO_PXE_SERVER 0x00a1 -#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0x00a2 -#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0x00a3 - -/* BUSD errors (0x00b0 to 0x00bf) */ -#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0x00b0 - -/* Loader errors (0x00c0 to 0x00cf) */ -#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0x00c0 -#define PXENV_STATUS_LOADER_NO_BC_ROMID 0x00c1 -#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0x00c2 -#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0x00c3 -#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0x00c4 -#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0x00c5 -#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0x00c6 -#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0x00c8 -#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0x00c9 -#define PXENV_STATUS_LOADER_UNDI_START 0x00ca -#define PXENV_STATUS_LOADER_BC_START 0x00cb - -/** @} */ - -/** Derive PXENV_STATUS code from iPXE error number */ -#define PXENV_STATUS( rc ) ( (-(rc)) & 0x00ff ) - -/** * @defgroup posixerrors POSIX error codes * * The names and meanings (but not the values) of these error codes @@ -354,409 +282,410 @@ static inline void euniq_discard ( int dummy __unused, ... ) {} /** Operation completed successfully */ #define ENOERR __einfo_error ( EINFO_ENOERR ) -#define EINFO_ENOERR __einfo ( PXENV_STATUS_SUCCESS, 0x00, 0, \ +#define EINFO_ENOERR __einfo ( PLATFORM_ENOERR, 0x00, 0, \ "Operation completed successfully" ) /** Argument list too long */ #define E2BIG __einfo_error ( EINFO_E2BIG ) -#define EINFO_E2BIG __einfo ( PXENV_STATUS_BAD_FUNC, 0x01, 0, \ +#define EINFO_E2BIG __einfo ( PLATFORM_E2BIG, 0x01, 0, \ "Argument list too long" ) /** Permission denied */ #define EACCES __einfo_error ( EINFO_EACCES ) -#define EINFO_EACCES __einfo ( PXENV_STATUS_TFTP_ACCESS_VIOLATION, 0x02, 0, \ +#define EINFO_EACCES __einfo ( PLATFORM_EACCES, 0x02, 0, \ "Permission denied" ) /** Address already in use */ #define EADDRINUSE __einfo_error ( EINFO_EADDRINUSE ) -#define EINFO_EADDRINUSE __einfo ( PXENV_STATUS_UDP_OPEN, 0x03, 0, \ +#define EINFO_EADDRINUSE __einfo ( PLATFORM_EADDRINUSE, 0x03, 0, \ "Address already in use" ) /** Address not available */ #define EADDRNOTAVAIL __einfo_error ( EINFO_EADDRNOTAVAIL ) -#define EINFO_EADDRNOTAVAIL __einfo ( PXENV_STATUS_UDP_OPEN, 0x04, 0, \ +#define EINFO_EADDRNOTAVAIL __einfo ( PLATFORM_EADDRNOTAVAIL, 0x04, 0, \ "Address not available" ) /** Address family not supported */ #define EAFNOSUPPORT __einfo_error ( EINFO_EAFNOSUPPORT ) -#define EINFO_EAFNOSUPPORT __einfo ( PXENV_STATUS_UNSUPPORTED, 0x05, 0, \ +#define EINFO_EAFNOSUPPORT __einfo ( PLATFORM_EAFNOSUPPORT, 0x05, 0, \ "Address family not supported" ) /** Resource temporarily unavailable */ #define EAGAIN __einfo_error ( EINFO_EAGAIN ) -#define EINFO_EAGAIN __einfo ( PXENV_STATUS_FAILURE, 0x06, 0, \ +#define EINFO_EAGAIN __einfo ( PLATFORM_EAGAIN, 0x06, 0, \ "Resource temporarily unavailable" ) /** Connection already in progress */ #define EALREADY __einfo_error ( EINFO_EALREADY ) -#define EINFO_EALREADY __einfo ( PXENV_STATUS_UDP_OPEN, 0x07, 0, \ +#define EINFO_EALREADY __einfo ( PLATFORM_EALREADY, 0x07, 0, \ "Connection already in progress" ) /** Bad file descriptor */ #define EBADF __einfo_error ( EINFO_EBADF ) -#define EINFO_EBADF __einfo ( PXENV_STATUS_TFTP_CLOSED, 0x08, 0, \ +#define EINFO_EBADF __einfo ( PLATFORM_EBADF, 0x08, 0, \ "Bad file descriptor" ) /** Bad message */ #define EBADMSG __einfo_error ( EINFO_EBADMSG ) -#define EINFO_EBADMSG __einfo ( PXENV_STATUS_FAILURE, 0x09, 0, \ +#define EINFO_EBADMSG __einfo ( PLATFORM_EBADMSG, 0x09, 0, \ "Bad message" ) /** Device or resource busy */ #define EBUSY __einfo_error ( EINFO_EBUSY ) -#define EINFO_EBUSY __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x0a, 0, \ +#define EINFO_EBUSY __einfo ( PLATFORM_EBUSY, 0x0a, 0, \ "Device or resource busy" ) /** Operation canceled */ #define ECANCELED __einfo_error ( EINFO_ECANCELED ) -#define EINFO_ECANCELED __einfo ( PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE, \ - 0x0b, 0, "Operation canceled" ) +#define EINFO_ECANCELED __einfo ( PLATFORM_ECANCELED, 0x0b, 0, \ + "Operation canceled" ) /** No child processes */ #define ECHILD __einfo_error ( EINFO_ECHILD ) -#define EINFO_ECHILD __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x0c, 0, \ +#define EINFO_ECHILD __einfo ( PLATFORM_ECHILD, 0x0c, 0, \ "No child processes" ) /** Connection aborted */ #define ECONNABORTED __einfo_error ( EINFO_ECONNABORTED ) -#define EINFO_ECONNABORTED \ - __einfo ( PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, 0x0d, 0, \ - "Connection aborted" ) +#define EINFO_ECONNABORTED __einfo ( PLATFORM_ECONNABORTED, 0x0d, 0, \ + "Connection aborted" ) /** Connection refused */ #define ECONNREFUSED __einfo_error ( EINFO_ECONNREFUSED ) -#define EINFO_ECONNREFUSED __einfo ( PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION, \ - 0x0e, 0, "Connection refused" ) +#define EINFO_ECONNREFUSED __einfo ( PLATFORM_ECONNREFUSED, 0x0e, 0, \ + "Connection refused" ) /** Connection reset */ #define ECONNRESET __einfo_error ( EINFO_ECONNRESET ) -#define EINFO_ECONNRESET \ - __einfo ( PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, 0x0f, 0, \ - "Connection reset" ) +#define EINFO_ECONNRESET __einfo ( PLATFORM_ECONNRESET, 0x0f, 0, \ + "Connection reset" ) /** Resource deadlock avoided */ #define EDEADLK __einfo_error ( EINFO_EDEADLK ) -#define EINFO_EDEADLK __einfo ( PXENV_STATUS_FAILURE, 0x10, 0, \ +#define EINFO_EDEADLK __einfo ( PLATFORM_EDEADLK, 0x10, 0, \ "Resource deadlock avoided" ) /** Destination address required */ #define EDESTADDRREQ __einfo_error ( EINFO_EDESTADDRREQ ) -#define EINFO_EDESTADDRREQ __einfo ( PXENV_STATUS_BAD_FUNC, 0x11, 0, \ +#define EINFO_EDESTADDRREQ __einfo ( PLATFORM_EDESTADDRREQ, 0x11, 0, \ "Destination address required" ) /** Mathematics argument out of domain of function */ #define EDOM __einfo_error ( EINFO_EDOM ) -#define EINFO_EDOM __einfo ( PXENV_STATUS_FAILURE, 0x12, 0, \ +#define EINFO_EDOM __einfo ( PLATFORM_EDOM, 0x12, 0, \ "Mathematics argument out of domain of function" ) /** Disk quota exceeded */ #define EDQUOT __einfo_error ( EINFO_EDQUOT ) -#define EINFO_EDQUOT __einfo ( PXENV_STATUS_FAILURE, 0x13, 0, \ +#define EINFO_EDQUOT __einfo ( PLATFORM_EDQUOT, 0x13, 0, \ "Disk quote exceeded" ) /** File exists */ #define EEXIST __einfo_error ( EINFO_EEXIST ) -#define EINFO_EEXIST __einfo ( PXENV_STATUS_FAILURE, 0x14, 0, \ +#define EINFO_EEXIST __einfo ( PLATFORM_EEXIST, 0x14, 0, \ "File exists" ) /** Bad address */ #define EFAULT __einfo_error ( EINFO_EFAULT ) -#define EINFO_EFAULT __einfo ( PXENV_STATUS_MCOPY_PROBLEM, 0x15, 0, \ +#define EINFO_EFAULT __einfo ( PLATFORM_EFAULT, 0x15, 0, \ "Bad address" ) /** File too large */ #define EFBIG __einfo_error ( EINFO_EFBIG ) -#define EINFO_EFBIG __einfo ( PXENV_STATUS_MCOPY_PROBLEM, 0x16, 0, \ +#define EINFO_EFBIG __einfo ( PLATFORM_EFBIG, 0x16, 0, \ "File too large" ) /** Host is unreachable */ #define EHOSTUNREACH __einfo_error ( EINFO_EHOSTUNREACH ) -#define EINFO_EHOSTUNREACH __einfo ( PXENV_STATUS_ARP_TIMEOUT, 0x17, 0, \ +#define EINFO_EHOSTUNREACH __einfo ( PLATFORM_EHOSTUNREACH, 0x17, 0, \ "Host is unreachable" ) /** Identifier removed */ #define EIDRM __einfo_error ( EINFO_EIDRM ) -#define EINFO_EIDRM __einfo ( PXENV_STATUS_FAILURE, 0x18, 0, \ +#define EINFO_EIDRM __einfo ( PLATFORM_EIDRM, 0x18, 0, \ "Identifier removed" ) /** Illegal byte sequence */ #define EILSEQ __einfo_error ( EINFO_EILSEQ ) -#define EINFO_EILSEQ __einfo ( PXENV_STATUS_FAILURE, 0x19, 0, \ +#define EINFO_EILSEQ __einfo ( PLATFORM_EILSEQ, 0x19, 0, \ "Illegal byte sequence" ) /** Operation in progress */ #define EINPROGRESS __einfo_error ( EINFO_EINPROGRESS ) -#define EINFO_EINPROGRESS __einfo ( PXENV_STATUS_FAILURE, 0x1a, 0, \ +#define EINFO_EINPROGRESS __einfo ( PLATFORM_EINPROGRESS, 0x1a, 0, \ "Operation in progress" ) /** Interrupted function call */ #define EINTR __einfo_error ( EINFO_EINTR ) -#define EINFO_EINTR __einfo ( PXENV_STATUS_FAILURE, 0x1b, 0, \ +#define EINFO_EINTR __einfo ( PLATFORM_EINTR, 0x1b, 0, \ "Interrupted function call" ) /** Invalid argument */ #define EINVAL __einfo_error ( EINFO_EINVAL ) -#define EINFO_EINVAL __einfo ( PXENV_STATUS_BAD_FUNC, 0x1c, 0, \ +#define EINFO_EINVAL __einfo ( PLATFORM_EINVAL, 0x1c, 0, \ "Invalid argument" ) /** Input/output error */ #define EIO __einfo_error ( EINFO_EIO ) -#define EINFO_EIO __einfo ( PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION, \ - 0x1d, 0, "Input/output error" ) +#define EINFO_EIO __einfo ( PLATFORM_EIO, 0x1d, 0, \ + "Input/output error" ) /** Socket is connected */ #define EISCONN __einfo_error ( EINFO_EISCONN ) -#define EINFO_EISCONN __einfo ( PXENV_STATUS_UDP_OPEN, 0x1e, 0, \ +#define EINFO_EISCONN __einfo ( PLATFORM_EISCONN, 0x1e, 0, \ "Socket is connected" ) /** Is a directory */ #define EISDIR __einfo_error ( EINFO_EISDIR ) -#define EINFO_EISDIR __einfo ( PXENV_STATUS_FAILURE, 0x1f, 0, \ +#define EINFO_EISDIR __einfo ( PLATFORM_EISDIR, 0x1f, 0, \ "Is a directory" ) /** Too many levels of symbolic links */ #define ELOOP __einfo_error ( EINFO_ELOOP ) -#define EINFO_ELOOP __einfo ( PXENV_STATUS_FAILURE, 0x20, 0, \ +#define EINFO_ELOOP __einfo ( PLATFORM_ELOOP, 0x20, 0, \ "Too many levels of symbolic links" ) /** Too many open files */ #define EMFILE __einfo_error ( EINFO_EMFILE ) -#define EINFO_EMFILE __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x21, 0, \ +#define EINFO_EMFILE __einfo ( PLATFORM_EMFILE, 0x21, 0, \ "Too many open files" ) /** Too many links */ #define EMLINK __einfo_error ( EINFO_EMLINK ) -#define EINFO_EMLINK __einfo ( PXENV_STATUS_FAILURE, 0x22, 0, \ +#define EINFO_EMLINK __einfo ( PLATFORM_EMLINK, 0x22, 0, \ "Too many links" ) /** Message too long */ #define EMSGSIZE __einfo_error ( EINFO_EMSGSIZE ) -#define EINFO_EMSGSIZE __einfo ( PXENV_STATUS_BAD_FUNC, 0x23, 0, \ +#define EINFO_EMSGSIZE __einfo ( PLATFORM_EMSGSIZE, 0x23, 0, \ "Message too long" ) /** Multihop attempted */ #define EMULTIHOP __einfo_error ( EINFO_EMULTIHOP ) -#define EINFO_EMULTIHOP __einfo ( PXENV_STATUS_FAILURE, 0x24, 0, \ +#define EINFO_EMULTIHOP __einfo ( PLATFORM_EMULTIHOP, 0x24, 0, \ "Multihop attempted" ) /** Filename too long */ #define ENAMETOOLONG __einfo_error ( EINFO_ENAMETOOLONG ) -#define EINFO_ENAMETOOLONG __einfo ( PXENV_STATUS_FAILURE, 0x25, 0, \ +#define EINFO_ENAMETOOLONG __einfo ( PLATFORM_ENAMETOOLONG, 0x25, 0, \ "Filename too long" ) /** Network is down */ #define ENETDOWN __einfo_error ( EINFO_ENETDOWN ) -#define EINFO_ENETDOWN __einfo ( PXENV_STATUS_ARP_TIMEOUT, 0x26, 0, \ +#define EINFO_ENETDOWN __einfo ( PLATFORM_ENETDOWN, 0x26, 0, \ "Network is down" ) /** Connection aborted by network */ #define ENETRESET __einfo_error ( EINFO_ENETRESET ) -#define EINFO_ENETRESET __einfo ( PXENV_STATUS_FAILURE, 0x27, 0, \ +#define EINFO_ENETRESET __einfo ( PLATFORM_ENETRESET, 0x27, 0, \ "Connection aborted by network" ) /** Network unreachable */ #define ENETUNREACH __einfo_error ( EINFO_ENETUNREACH ) -#define EINFO_ENETUNREACH __einfo ( PXENV_STATUS_ARP_TIMEOUT, 0x28, 0, \ +#define EINFO_ENETUNREACH __einfo ( PLATFORM_ENETUNREACH, 0x28, 0, \ "Network unreachable" ) /** Too many open files in system */ #define ENFILE __einfo_error ( EINFO_ENFILE ) -#define EINFO_ENFILE __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x29, 0, \ +#define EINFO_ENFILE __einfo ( PLATFORM_ENFILE, 0x29, 0, \ "Too many open files in system" ) /** No buffer space available */ #define ENOBUFS __einfo_error ( EINFO_ENOBUFS ) -#define EINFO_ENOBUFS __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x2a, 0, \ +#define EINFO_ENOBUFS __einfo ( PLATFORM_ENOBUFS, 0x2a, 0, \ "No buffer space available" ) /** No message is available on the STREAM head read queue */ #define ENODATA __einfo_error ( EINFO_ENODATA ) -#define EINFO_ENODATA \ - __einfo ( PXENV_STATUS_FAILURE, 0x2b, 0, \ - "No message is available on the STREAM head read queue" ) +#define EINFO_ENODATA __einfo ( PLATFORM_ENODATA, 0x2b, 0, \ + "No message is available on the STREAM " \ + "head read queue" ) /** No such device */ #define ENODEV __einfo_error ( EINFO_ENODEV ) -#define EINFO_ENODEV __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x2c, 0, \ +#define EINFO_ENODEV __einfo ( PLATFORM_ENODEV, 0x2c, 0, \ "No such device" ) /** No such file or directory */ #define ENOENT __einfo_error ( EINFO_ENOENT ) -#define EINFO_ENOENT __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x2d, 0, \ +#define EINFO_ENOENT __einfo ( PLATFORM_ENOENT, 0x2d, 0, \ "No such file or directory" ) /** Exec format error */ #define ENOEXEC __einfo_error ( EINFO_ENOEXEC ) -#define EINFO_ENOEXEC __einfo ( PXENV_STATUS_FAILURE, 0x2e, 0, \ +#define EINFO_ENOEXEC __einfo ( PLATFORM_ENOEXEC, 0x2e, 0, \ "Exec format error" ) /** No locks available */ #define ENOLCK __einfo_error ( EINFO_ENOLCK ) -#define EINFO_ENOLCK __einfo ( PXENV_STATUS_FAILURE, 0x2f, 0, \ +#define EINFO_ENOLCK __einfo ( PLATFORM_ENOLCK, 0x2f, 0, \ "No locks available" ) /** Link has been severed */ #define ENOLINK __einfo_error ( EINFO_ENOLINK ) -#define EINFO_ENOLINK __einfo ( PXENV_STATUS_FAILURE, 0x30, 0, \ +#define EINFO_ENOLINK __einfo ( PLATFORM_ENOLINK, 0x30, 0, \ "Link has been severed" ) /** Not enough space */ #define ENOMEM __einfo_error ( EINFO_ENOMEM ) -#define EINFO_ENOMEM __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x31, 0, \ +#define EINFO_ENOMEM __einfo ( PLATFORM_ENOMEM, 0x31, 0, \ "Not enough space" ) /** No message of the desired type */ #define ENOMSG __einfo_error ( EINFO_ENOMSG ) -#define EINFO_ENOMSG __einfo ( PXENV_STATUS_FAILURE, 0x32, 0, \ +#define EINFO_ENOMSG __einfo ( PLATFORM_ENOMSG, 0x32, 0, \ "No message of the desired type" ) /** Protocol not available */ #define ENOPROTOOPT __einfo_error ( EINFO_ENOPROTOOPT ) -#define EINFO_ENOPROTOOPT __einfo ( PXENV_STATUS_UNSUPPORTED, 0x33, 0, \ +#define EINFO_ENOPROTOOPT __einfo ( PLATFORM_ENOPROTOOPT, 0x33, 0, \ "Protocol not available" ) /** No space left on device */ #define ENOSPC __einfo_error ( EINFO_ENOSPC ) -#define EINFO_ENOSPC __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x34, 0, \ +#define EINFO_ENOSPC __einfo ( PLATFORM_ENOSPC, 0x34, 0, \ "No space left on device" ) /** No STREAM resources */ #define ENOSR __einfo_error ( EINFO_ENOSR ) -#define EINFO_ENOSR __einfo ( PXENV_STATUS_OUT_OF_RESOURCES, 0x35, 0, \ +#define EINFO_ENOSR __einfo ( PLATFORM_ENOSR, 0x35, 0, \ "No STREAM resources" ) /** Not a STREAM */ #define ENOSTR __einfo_error ( EINFO_ENOSTR ) -#define EINFO_ENOSTR __einfo ( PXENV_STATUS_FAILURE, 0x36, 0, \ +#define EINFO_ENOSTR __einfo ( PLATFORM_ENOSTR, 0x36, 0, \ "Not a STREAM" ) /** Function not implemented */ #define ENOSYS __einfo_error ( EINFO_ENOSYS ) -#define EINFO_ENOSYS __einfo ( PXENV_STATUS_UNSUPPORTED, 0x37, 0, \ +#define EINFO_ENOSYS __einfo ( PLATFORM_ENOSYS, 0x37, 0, \ "Function not implemented" ) /** The socket is not connected */ #define ENOTCONN __einfo_error ( EINFO_ENOTCONN ) -#define EINFO_ENOTCONN __einfo ( PXENV_STATUS_FAILURE, 0x38, 0, \ +#define EINFO_ENOTCONN __einfo ( PLATFORM_ENOTCONN, 0x38, 0, \ "The socket is not connected" ) /** Not a directory */ #define ENOTDIR __einfo_error ( EINFO_ENOTDIR ) -#define EINFO_ENOTDIR __einfo ( PXENV_STATUS_FAILURE, 0x39, 0, \ +#define EINFO_ENOTDIR __einfo ( PLATFORM_ENOTDIR, 0x39, 0, \ "Not a directory" ) /** Directory not empty */ #define ENOTEMPTY __einfo_error ( EINFO_ENOTEMPTY ) -#define EINFO_ENOTEMPTY __einfo ( PXENV_STATUS_FAILURE, 0x3a, 0, \ +#define EINFO_ENOTEMPTY __einfo ( PLATFORM_ENOTEMPTY, 0x3a, 0, \ "Directory not empty" ) /** Not a socket */ #define ENOTSOCK __einfo_error ( EINFO_ENOTSOCK ) -#define EINFO_ENOTSOCK __einfo ( PXENV_STATUS_FAILURE, 0x3b, 0, \ +#define EINFO_ENOTSOCK __einfo ( PLATFORM_ENOTSOCK, 0x3b, 0, \ "Not a socket" ) /** Operation not supported */ #define ENOTSUP __einfo_error ( EINFO_ENOTSUP ) -#define EINFO_ENOTSUP __einfo ( PXENV_STATUS_UNSUPPORTED, 0x3c, 0, \ +#define EINFO_ENOTSUP __einfo ( PLATFORM_ENOTSUP, 0x3c, 0, \ "Operation not supported" ) /** Inappropriate I/O control operation */ #define ENOTTY __einfo_error ( EINFO_ENOTTY ) -#define EINFO_ENOTTY __einfo ( PXENV_STATUS_FAILURE, 0x3d, 0, \ +#define EINFO_ENOTTY __einfo ( PLATFORM_ENOTTY, 0x3d, 0, \ "Inappropriate I/O control operation" ) /** No such device or address */ #define ENXIO __einfo_error ( EINFO_ENXIO ) -#define EINFO_ENXIO __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x3e, 0, \ +#define EINFO_ENXIO __einfo ( PLATFORM_ENXIO, 0x3e, 0, \ "No such device or address" ) /** Operation not supported on socket */ #define EOPNOTSUPP __einfo_error ( EINFO_EOPNOTSUPP ) -#define EINFO_EOPNOTSUPP __einfo ( PXENV_STATUS_UNSUPPORTED, 0x3f, 0, \ +#define EINFO_EOPNOTSUPP __einfo ( PLATFORM_EOPNOTSUPP, 0x3f, 0, \ "Operation not supported on socket" ) /** Value too large to be stored in data type */ #define EOVERFLOW __einfo_error ( EINFO_EOVERFLOW ) -#define EINFO_EOVERFLOW __einfo ( PXENV_STATUS_FAILURE, 0x40, 0, \ +#define EINFO_EOVERFLOW __einfo ( PLATFORM_EOVERFLOW, 0x40, 0, \ "Value too large to be stored in data type" ) /** Operation not permitted */ #define EPERM __einfo_error ( EINFO_EPERM ) -#define EINFO_EPERM __einfo ( PXENV_STATUS_TFTP_ACCESS_VIOLATION, 0x41, 0, \ +#define EINFO_EPERM __einfo ( PLATFORM_EPERM, 0x41, 0, \ "Operation not permitted" ) /** Broken pipe */ #define EPIPE __einfo_error ( EINFO_EPIPE ) -#define EINFO_EPIPE __einfo ( PXENV_STATUS_FAILURE, 0x42, 0, \ +#define EINFO_EPIPE __einfo ( PLATFORM_EPIPE, 0x42, 0, \ "Broken pipe" ) /** Protocol error */ #define EPROTO __einfo_error ( EINFO_EPROTO ) -#define EINFO_EPROTO __einfo ( PXENV_STATUS_FAILURE, 0x43, 0, \ +#define EINFO_EPROTO __einfo ( PLATFORM_EPROTO, 0x43, 0, \ "Protocol error" ) /** Protocol not supported */ #define EPROTONOSUPPORT __einfo_error ( EINFO_EPROTONOSUPPORT ) -#define EINFO_EPROTONOSUPPORT __einfo ( PXENV_STATUS_UNSUPPORTED, 0x44, 0, \ +#define EINFO_EPROTONOSUPPORT __einfo ( PLATFORM_EPROTONOSUPPORT, 0x44, 0, \ "Protocol not supported" ) /** Protocol wrong type for socket */ #define EPROTOTYPE __einfo_error ( EINFO_EPROTOTYPE ) -#define EINFO_EPROTOTYPE __einfo ( PXENV_STATUS_FAILURE, 0x45, 0, \ +#define EINFO_EPROTOTYPE __einfo ( PLATFORM_EPROTOTYPE, 0x45, 0, \ "Protocol wrong type for socket" ) /** Result too large */ #define ERANGE __einfo_error ( EINFO_ERANGE ) -#define EINFO_ERANGE __einfo ( PXENV_STATUS_FAILURE, 0x46, 0, \ +#define EINFO_ERANGE __einfo ( PLATFORM_ERANGE, 0x46, 0, \ "Result too large" ) /** Read-only file system */ #define EROFS __einfo_error ( EINFO_EROFS ) -#define EINFO_EROFS __einfo ( PXENV_STATUS_FAILURE, 0x47, 0, \ +#define EINFO_EROFS __einfo ( PLATFORM_EROFS, 0x47, 0, \ "Read-only file system" ) /** Invalid seek */ #define ESPIPE __einfo_error ( EINFO_ESPIPE ) -#define EINFO_ESPIPE __einfo ( PXENV_STATUS_FAILURE, 0x48, 0, \ +#define EINFO_ESPIPE __einfo ( PLATFORM_ESPIPE, 0x48, 0, \ "Invalid seek" ) /** No such process */ #define ESRCH __einfo_error ( EINFO_ESRCH ) -#define EINFO_ESRCH __einfo ( PXENV_STATUS_TFTP_FILE_NOT_FOUND, 0x49, 0, \ +#define EINFO_ESRCH __einfo ( PLATFORM_ESRCH, 0x49, 0, \ "No such process" ) /** Stale file handle */ #define ESTALE __einfo_error ( EINFO_ESTALE ) -#define EINFO_ESTALE __einfo ( PXENV_STATUS_FAILURE, 0x4a, 0, \ +#define EINFO_ESTALE __einfo ( PLATFORM_ESTALE, 0x4a, 0, \ "Stale file handle" ) /** Timer expired */ #define ETIME __einfo_error ( EINFO_ETIME ) -#define EINFO_ETIME __einfo ( PXENV_STATUS_FAILURE, 0x4b, 0, \ +#define EINFO_ETIME __einfo ( PLATFORM_ETIME, 0x4b, 0, \ "Timer expired" ) /** Connection timed out */ #define ETIMEDOUT __einfo_error ( EINFO_ETIMEDOUT ) -#define EINFO_ETIMEDOUT __einfo ( PXENV_STATUS_TFTP_READ_TIMEOUT, 0x4c, 0, \ +#define EINFO_ETIMEDOUT __einfo ( PLATFORM_ETIMEDOUT, 0x4c, 0, \ "Connection timed out" ) /** Text file busy */ #define ETXTBSY __einfo_error ( EINFO_ETXTBSY ) -#define EINFO_ETXTBSY __einfo ( PXENV_STATUS_FAILURE, 0x4d, 0, \ +#define EINFO_ETXTBSY __einfo ( PLATFORM_ETXTBSY, 0x4d, 0, \ "Text file busy" ) /** Operation would block */ #define EWOULDBLOCK __einfo_error ( EINFO_EWOULDBLOCK ) -#define EINFO_EWOULDBLOCK __einfo ( PXENV_STATUS_TFTP_OPEN, 0x4e, 0, \ +#define EINFO_EWOULDBLOCK __einfo ( PLATFORM_EWOULDBLOCK, 0x4e, 0, \ "Operation would block" ) /** Improper link */ #define EXDEV __einfo_error ( EINFO_EXDEV ) -#define EINFO_EXDEV __einfo ( PXENV_STATUS_FAILURE, 0x4f, 0, \ +#define EINFO_EXDEV __einfo ( PLATFORM_EXDEV, 0x4f, 0, \ "Improper link" ) /** @} */ +/** Platform-generated base error */ +#define EINFO_EPLATFORM __einfo ( 0, 0x7f, 0, "Platform-generated error" ) + extern int errno; #endif /* ERRNO_H */ diff --git a/roms/ipxe/src/include/hci/ifmgmt_cmd.h b/roms/ipxe/src/include/hci/ifmgmt_cmd.h index abdb27f43..913b911d8 100644 --- a/roms/ipxe/src/include/hci/ifmgmt_cmd.h +++ b/roms/ipxe/src/include/hci/ifmgmt_cmd.h @@ -26,13 +26,47 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct net_device; -struct ifcommon_options {}; +/** An "if<xxx>" command descriptor */ +struct ifcommon_command_descriptor { + /** Command descriptor */ + struct command_descriptor cmd; + /** Payload + * + * @v netdev Network device + * @v opts Command options + * @ret rc Return status code + */ + int ( * payload ) ( struct net_device *netdev, void *opts ); + /** Stop on first success */ + int stop_on_first_success; +}; -extern struct option_descriptor ifcommon_opts[0]; +/** + * Construct "if<xxx>" command descriptor + * + * @v _struct Options structure type + * @v _options Option descriptor array + * @v _check_args Remaining argument checker + * @v _usage Command usage + * @ret _command Command descriptor + */ +#define IFCOMMON_COMMAND_DESC( _struct, _options, _min_args, \ + _max_args, _usage, _payload, \ + _stop_on_first_success ) \ + { \ + .cmd = COMMAND_DESC ( _struct, _options, _min_args, \ + _max_args, _usage ), \ + .payload = ( ( int ( * ) ( struct net_device *netdev, \ + void *opts ) ) \ + ( ( ( ( int ( * ) ( struct net_device *, \ + _struct * ) ) NULL ) \ + == ( typeof ( _payload ) * ) NULL ) \ + ? _payload : _payload ) ), \ + .stop_on_first_success = _stop_on_first_success, \ + } extern int ifcommon_exec ( int argc, char **argv, - struct command_descriptor *cmd, - int ( * payload ) ( struct net_device * ), - int stop_on_first_success ); + struct ifcommon_command_descriptor *cmd ); +extern int ifconf_exec ( int argc, char **argv ); #endif /* _IFMGMT_CMD_H */ diff --git a/roms/ipxe/src/include/ipxe/ansicol.h b/roms/ipxe/src/include/ipxe/ansicol.h new file mode 100644 index 000000000..707d1599d --- /dev/null +++ b/roms/ipxe/src/include/ipxe/ansicol.h @@ -0,0 +1,84 @@ +#ifndef _IPXE_ANSICOL_H +#define _IPXE_ANSICOL_H + +/** @file + * + * ANSI colours + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <curses.h> /* For COLOR_RED etc. */ + +/** Default colour (usually white foreground, black background) */ +#define COLOUR_DEFAULT 9 +#define COLOR_DEFAULT COLOUR_DEFAULT + +/** Magic colour + * + * The magic basic colour is automatically remapped to the colour + * stored in @c ansicol_magic. This is used to allow the UI + * background to automatically become transparent when a background + * picture is used. + */ +#define ANSICOL_MAGIC 15 + +/** RGB value for "not defined" */ +#define ANSICOL_NO_RGB 0x01000000 + +/** + * @defgroup ansicolpairs ANSI colour pairs + * @{ + */ + +/** Default colour pair */ +#define CPAIR_DEFAULT 0 + +/** Normal text */ +#define CPAIR_NORMAL 1 + +/** Highlighted text */ +#define CPAIR_SELECT 2 + +/** Unselectable text (e.g. continuation ellipses, menu separators) */ +#define CPAIR_SEPARATOR 3 + +/** Editable text */ +#define CPAIR_EDIT 4 + +/** Error text */ +#define CPAIR_ALERT 5 + +/** URL text */ +#define CPAIR_URL 6 + +/** PXE selected menu entry */ +#define CPAIR_PXE 7 + +/** @} */ + +/** An ANSI colour pair definition */ +struct ansicol_pair { + /** Foreground colour index */ + uint8_t foreground; + /** Background colour index */ + uint8_t background; +} __attribute__ (( packed )); + +/* ansicol.c */ +extern void ansicol_set_pair ( unsigned int cpair ); +extern int ansicol_define_pair ( unsigned int cpair, unsigned int foreground, + unsigned int background ); + +/* ansicoldef.c */ +extern int ansicol_define ( unsigned int colour, unsigned int ansi, + uint32_t rgb ); +extern void ansicol_reset_magic ( void ); +extern void ansicol_set_magic_transparent ( void ); + +/* Function provided by ansicol.c but overridden by ansicoldef.c, if present */ +extern void ansicol_set ( unsigned int colour, unsigned int which ); + +#endif /* _IPXE_ANSICOL_H */ diff --git a/roms/ipxe/src/include/ipxe/ansiesc.h b/roms/ipxe/src/include/ipxe/ansiesc.h index c00af258a..c1c74481d 100644 --- a/roms/ipxe/src/include/ipxe/ansiesc.h +++ b/roms/ipxe/src/include/ipxe/ansiesc.h @@ -28,6 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); +struct ansiesc_context; + /** A handler for an escape sequence */ struct ansiesc_handler { /** The control function identifier @@ -42,6 +44,7 @@ struct ansiesc_handler { unsigned int function; /** Handle escape sequence * + * @v ctx ANSI escape context * @v count Parameter count * @v params Parameter list * @@ -54,11 +57,12 @@ struct ansiesc_handler { * omitted". Consequently, the parameter list will always * contain at least one item. */ - void ( * handle ) ( unsigned int count, int params[] ); + void ( * handle ) ( struct ansiesc_context *ctx, unsigned int count, + int params[] ); }; /** Maximum number of parameters within a single escape sequence */ -#define ANSIESC_MAX_PARAMS 4 +#define ANSIESC_MAX_PARAMS 5 /** * ANSI escape sequence context @@ -120,6 +124,12 @@ struct ansiesc_context { */ #define ANSIESC_LOG_PRIORITY 'p' +/** Show cursor */ +#define ANSIESC_DECTCEM_SET ( ( '?' << 8 ) | 'h' ) + +/** Hide cursor */ +#define ANSIESC_DECTCEM_RESET ( ( '?' << 8 ) | 'l' ) + /** @} */ extern int ansiesc_process ( struct ansiesc_context *ctx, int c ); diff --git a/roms/ipxe/src/include/ipxe/arp.h b/roms/ipxe/src/include/ipxe/arp.h index 00396d821..e30ae6b76 100644 --- a/roms/ipxe/src/include/ipxe/arp.h +++ b/roms/ipxe/src/include/ipxe/arp.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/tables.h> #include <ipxe/netdevice.h> +#include <ipxe/neighbour.h> /** A network-layer protocol that relies upon ARP */ struct arp_net_protocol { @@ -34,9 +35,26 @@ struct arp_net_protocol { #define __arp_net_protocol __table_entry ( ARP_NET_PROTOCOLS, 01 ) extern struct net_protocol arp_protocol __net_protocol; +extern struct neighbour_discovery arp_discovery; -extern int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, - struct net_protocol *net_protocol, const void *net_dest, - const void *net_source, const void *ll_source ); +/** + * Transmit packet, determining link-layer address via ARP + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @v ll_source Source link-layer address + * @ret rc Return status code + */ +static inline int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *net_source, + const void *ll_source ) { + + return neighbour_tx ( iobuf, netdev, net_protocol, net_dest, + &arp_discovery, net_source, ll_source ); +} #endif /* _IPXE_ARP_H */ diff --git a/roms/ipxe/src/include/ipxe/asn1.h b/roms/ipxe/src/include/ipxe/asn1.h index 3e73b59c7..d12524ddb 100644 --- a/roms/ipxe/src/include/ipxe/asn1.h +++ b/roms/ipxe/src/include/ipxe/asn1.h @@ -222,6 +222,11 @@ struct asn1_builder_header { ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 9 ) +/** ASN.1 OID for id-ce-subjectAltName (2.5.29.17) */ +#define ASN1_OID_SUBJECTALTNAME \ + ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ + ASN1_OID_SINGLE ( 17 ) + /** Define an ASN.1 cursor containing an OID */ #define ASN1_OID_CURSOR( oid_value ) { \ .data = oid_value, \ diff --git a/roms/ipxe/src/include/ipxe/base16.h b/roms/ipxe/src/include/ipxe/base16.h index f0c9842f9..60e3f2315 100644 --- a/roms/ipxe/src/include/ipxe/base16.h +++ b/roms/ipxe/src/include/ipxe/base16.h @@ -33,6 +33,8 @@ static inline size_t base16_decoded_max_len ( const char *encoded ) { } extern void base16_encode ( const uint8_t *raw, size_t len, char *encoded ); +extern int hex_decode ( const char *string, char separator, void *data, + size_t len ); extern int base16_decode ( const char *encoded, uint8_t *raw ); #endif /* _IPXE_BASE16_H */ diff --git a/roms/ipxe/src/include/ipxe/certstore.h b/roms/ipxe/src/include/ipxe/certstore.h new file mode 100644 index 000000000..7456db621 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/certstore.h @@ -0,0 +1,21 @@ +#ifndef _IPXE_CERTSTORE_H +#define _IPXE_CERTSTORE_H + +/** @file + * + * Certificate store + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/asn1.h> +#include <ipxe/x509.h> + +extern struct x509_chain certstore; + +extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw ); +extern struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ); +extern void certstore_add ( struct x509_certificate *cert ); + +#endif /* _IPXE_CERTSTORE_H */ diff --git a/roms/ipxe/src/include/ipxe/clientcert.h b/roms/ipxe/src/include/ipxe/clientcert.h deleted file mode 100644 index 08f62eb73..000000000 --- a/roms/ipxe/src/include/ipxe/clientcert.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _IPXE_CLIENTCERT_H -#define _IPXE_CLIENTCERT_H - -/** @file - * - * Client certificate store - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdint.h> - -/** A client certificate */ -struct client_certificate { - /** Data */ - const void *data; - /** Length */ - size_t len; -}; - -/** A client private key */ -struct client_private_key { - /** Data */ - const void *data; - /** Length */ - size_t len; -}; - -extern struct client_certificate client_certificate; -extern struct client_private_key client_private_key; - -/** - * Check for presence of a client certificate - * - * @ret have_cert We have a client certificate and private key - */ -static inline int have_client_certificate ( void ) { - return ( ( client_certificate.len > 0 ) && - ( client_private_key.len > 0 ) ); -} - -#endif /* _IPXE_CLIENTCERT_H */ diff --git a/roms/ipxe/src/include/ipxe/cms.h b/roms/ipxe/src/include/ipxe/cms.h index eadeca4b8..e026ebd2f 100644 --- a/roms/ipxe/src/include/ipxe/cms.h +++ b/roms/ipxe/src/include/ipxe/cms.h @@ -70,6 +70,7 @@ cms_put ( struct cms_signature *sig ) { extern int cms_signature ( const void *data, size_t len, struct cms_signature **sig ); extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, - const char *name, time_t time, struct x509_root *root ); + const char *name, time_t time, struct x509_chain *store, + struct x509_root *root ); #endif /* _IPXE_CMS_H */ diff --git a/roms/ipxe/src/include/ipxe/console.h b/roms/ipxe/src/include/ipxe/console.h index e2bf4be97..4b90c9cec 100644 --- a/roms/ipxe/src/include/ipxe/console.h +++ b/roms/ipxe/src/include/ipxe/console.h @@ -1,6 +1,7 @@ #ifndef _IPXE_CONSOLE_H #define _IPXE_CONSOLE_H +#include <stddef.h> #include <stdio.h> #include <ipxe/tables.h> @@ -17,6 +18,28 @@ FILE_LICENCE ( GPL2_OR_LATER ); +struct pixel_buffer; + +/** A console configuration */ +struct console_configuration { + /** Width */ + unsigned int width; + /** Height */ + unsigned int height; + /** Colour depth */ + unsigned int depth; + /** Left margin */ + unsigned int left; + /** Right margin */ + unsigned int right; + /** Top margin */ + unsigned int top; + /** Bottom margin */ + unsigned int bottom; + /** Background picture, if any */ + struct pixel_buffer *pixbuf; +}; + /** * A console driver * @@ -25,58 +48,52 @@ FILE_LICENCE ( GPL2_OR_LATER ); * #__console_driver. * * @note Consoles that cannot be used before their initialisation - * function has completed should set #disabled=1 initially. This - * allows other console devices to still be used to print out early - * debugging messages. - * + * function has completed should set #disabled initially. This allows + * other console devices to still be used to print out early debugging + * messages. */ struct console_driver { - /** Console is disabled. - * - * The console's putchar(), getchar() and iskey() methods will - * not be called while #disabled==1. Typically the console's - * initialisation functions will set #disabled=0 upon - * completion. + /** + * Console disabled flags * + * This is the bitwise OR of zero or more console disabled + * flags. */ int disabled; - - /** Write a character to the console. + /** + * Write a character to the console * * @v character Character to be written - * @ret None - - * @err None - - * */ - void ( *putchar ) ( int character ); - - /** Read a character from the console. + void ( * putchar ) ( int character ); + /** + * Read a character from the console * - * @v None - * @ret character Character read - * @err None - * * If no character is available to be read, this method will * block. The character read should not be echoed back to the * console. - * */ - int ( *getchar ) ( void ); - - /** Check for available input. + int ( * getchar ) ( void ); + /** + * Check for available input * - * @v None - - * @ret True Input is available - * @ret False Input is not available - * @err None - + * @ret is_available Input is available * - * This should return True if a subsequent call to getchar() + * This should return true if a subsequent call to getchar() * will not block. + */ + int ( * iskey ) ( void ); + /** + * Configure console * + * @v config Console configuration, or NULL to reset + * @ret rc Return status code */ - int ( *iskey ) ( void ); - - /** Console usage bitmask + int ( * configure ) ( struct console_configuration *config ); + /** + * Console usage bitmask * * This is the bitwise OR of zero or more @c CONSOLE_USAGE_XXX * values. @@ -84,6 +101,15 @@ struct console_driver { int usage; }; +/** Console is disabled for input */ +#define CONSOLE_DISABLED_INPUT 0x0001 + +/** Console is disabled for output */ +#define CONSOLE_DISABLED_OUTPUT 0x0002 + +/** Console is disabled for all uses */ +#define CONSOLE_DISABLED ( CONSOLE_DISABLED_INPUT | CONSOLE_DISABLED_OUTPUT ) + /** Console driver table */ #define CONSOLES __table ( struct console_driver, "consoles" ) @@ -141,7 +167,15 @@ struct console_driver { */ #define CONSOLE_EXPLICIT( console ) ( ( 2 * console + 1 ) != 2 ) +/** Default console width */ +#define CONSOLE_DEFAULT_WIDTH 80 + +/** Default console height */ +#define CONSOLE_DEFAULT_HEIGHT 25 + extern int console_usage; +extern unsigned int console_width; +extern unsigned int console_height; /** * Set console usage @@ -157,7 +191,29 @@ console_set_usage ( int usage ) { return old_usage; } +/** + * Set console size + * + * @v width Width, in characters + * @v height Height, in characters + */ +static inline __attribute__ (( always_inline )) void +console_set_size ( unsigned int width, unsigned int height ) { + console_width = width; + console_height = height; +} + extern int iskey ( void ); extern int getkey ( unsigned long timeout ); +extern int console_configure ( struct console_configuration *config ); + +/** + * Reset console + * + */ +static inline __attribute__ (( always_inline )) void console_reset ( void ) { + + console_configure ( NULL ); +} #endif /* _IPXE_CONSOLE_H */ diff --git a/roms/ipxe/src/include/ipxe/crypto.h b/roms/ipxe/src/include/ipxe/crypto.h index d7d42b66c..3eda5ec6e 100644 --- a/roms/ipxe/src/include/ipxe/crypto.h +++ b/roms/ipxe/src/include/ipxe/crypto.h @@ -157,6 +157,16 @@ struct pubkey_algorithm { * @v ctx Context */ void ( * final ) ( void *ctx ); + /** Check that public key matches private key + * + * @v private_key Private key + * @v private_key_len Private key length + * @v public_key Public key + * @v public_key_len Public key length + * @ret rc Return status code + */ + int ( * match ) ( const void *private_key, size_t private_key_len, + const void *public_key, size_t public_key_len ); }; static inline void digest_init ( struct digest_algorithm *digest, @@ -245,6 +255,14 @@ static inline void pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { pubkey->final ( ctx ); } +static inline int pubkey_match ( struct pubkey_algorithm *pubkey, + const void *private_key, + size_t private_key_len, const void *public_key, + size_t public_key_len ) { + return pubkey->match ( private_key, private_key_len, public_key, + public_key_len ); +} + extern struct digest_algorithm digest_null; extern struct cipher_algorithm cipher_null; extern struct pubkey_algorithm pubkey_null; diff --git a/roms/ipxe/src/include/ipxe/deflate.h b/roms/ipxe/src/include/ipxe/deflate.h new file mode 100644 index 000000000..19c5125eb --- /dev/null +++ b/roms/ipxe/src/include/ipxe/deflate.h @@ -0,0 +1,283 @@ +#ifndef _IPXE_DEFLATE_H +#define _IPXE_DEFLATE_H + +/** @file + * + * DEFLATE decompression algorithm + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <string.h> +#include <ipxe/uaccess.h> + +/** Compression formats */ +enum deflate_format { + /** Raw DEFLATE data (no header or footer) */ + DEFLATE_RAW, + /** ZLIB header and footer */ + DEFLATE_ZLIB, +}; + +/** Block header length (in bits) */ +#define DEFLATE_HEADER_BITS 3 + +/** Block header final block flags bit */ +#define DEFLATE_HEADER_BFINAL_BIT 0 + +/** Block header type LSB */ +#define DEFLATE_HEADER_BTYPE_LSB 1 + +/** Block header type mask */ +#define DEFLATE_HEADER_BTYPE_MASK 0x03 + +/** Block header type: literal data */ +#define DEFLATE_HEADER_BTYPE_LITERAL 0 + +/** Block header type: static Huffman alphabet */ +#define DEFLATE_HEADER_BTYPE_STATIC 1 + +/** Block header type: dynamic Huffman alphabet */ +#define DEFLATE_HEADER_BTYPE_DYNAMIC 2 + +/** Literal header LEN/NLEN field length (in bits) */ +#define DEFLATE_LITERAL_LEN_BITS 16 + +/** Dynamic header length (in bits) */ +#define DEFLATE_DYNAMIC_BITS 14 + +/** Dynamic header HLIT field LSB */ +#define DEFLATE_DYNAMIC_HLIT_LSB 0 + +/** Dynamic header HLIT field mask */ +#define DEFLATE_DYNAMIC_HLIT_MASK 0x1f + +/** Dynamic header HDIST field LSB */ +#define DEFLATE_DYNAMIC_HDIST_LSB 5 + +/** Dynamic header HDIST field mask */ +#define DEFLATE_DYNAMIC_HDIST_MASK 0x1f + +/** Dynamic header HCLEN field LSB */ +#define DEFLATE_DYNAMIC_HCLEN_LSB 10 + +/** Dynamic header HCLEN field mask */ +#define DEFLATE_DYNAMIC_HCLEN_MASK 0x0f + +/** Dynamic header code length length (in bits) */ +#define DEFLATE_CODELEN_BITS 3 + +/** Maximum length of a Huffman symbol (in bits) */ +#define DEFLATE_HUFFMAN_BITS 15 + +/** Quick lookup length for a Huffman symbol (in bits) + * + * This is a policy decision. + */ +#define DEFLATE_HUFFMAN_QL_BITS 7 + +/** Quick lookup shift */ +#define DEFLATE_HUFFMAN_QL_SHIFT ( 16 - DEFLATE_HUFFMAN_QL_BITS ) + +/** Literal/length end of block code */ +#define DEFLATE_LITLEN_END 256 + +/** Maximum value of a literal/length code */ +#define DEFLATE_LITLEN_MAX_CODE 287 + +/** Maximum value of a distance code */ +#define DEFLATE_DISTANCE_MAX_CODE 31 + +/** Maximum value of a code length code */ +#define DEFLATE_CODELEN_MAX_CODE 18 + +/** ZLIB header length (in bits) */ +#define ZLIB_HEADER_BITS 16 + +/** ZLIB header compression method LSB */ +#define ZLIB_HEADER_CM_LSB 0 + +/** ZLIB header compression method mask */ +#define ZLIB_HEADER_CM_MASK 0x0f + +/** ZLIB header compression method: DEFLATE */ +#define ZLIB_HEADER_CM_DEFLATE 8 + +/** ZLIB header preset dictionary flag bit */ +#define ZLIB_HEADER_FDICT_BIT 13 + +/** ZLIB ADLER32 length (in bits) */ +#define ZLIB_ADLER32_BITS 32 + +/** A Huffman-coded set of symbols of a given length */ +struct deflate_huf_symbols { + /** Length of Huffman-coded symbols */ + uint8_t bits; + /** Shift to normalise symbols of this length to 16 bits */ + uint8_t shift; + /** Number of Huffman-coded symbols having this length */ + uint16_t freq; + /** First symbol of this length (normalised to 16 bits) + * + * Stored as a 32-bit value to allow the value 0x10000 to be + * used for empty sets of symbols longer than the maximum + * utilised length. + */ + uint32_t start; + /** Raw symbols having this length */ + uint16_t *raw; +}; + +/** A Huffman-coded alphabet */ +struct deflate_alphabet { + /** Huffman-coded symbol set for each length */ + struct deflate_huf_symbols huf[DEFLATE_HUFFMAN_BITS]; + /** Quick lookup table */ + uint8_t lookup[ 1 << DEFLATE_HUFFMAN_QL_BITS ]; + /** Raw symbols + * + * Ordered by Huffman-coded symbol length, then by symbol + * value. This field has a variable length. + */ + uint16_t raw[0]; +}; + +/** A static Huffman alphabet length pattern */ +struct deflate_static_length_pattern { + /** Length pair */ + uint8_t fill; + /** Repetition count */ + uint8_t count; +} __attribute__ (( packed )); + +/** Decompressor */ +struct deflate { + /** Resume point + * + * Used as the target of a computed goto to jump to the + * appropriate point within the state machine. + */ + void *resume; + /** Format */ + enum deflate_format format; + + /** Accumulator */ + uint32_t accumulator; + /** Bit-reversed accumulator + * + * Don't ask. + */ + uint32_t rotalumucca; + /** Number of bits within the accumulator */ + unsigned int bits; + + /** Current block header */ + unsigned int header; + /** Remaining length of data (e.g. within a literal block) */ + size_t remaining; + /** Current length index within a set of code lengths */ + unsigned int length_index; + /** Target length index within a set of code lengths */ + unsigned int length_target; + /** Current length within a set of code lengths */ + unsigned int length; + /** Number of extra bits required */ + unsigned int extra_bits; + /** Length of a duplicated string */ + size_t dup_len; + /** Distance of a duplicated string */ + size_t dup_distance; + + /** Literal/length Huffman alphabet */ + struct deflate_alphabet litlen; + /** Literal/length raw symbols + * + * Must immediately follow the literal/length Huffman alphabet. + */ + uint16_t litlen_raw[ DEFLATE_LITLEN_MAX_CODE + 1 ]; + /** Number of symbols in the literal/length Huffman alphabet */ + unsigned int litlen_count; + + /** Distance and code length Huffman alphabet + * + * The code length Huffman alphabet has a maximum Huffman + * symbol length of 7 and a maximum code value of 18, and is + * thus strictly smaller than the distance Huffman alphabet. + * Since we never need both alphabets simultaneously, we can + * reuse the storage space for the distance alphabet to + * temporarily hold the code length alphabet. + */ + struct deflate_alphabet distance_codelen; + /** Distance and code length raw symbols + * + * Must immediately follow the distance and code length + * Huffman alphabet. + */ + uint16_t distance_codelen_raw[ DEFLATE_DISTANCE_MAX_CODE + 1 ]; + /** Number of symbols in the distance Huffman alphabet */ + unsigned int distance_count; + + /** Huffman code lengths + * + * The literal/length and distance code lengths are + * constructed as a single set of lengths. + * + * The code length Huffman alphabet has a maximum code value + * of 18 and the set of lengths is thus strictly smaller than + * the combined literal/length and distance set of lengths. + * Since we never need both alphabets simultaneously, we can + * reuse the storage space for the literal/length and distance + * code lengths to temporarily hold the code length code + * lengths. + */ + uint8_t lengths[ ( ( DEFLATE_LITLEN_MAX_CODE + 1 ) + + ( DEFLATE_DISTANCE_MAX_CODE + 1 ) + + 1 /* round up */ ) / 2 ]; +}; + +/** A chunk of data */ +struct deflate_chunk { + /** Data */ + userptr_t data; + /** Current offset */ + size_t offset; + /** Length of data */ + size_t len; +}; + +/** + * Initialise chunk of data + * + * @v chunk Chunk of data to initialise + * @v data Data + * @v offset Starting offset + * @v len Length + */ +static inline __attribute__ (( always_inline )) void +deflate_chunk_init ( struct deflate_chunk *chunk, userptr_t data, + size_t offset, size_t len ) { + + chunk->data = data; + chunk->offset = offset; + chunk->len = len; +} + +/** + * Check if decompression has finished + * + * @v deflate Decompressor + * @ret finished Decompression has finished + */ +static inline int deflate_finished ( struct deflate *deflate ) { + return ( deflate->resume == NULL ); +} + +extern void deflate_init ( struct deflate *deflate, + enum deflate_format format ); +extern int deflate_inflate ( struct deflate *deflate, + struct deflate_chunk *in, + struct deflate_chunk *out ); + +#endif /* _IPXE_DEFLATE_H */ diff --git a/roms/ipxe/src/include/ipxe/device.h b/roms/ipxe/src/include/ipxe/device.h index 435af6ecf..c59697c03 100644 --- a/roms/ipxe/src/include/ipxe/device.h +++ b/roms/ipxe/src/include/ipxe/device.h @@ -54,6 +54,9 @@ struct device_description { /** ISA bus type */ #define BUS_TYPE_ISA 5 +/** TAP bus type */ +#define BUS_TYPE_TAP 6 + /** A hardware device */ struct device { /** Name */ diff --git a/roms/ipxe/src/include/ipxe/dhcp.h b/roms/ipxe/src/include/ipxe/dhcp.h index b97dfe32c..bcfb85cc1 100644 --- a/roms/ipxe/src/include/ipxe/dhcp.h +++ b/roms/ipxe/src/include/ipxe/dhcp.h @@ -290,6 +290,9 @@ struct dhcp_client_uuid { #define DHCP_CLIENT_UUID_TYPE 0 +/** DNS domain search list */ +#define DHCP_DOMAIN_SEARCH 119 + /** Etherboot-specific encapsulated options * * This encapsulated options field is used to contain all options @@ -397,14 +400,7 @@ struct dhcp_netdev_desc { uint16_t device; } __attribute__ (( packed )); -/** Use cached network settings - * - * Cached network settings may be available from a prior DHCP request - * (if running as a PXE NBP), non-volatile storage on the NIC, or - * settings set via the command line or an embedded image. If this - * flag is not set, it will be assumed that those sources are - * insufficient and that DHCP should still be run when autobooting. - */ +/** Use cached network settings (obsolete; do not reuse this value) */ #define DHCP_EB_USE_CACHED DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xb2 ) /** BIOS drive number @@ -450,6 +446,18 @@ struct dhcp_netdev_desc { */ #define DHCP_EB_REVERSE_PASSWORD DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc1 ) +/** User ID + * + * This will be used as the user id for AUTH_SYS based authentication in NFS. + */ +#define DHCP_EB_UID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc2 ) + +/** Group ID + * + * This will be used as the group id for AUTH_SYS based authentication in NFS. + */ +#define DHCP_EB_GID DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xc3 ) + /** iPXE version number */ #define DHCP_EB_VERSION DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0xeb ) @@ -665,12 +673,4 @@ extern int start_dhcp ( struct interface *job, struct net_device *netdev ); extern int start_pxebs ( struct interface *job, struct net_device *netdev, unsigned int pxe_type ); -/* In environments that can provide cached DHCP packets, this function - * should look for such a packet and call store_cached_dhcpack() with - * it if it exists. - */ -extern void get_cached_dhcpack ( void ); - -extern void store_cached_dhcpack ( userptr_t data, size_t len ); - #endif /* _IPXE_DHCP_H */ diff --git a/roms/ipxe/src/include/ipxe/dhcpv6.h b/roms/ipxe/src/include/ipxe/dhcpv6.h new file mode 100644 index 000000000..2636b8ab2 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/dhcpv6.h @@ -0,0 +1,227 @@ +#ifndef _IPXE_DHCPV6_H +#define _IPXE_DHCPV6_H + +/** @file + * + * Dynamic Host Configuration Protocol for IPv6 + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/in.h> +#include <ipxe/uuid.h> + +/** DHCPv6 server port */ +#define DHCPV6_SERVER_PORT 547 + +/** DHCPv6 client port */ +#define DHCPV6_CLIENT_PORT 546 + +/** + * A DHCPv6 option + * + */ +struct dhcpv6_option { + /** Code */ + uint16_t code; + /** Length of the data field */ + uint16_t len; + /** Data */ + uint8_t data[0]; +} __attribute__ (( packed )); + +/** DHCP unique identifier based on UUID (DUID-UUID) */ +struct dhcpv6_duid_uuid { + /** Type */ + uint16_t type; + /** UUID */ + union uuid uuid; +} __attribute__ (( packed )); + +/** DHCP unique identifier based on UUID (DUID-UUID) */ +#define DHCPV6_DUID_UUID 4 + +/** DHCPv6 client or server identifier option */ +struct dhcpv6_duid_option { + /** Option header */ + struct dhcpv6_option header; + /** DHCP unique identifier (DUID) */ + uint8_t duid[0]; +} __attribute__ (( packed )); + +/** DHCPv6 client identifier option */ +#define DHCPV6_CLIENT_ID 1 + +/** DHCPv6 server identifier option */ +#define DHCPV6_SERVER_ID 2 + +/** DHCPv6 identity association for non-temporary address (IA_NA) option */ +struct dhcpv6_ia_na_option { + /** Option header */ + struct dhcpv6_option header; + /** Identity association identifier (IAID) */ + uint32_t iaid; + /** Renew time (in seconds) */ + uint32_t renew; + /** Rebind time (in seconds) */ + uint32_t rebind; + /** IA_NA options */ + struct dhcpv6_option options[0]; +} __attribute__ (( packed )); + +/** DHCPv6 identity association for non-temporary address (IA_NA) option */ +#define DHCPV6_IA_NA 3 + +/** DHCPv6 identity association address (IAADDR) option */ +struct dhcpv6_iaaddr_option { + /** Option header */ + struct dhcpv6_option header; + /** IPv6 address */ + struct in6_addr address; + /** Preferred lifetime (in seconds) */ + uint32_t preferred; + /** Valid lifetime (in seconds) */ + uint32_t valid; + /** IAADDR options */ + struct dhcpv6_option options[0]; +} __attribute__ (( packed )); + +/** DHCPv6 identity association address (IAADDR) option */ +#define DHCPV6_IAADDR 5 + +/** DHCPv6 option request option */ +struct dhcpv6_option_request_option { + /** Option header */ + struct dhcpv6_option header; + /** Requested options */ + uint16_t requested[0]; +} __attribute__ (( packed )); + +/** DHCPv6 option request option */ +#define DHCPV6_OPTION_REQUEST 6 + +/** DHCPv6 elapsed time option */ +struct dhcpv6_elapsed_time_option { + /** Option header */ + struct dhcpv6_option header; + /** Elapsed time, in centiseconds */ + uint16_t elapsed; +} __attribute__ (( packed )); + +/** DHCPv6 elapsed time option */ +#define DHCPV6_ELAPSED_TIME 8 + +/** DHCPv6 status code option */ +struct dhcpv6_status_code_option { + /** Option header */ + struct dhcpv6_option header; + /** Status code */ + uint16_t status; + /** Status message */ + char message[0]; +} __attribute__ (( packed )); + +/** DHCPv6 status code option */ +#define DHCPV6_STATUS_CODE 13 + +/** DHCPv6 user class */ +struct dhcpv6_user_class { + /** Length */ + uint16_t len; + /** User class string */ + char string[0]; +} __attribute__ (( packed )); + +/** DHCPv6 user class option */ +struct dhcpv6_user_class_option { + /** Option header */ + struct dhcpv6_option header; + /** User class */ + struct dhcpv6_user_class user_class[0]; +} __attribute__ (( packed )); + +/** DHCPv6 user class option */ +#define DHCPV6_USER_CLASS 15 + +/** DHCPv6 DNS recursive name server option */ +#define DHCPV6_DNS_SERVERS 23 + +/** DHCPv6 domain search list option */ +#define DHCPV6_DOMAIN_LIST 24 + +/** DHCPv6 bootfile URI option */ +#define DHCPV6_BOOTFILE_URL 59 + +/** DHCPv6 bootfile parameters option */ +#define DHCPV6_BOOTFILE_PARAM 60 + +/** DHCPv6 syslog server option + * + * This option code has not yet been assigned by IANA. Please update + * this definition once an option code has been assigned. + */ +#define DHCPV6_LOG_SERVERS 0xffffffffUL + +/** + * Any DHCPv6 option + * + */ +union dhcpv6_any_option { + struct dhcpv6_option header; + struct dhcpv6_duid_option duid; + struct dhcpv6_ia_na_option ia_na; + struct dhcpv6_iaaddr_option iaaddr; + struct dhcpv6_option_request_option option_request; + struct dhcpv6_elapsed_time_option elapsed_time; + struct dhcpv6_status_code_option status_code; + struct dhcpv6_user_class_option user_class; +}; + +/** + * A DHCPv6 header + * + */ +struct dhcpv6_header { + /** Message type */ + uint8_t type; + /** Transaction ID */ + uint8_t xid[3]; + /** Options */ + struct dhcpv6_option options[0]; +} __attribute__ (( packed )); + +/** DHCPv6 solicitation */ +#define DHCPV6_SOLICIT 1 + +/** DHCPv6 advertisement */ +#define DHCPV6_ADVERTISE 2 + +/** DHCPv6 request */ +#define DHCPV6_REQUEST 3 + +/** DHCPv6 reply */ +#define DHCPV6_REPLY 7 + +/** DHCPv6 information request */ +#define DHCPV6_INFORMATION_REQUEST 11 + +/** DHCPv6 settings block name */ +#define DHCPV6_SETTINGS_NAME "dhcpv6" + +/** + * Construct all-DHCP-relay-agents-and-servers multicast address + * + * @v addr Zeroed address to construct + */ +static inline void ipv6_all_dhcp_relay_and_servers ( struct in6_addr *addr ) { + addr->s6_addr16[0] = htons ( 0xff02 ); + addr->s6_addr[13] = 1; + addr->s6_addr[15] = 2; +} + +extern int start_dhcpv6 ( struct interface *job, struct net_device *netdev, + int stateful ); + +#endif /* _IPXE_DHCPV6_H */ diff --git a/roms/ipxe/src/include/ipxe/dns.h b/roms/ipxe/src/include/ipxe/dns.h index 1c427601a..4f6cab3a4 100644 --- a/roms/ipxe/src/include/ipxe/dns.h +++ b/roms/ipxe/src/include/ipxe/dns.h @@ -12,81 +12,144 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> #include <ipxe/in.h> -/* - * Constants +/** DNS server port */ +#define DNS_PORT 53 + +/** An RFC1035-encoded DNS name */ +struct dns_name { + /** Start of data */ + void *data; + /** Offset of name within data */ + size_t offset; + /** Total length of data */ + size_t len; +}; + +/** + * Test for a DNS compression pointer + * + * @v byte Initial byte + * @ret is_compressed Is a compression pointer + */ +#define DNS_IS_COMPRESSED( byte ) ( (byte) & 0xc0 ) + +/** + * Extract DNS compression pointer * + * @v word Initial word + * @ret offset Offset */ +#define DNS_COMPRESSED_OFFSET( word ) ( (word) & ~0xc000 ) + +/** + * Extract DNS label length + * + * @v byte Initial byte + * @ret len Label length + */ +#define DNS_LABEL_LEN( byte ) ( (byte) & ~0xc0 ) + +/** Maximum length of a single DNS label */ +#define DNS_MAX_LABEL_LEN 0x3f -#define DNS_TYPE_A 1 -#define DNS_TYPE_CNAME 5 -#define DNS_TYPE_ANY 255 - -#define DNS_CLASS_IN 1 -#define DNS_CLASS_CS 2 -#define DNS_CLASS_CH 3 -#define DNS_CLASS_HS 4 - -#define DNS_FLAG_QUERY ( 0x00 << 15 ) -#define DNS_FLAG_RESPONSE ( 0x01 << 15 ) -#define DNS_FLAG_QR(flags) ( (flags) & ( 0x01 << 15 ) ) -#define DNS_FLAG_OPCODE_QUERY ( 0x00 << 11 ) -#define DNS_FLAG_OPCODE_IQUERY ( 0x01 << 11 ) -#define DNS_FLAG_OPCODE_STATUS ( 0x02 << 11 ) -#define DNS_FLAG_OPCODE(flags) ( (flags) & ( 0x0f << 11 ) ) -#define DNS_FLAG_RD ( 0x01 << 8 ) -#define DNS_FLAG_RA ( 0x01 << 7 ) -#define DNS_FLAG_RCODE_OK ( 0x00 << 0 ) -#define DNS_FLAG_RCODE_NX ( 0x03 << 0 ) -#define DNS_FLAG_RCODE(flags) ( (flags) & ( 0x0f << 0 ) ) - -#define DNS_PORT 53 -#define DNS_MAX_RETRIES 3 -#define DNS_MAX_CNAME_RECURSION 0x30 - -/* - * DNS protocol structures +/** Maximum length of a DNS name (mandated by RFC1035 section 2.3.4) */ +#define DNS_MAX_NAME_LEN 255 + +/** Maximum depth of CNAME recursion * + * This is a policy decision. */ +#define DNS_MAX_CNAME_RECURSION 32 + +/** A DNS packet header */ struct dns_header { - uint16_t id; - uint16_t flags; - uint16_t qdcount; - uint16_t ancount; - uint16_t nscount; - uint16_t arcount; + /** Query identifier */ + uint16_t id; + /** Flags */ + uint16_t flags; + /** Number of question records */ + uint16_t qdcount; + /** Number of answer records */ + uint16_t ancount; + /** Number of name server records */ + uint16_t nscount; + /** Number of additional records */ + uint16_t arcount; } __attribute__ (( packed )); -struct dns_query_info { - uint16_t qtype; - uint16_t qclass; -} __attribute__ (( packed )); +/** Recursion desired flag */ +#define DNS_FLAG_RD 0x0100 -struct dns_query { - struct dns_header dns; - char payload[ 256 + sizeof ( struct dns_query_info ) ]; +/** A DNS question */ +struct dns_question { + /** Query type */ + uint16_t qtype; + /** Query class */ + uint16_t qclass; } __attribute__ (( packed )); -struct dns_rr_info_common { - uint16_t type; - uint16_t class; - uint32_t ttl; - uint16_t rdlength; +/** DNS class "IN" */ +#define DNS_CLASS_IN 1 + +/** A DNS resource record */ +struct dns_rr_common { + /** Type */ + uint16_t type; + /** Class */ + uint16_t class; + /** Time to live */ + uint32_t ttl; + /** Resource data length */ + uint16_t rdlength; } __attribute__ (( packed )); -struct dns_rr_info_a { - struct dns_rr_info_common common; +/** Type of a DNS "A" record */ +#define DNS_TYPE_A 1 + +/** A DNS "A" record */ +struct dns_rr_a { + /** Common fields */ + struct dns_rr_common common; + /** IPv4 address */ struct in_addr in_addr; } __attribute__ (( packed )); -struct dns_rr_info_cname { - struct dns_rr_info_common common; - char cname[0]; +/** Type of a DNS "AAAA" record */ +#define DNS_TYPE_AAAA 28 + +/** A DNS "AAAA" record */ +struct dns_rr_aaaa { + /** Common fields */ + struct dns_rr_common common; + /** IPv6 address */ + struct in6_addr in6_addr; } __attribute__ (( packed )); -union dns_rr_info { - struct dns_rr_info_common common; - struct dns_rr_info_a a; - struct dns_rr_info_cname cname; +/** Type of a DNS "NAME" record */ +#define DNS_TYPE_CNAME 5 + +/** A DNS "CNAME" record */ +struct dns_rr_cname { + /** Common fields */ + struct dns_rr_common common; +} __attribute__ (( packed )); + +/** A DNS resource record */ +union dns_rr { + /** Common fields */ + struct dns_rr_common common; + /** "A" record */ + struct dns_rr_a a; + /** "AAAA" record */ + struct dns_rr_aaaa aaaa; + /** "CNAME" record */ + struct dns_rr_cname cname; }; +extern int dns_encode ( const char *string, struct dns_name *name ); +extern int dns_decode ( struct dns_name *name, char *data, size_t len ); +extern int dns_compare ( struct dns_name *first, struct dns_name *second ); +extern int dns_copy ( struct dns_name *src, struct dns_name *dst ); +extern int dns_skip ( struct dns_name *name ); + #endif /* _IPXE_DNS_H */ diff --git a/roms/ipxe/src/include/ipxe/downloader.h b/roms/ipxe/src/include/ipxe/downloader.h index a7efa3f79..de1a2e75e 100644 --- a/roms/ipxe/src/include/ipxe/downloader.h +++ b/roms/ipxe/src/include/ipxe/downloader.h @@ -12,7 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct interface; struct image; -extern int create_downloader ( struct interface *job, struct image *image, - int type, ... ); +extern int create_downloader ( struct interface *job, struct image *image ); #endif /* _IPXE_DOWNLOADER_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/Guid/FileInfo.h b/roms/ipxe/src/include/ipxe/efi/Guid/FileInfo.h new file mode 100644 index 000000000..21fd38904 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Guid/FileInfo.h @@ -0,0 +1,73 @@ +/** @file + Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.SetInfo() + and EFI_FILE_PROTOCOL.GetInfo() to set or get generic file information. + This GUID is defined in UEFI specification. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __FILE_INFO_H__ +#define __FILE_INFO_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_FILE_INFO_ID \ + { \ + 0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +typedef struct { + /// + /// The size of the EFI_FILE_INFO structure, including the Null-terminated FileName string. + /// + UINT64 Size; + /// + /// The size of the file in bytes. + /// + UINT64 FileSize; + /// + /// PhysicalSize The amount of physical space the file consumes on the file system volume. + /// + UINT64 PhysicalSize; + /// + /// The time the file was created. + /// + EFI_TIME CreateTime; + /// + /// The time when the file was last accessed. + /// + EFI_TIME LastAccessTime; + /// + /// The time when the file's contents were last modified. + /// + EFI_TIME ModificationTime; + /// + /// The attribute bits for the file. + /// + UINT64 Attribute; + /// + /// The Null-terminated name of the file. + /// + CHAR16 FileName[1]; +} EFI_FILE_INFO; + +/// +/// The FileName field of the EFI_FILE_INFO data structure is variable length. +/// Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to +/// be the size of the data structure without the FileName field. The following macro +/// computes this size correctly no matter how big the FileName array is declared. +/// This is required to make the EFI_FILE_INFO data structure ANSI compilant. +/// +#define SIZE_OF_EFI_FILE_INFO OFFSET_OF (EFI_FILE_INFO, FileName) + +extern EFI_GUID gEfiFileInfoGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Guid/FileSystemInfo.h b/roms/ipxe/src/include/ipxe/efi/Guid/FileSystemInfo.h new file mode 100644 index 000000000..504b7938f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Guid/FileSystemInfo.h @@ -0,0 +1,65 @@ +/** @file + Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.GetInfo() + or EFI_FILE_PROTOCOL.SetInfo() to get or set information about the system's volume. + This GUID is defined in UEFI specification. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __FILE_SYSTEM_INFO_H__ +#define __FILE_SYSTEM_INFO_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_FILE_SYSTEM_INFO_ID \ + { \ + 0x9576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +typedef struct { + /// + /// The size of the EFI_FILE_SYSTEM_INFO structure, including the Null-terminated VolumeLabel string. + /// + UINT64 Size; + /// + /// TRUE if the volume only supports read access. + /// + BOOLEAN ReadOnly; + /// + /// The number of bytes managed by the file system. + /// + UINT64 VolumeSize; + /// + /// The number of available bytes for use by the file system. + /// + UINT64 FreeSpace; + /// + /// The nominal block size by which files are typically grown. + /// + UINT32 BlockSize; + /// + /// The Null-terminated string that is the volume's label. + /// + CHAR16 VolumeLabel[1]; +} EFI_FILE_SYSTEM_INFO; + +/// +/// The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length. +/// Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs +/// to be the size of the data structure without the VolumeLable field. The following macro +/// computes this size correctly no matter how big the VolumeLable array is declared. +/// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant. +/// +#define SIZE_OF_EFI_FILE_SYSTEM_INFO OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel) + +extern EFI_GUID gEfiFileSystemInfoGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h b/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h index 75fc642f0..cf0a7c25e 100644 --- a/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h +++ b/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h @@ -1,7 +1,7 @@ /** @file GUID for UEFI WIN_CERTIFICATE structure. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -76,7 +76,7 @@ typedef struct { typedef struct { /// /// This is the standard WIN_CERTIFICATE header, where - /// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID. + /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID. /// WIN_CERTIFICATE Hdr; /// diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h index b57059a94..53654ee42 100644 --- a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h +++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h @@ -6,7 +6,7 @@ PCI-to-PCI Bridge Architecture Specification, Revision 1.2 PC Card Standard, 8.0 - Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -221,7 +221,7 @@ typedef struct { #define PCI_IF_16550_MODEM 0x02 #define PCI_IF_16650_MODEM 0x03 #define PCI_IF_16750_MODEM 0x04 -#define PCI_SUBCLASS_SCC_OTHER 0x80 +#define PCI_SUBCLASS_SCC_OTHER 0x80 #define PCI_CLASS_SYSTEM_PERIPHERAL 0x08 #define PCI_SUBCLASS_PIC 0x00 @@ -240,7 +240,7 @@ typedef struct { #define PCI_IF_EISA_TIMER 0x02 #define PCI_SUBCLASS_RTC 0x03 #define PCI_IF_GENERIC_RTC 0x00 -#define PCI_IF_ISA_RTC 0x00 +#define PCI_IF_ISA_RTC 0x01 #define PCI_SUBCLASS_PNP_CONTROLLER 0x04 ///< HotPlug Controller #define PCI_SUBCLASS_PERIPHERAL_OTHER 0x80 @@ -251,10 +251,12 @@ typedef struct { #define PCI_SUBCLASS_SCAN_CONTROLLER 0x03 #define PCI_SUBCLASS_GAMEPORT 0x04 #define PCI_IF_GAMEPORT 0x00 -#define PCI_IF_GAMEPORT1 0x01 +#define PCI_IF_GAMEPORT1 0x10 #define PCI_SUBCLASS_INPUT_OTHER 0x80 #define PCI_CLASS_DOCKING_STATION 0x0A +#define PCI_SUBCLASS_DOCKING_GENERIC 0x00 +#define PCI_SUBCLASS_DOCKING_OTHER 0x80 #define PCI_CLASS_PROCESSOR 0x0B #define PCI_SUBCLASS_PROC_386 0x00 @@ -282,7 +284,7 @@ typedef struct { #define PCI_CLASS_WIRELESS 0x0D #define PCI_SUBCLASS_IRDA 0x00 #define PCI_SUBCLASS_IR 0x01 -#define PCI_SUBCLASS_RF 0x02 +#define PCI_SUBCLASS_RF 0x10 #define PCI_SUBCLASS_WIRELESS_OTHER 0x80 #define PCI_CLASS_INTELLIGENT_IO 0x0E diff --git a/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h b/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h index af4c87434..be521f969 100644 --- a/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h +++ b/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h @@ -17,6 +17,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef __BASE_LIB__ #define __BASE_LIB__ +FILE_LICENCE ( BSD3 ); + // // Definitions for architecture-specific types // @@ -1291,7 +1293,7 @@ InitializeListHead ( If Entry is NULL, then ASSERT(). If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number + If PcdMaximumLinkedListLength is not zero, and prior to insertion the number of nodes in ListHead, including the ListHead node, is greater than or equal to PcdMaximumLinkedListLength, then ASSERT(). @@ -1321,7 +1323,7 @@ InsertHeadList ( If Entry is NULL, then ASSERT(). If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number + If PcdMaximumLinkedListLength is not zero, and prior to insertion the number of nodes in ListHead, including the ListHead node, is greater than or equal to PcdMaximumLinkedListLength, then ASSERT(). @@ -1350,7 +1352,7 @@ InsertTailList ( If List is NULL, then ASSERT(). If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and the number of nodes + If PcdMaximumLinkedListLength is not zero, and the number of nodes in List, including the List node, is greater than or equal to PcdMaximumLinkedListLength, then ASSERT(). @@ -1378,8 +1380,8 @@ GetFirstNode ( If Node is NULL, then ASSERT(). If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and List contains more than - PcdMaximumLinkedListLenth nodes, then ASSERT(). + If PcdMaximumLinkedListLength is not zero, and List contains more than + PcdMaximumLinkedListLength nodes, then ASSERT(). If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT(). @param List A pointer to the head node of a doubly linked list. @@ -1407,8 +1409,8 @@ GetNextNode ( If Node is NULL, then ASSERT(). If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and List contains more than - PcdMaximumLinkedListLenth nodes, then ASSERT(). + If PcdMaximumLinkedListLength is not zero, and List contains more than + PcdMaximumLinkedListLength nodes, then ASSERT(). If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT(). @param List A pointer to the head node of a doubly linked list. @@ -1434,7 +1436,7 @@ GetPreviousNode ( If ListHead is NULL, then ASSERT(). If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and the number of nodes + If PcdMaximumLinkedListLength is not zero, and the number of nodes in List, including the List node, is greater than or equal to PcdMaximumLinkedListLength, then ASSERT(). @@ -1464,7 +1466,7 @@ IsListEmpty ( If Node is NULL, then ASSERT(). If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and the number of nodes + If PcdMaximumLinkedListLength is not zero, and the number of nodes in List, including the List node, is greater than or equal to PcdMaximumLinkedListLength, then ASSERT(). If PcdVerifyNodeInList is TRUE and Node is not a node in List the and Node is not equal @@ -1496,7 +1498,7 @@ IsNull ( If Node is NULL, then ASSERT(). If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(), then ASSERT(). - If PcdMaximumLinkedListLenth is not zero, and the number of nodes + If PcdMaximumLinkedListLength is not zero, and the number of nodes in List, including the List node, is greater than or equal to PcdMaximumLinkedListLength, then ASSERT(). If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT(). @@ -2343,6 +2345,7 @@ BitFieldRead8 ( If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2376,6 +2379,7 @@ BitFieldWrite8 ( If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2409,6 +2413,7 @@ BitFieldOr8 ( If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2443,6 +2448,8 @@ BitFieldAnd8 ( If StartBit is greater than 7, then ASSERT(). If EndBit is greater than 7, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2505,6 +2512,7 @@ BitFieldRead16 ( If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2538,6 +2546,7 @@ BitFieldWrite16 ( If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2571,6 +2580,7 @@ BitFieldOr16 ( If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2605,6 +2615,8 @@ BitFieldAnd16 ( If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2667,6 +2679,7 @@ BitFieldRead32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2700,6 +2713,7 @@ BitFieldWrite32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2733,6 +2747,7 @@ BitFieldOr32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2767,6 +2782,8 @@ BitFieldAnd32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2829,6 +2846,7 @@ BitFieldRead64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2862,6 +2880,7 @@ BitFieldWrite64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2895,6 +2914,7 @@ BitFieldOr64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -2929,6 +2949,8 @@ BitFieldAnd64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Operand Operand on which to perform the bitfield operation. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5380,6 +5402,7 @@ AsmMsrBitFieldRead32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5416,6 +5439,7 @@ AsmMsrBitFieldWrite32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5452,6 +5476,7 @@ AsmMsrBitFieldOr32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5490,6 +5515,8 @@ AsmMsrBitFieldAnd32 ( If StartBit is greater than 31, then ASSERT(). If EndBit is greater than 31, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5684,6 +5711,7 @@ AsmMsrBitFieldRead64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5720,6 +5748,7 @@ AsmMsrBitFieldWrite64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5756,6 +5785,7 @@ AsmMsrBitFieldOr64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. @@ -5793,6 +5823,8 @@ AsmMsrBitFieldAnd64 ( If StartBit is greater than 63, then ASSERT(). If EndBit is greater than 63, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). + If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). + If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Index The 32-bit MSR index to write. @param StartBit The ordinal of the least significant bit in the bit field. diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h index 30fd44377..f462f7aad 100644 --- a/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h +++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h @@ -1,7 +1,7 @@ /** @file Present the boot mode values in PI. - Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -11,7 +11,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. @par Revision Reference: - PI Version 1.0 + PI Version 1.2.1A **/ @@ -35,6 +35,7 @@ typedef UINT32 EFI_BOOT_MODE; #define BOOT_WITH_DEFAULT_SETTINGS 0x04 #define BOOT_ON_S4_RESUME 0x05 #define BOOT_ON_S5_RESUME 0x06 +#define BOOT_WITH_MFG_MODE_SETTINGS 0x07 #define BOOT_ON_S2_RESUME 0x10 #define BOOT_ON_S3_RESUME 0x11 #define BOOT_ON_FLASH_UPDATE 0x12 diff --git a/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h b/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h index 535cd4ce0..1294459f9 100644 --- a/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h +++ b/roms/ipxe/src/include/ipxe/efi/ProcessorBind.h @@ -1,6 +1,8 @@ #ifndef _IPXE_EFI_PROCESSOR_BIND_H #define _IPXE_EFI_PROCESSOR_BIND_H +FILE_LICENCE ( GPL2_OR_LATER ); + /* * EFI header files rely on having the CPU architecture directory * present in the search path in order to pick up ProcessorBind.h. We diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/BlockIo.h b/roms/ipxe/src/include/ipxe/efi/Protocol/BlockIo.h new file mode 100644 index 000000000..f45154bb1 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/BlockIo.h @@ -0,0 +1,243 @@ +/** @file + Block IO protocol as defined in the UEFI 2.0 specification. + + The Block IO protocol is used to abstract block devices like hard drives, + DVD-ROMs and floppy drives. + + Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __BLOCK_IO_H__ +#define __BLOCK_IO_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_BLOCK_IO_PROTOCOL_GUID \ + { \ + 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +typedef struct _EFI_BLOCK_IO_PROTOCOL EFI_BLOCK_IO_PROTOCOL; + +/// +/// Protocol GUID name defined in EFI1.1. +/// +#define BLOCK_IO_PROTOCOL EFI_BLOCK_IO_PROTOCOL_GUID + +/// +/// Protocol defined in EFI1.1. +/// +typedef EFI_BLOCK_IO_PROTOCOL EFI_BLOCK_IO; + +/** + Reset the Block Device. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_RESET)( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Read BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId Id of the media, changes every time the media is replaced. + @param Lba The starting Logical Block Address to read from + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while performing the read. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_READ)( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Write BufferSize bytes from Lba into Buffer. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. The caller is + responsible for writing to only legitimate locations. + @param BufferSize Size of Buffer, must be a multiple of device block size. + @param Buffer A pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data was written correctly to the device. + @retval EFI_WRITE_PROTECTED The device can not be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing the write. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. + @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_WRITE)( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flush the Block Device. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data was written to the device + @retval EFI_DEVICE_ERROR The device reported an error while writting back the data + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_BLOCK_FLUSH)( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +/** + Block IO read only mode data and updated only via members of BlockIO +**/ +typedef struct { + /// + /// The curent media Id. If the media changes, this value is changed. + /// + UINT32 MediaId; + + /// + /// TRUE if the media is removable; otherwise, FALSE. + /// + BOOLEAN RemovableMedia; + + /// + /// TRUE if there is a media currently present in the device; + /// othersise, FALSE. THis field shows the media present status + /// as of the most recent ReadBlocks() or WriteBlocks() call. + /// + BOOLEAN MediaPresent; + + /// + /// TRUE if LBA 0 is the first block of a partition; otherwise + /// FALSE. For media with only one partition this would be TRUE. + /// + BOOLEAN LogicalPartition; + + /// + /// TRUE if the media is marked read-only otherwise, FALSE. + /// This field shows the read-only status as of the most recent WriteBlocks () call. + /// + BOOLEAN ReadOnly; + + /// + /// TRUE if the WriteBlock () function caches write data. + /// + BOOLEAN WriteCaching; + + /// + /// The intrinsic block size of the device. If the media changes, then + /// this field is updated. + /// + UINT32 BlockSize; + + /// + /// Supplies the alignment requirement for any buffer to read or write block(s). + /// + UINT32 IoAlign; + + /// + /// The last logical block address on the device. + /// If the media changes, then this field is updated. + /// + EFI_LBA LastBlock; + + /// + /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to + /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the first LBA is aligned to + /// a physical block boundary. + /// + EFI_LBA LowestAlignedLba; + + /// + /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to + /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the number of logical blocks + /// per physical block. + /// + UINT32 LogicalBlocksPerPhysicalBlock; + + /// + /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to + /// EFI_BLOCK_IO_PROTOCOL_REVISION3. Returns the optimal transfer length + /// granularity as a number of logical blocks. + /// + UINT32 OptimalTransferLengthGranularity; +} EFI_BLOCK_IO_MEDIA; + +#define EFI_BLOCK_IO_PROTOCOL_REVISION 0x00010000 +#define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001 +#define EFI_BLOCK_IO_PROTOCOL_REVISION3 0x00020031 + +/// +/// Revision defined in EFI1.1. +/// +#define EFI_BLOCK_IO_INTERFACE_REVISION EFI_BLOCK_IO_PROTOCOL_REVISION + +/// +/// This protocol provides control over block devices. +/// +struct _EFI_BLOCK_IO_PROTOCOL { + /// + /// The revision to which the block IO interface adheres. All future + /// revisions must be backwards compatible. If a future version is not + /// back wards compatible, it is not the same GUID. + /// + UINT64 Revision; + /// + /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device. + /// + EFI_BLOCK_IO_MEDIA *Media; + + EFI_BLOCK_RESET Reset; + EFI_BLOCK_READ ReadBlocks; + EFI_BLOCK_WRITE WriteBlocks; + EFI_BLOCK_FLUSH FlushBlocks; + +}; + +extern EFI_GUID gEfiBlockIoProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo.h b/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo.h deleted file mode 100644 index 39b82b3bc..000000000 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo.h +++ /dev/null @@ -1,48 +0,0 @@ -/** @file - This code abstracts the CPU IO Protocol which installed by some platform or chipset-specific - PEIM that abstracts the processor-visible I/O operations. - - Note: This is a runtime protocol and can be used by runtime drivers after ExitBootServices(). - It is different from the PI 1.2 CPU I/O 2 Protocol, which is a boot services only protocol - and may not be used by runtime drivers after ExitBootServices(). - -Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> -This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - @par Revision Reference: - CPU IO Protocol is defined in Framework of EFI CPU IO Protocol Spec - Version 0.9. - -**/ - -#ifndef _CPUIO_H_ -#define _CPUIO_H_ - -FILE_LICENCE ( BSD3 ); - -#include <ipxe/efi/Protocol/CpuIo2.h> - -#define EFI_CPU_IO_PROTOCOL_GUID \ - { \ - 0xB0732526, 0x38C8, 0x4b40, {0x88, 0x77, 0x61, 0xC7, 0xB0, 0x6A, 0xAC, 0x45 } \ - } - -// -// Framework CPU IO protocol structure is the same as CPU IO 2 protocol defined in PI 1.2 spec. -// However, there is a significant different between the Framework CPU I/O -// Protocol and the PI 1.2 CPU I/O 2 Protocol. The Framework one is a runtime -// protocol, which means it can be used by runtime drivers after ExitBootServices(). -// The PI one is not runtime safe, so it is a boot services only protocol and may -// not be used by runtime drivers after ExitBootServices(). -// -typedef EFI_CPU_IO2_PROTOCOL EFI_CPU_IO_PROTOCOL; - -extern EFI_GUID gEfiCpuIoProtocolGuid; - -#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h b/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h deleted file mode 100644 index aef8157d8..000000000 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/CpuIo2.h +++ /dev/null @@ -1,144 +0,0 @@ -/** @file - This files describes the CPU I/O 2 Protocol. - - This protocol provides an I/O abstraction for a system processor. This protocol - is used by a PCI root bridge I/O driver to perform memory-mapped I/O and I/O transactions. - The I/O or memory primitives can be used by the consumer of the protocol to materialize - bus-specific configuration cycles, such as the transitional configuration address and data - ports for PCI. Only drivers that require direct access to the entire system should use this - protocol. - - Note: This is a boot-services only protocol and it may not be used by runtime drivers after - ExitBootServices(). It is different from the Framework CPU I/O Protocol, which is a runtime - protocol and can be used by runtime drivers after ExitBootServices(). - - Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - @par Revision Reference: - This Protocol is defined in UEFI Platform Initialization Specification 1.2 - Volume 5: Standards - -**/ - -#ifndef __CPU_IO2_H__ -#define __CPU_IO2_H__ - -FILE_LICENCE ( BSD3 ); - -#define EFI_CPU_IO2_PROTOCOL_GUID \ - { \ - 0xad61f191, 0xae5f, 0x4c0e, {0xb9, 0xfa, 0xe8, 0x69, 0xd2, 0x88, 0xc6, 0x4f} \ - } - -typedef struct _EFI_CPU_IO2_PROTOCOL EFI_CPU_IO2_PROTOCOL; - -/// -/// Enumeration that defines the width of the I/O operation. -/// -typedef enum { - EfiCpuIoWidthUint8, - EfiCpuIoWidthUint16, - EfiCpuIoWidthUint32, - EfiCpuIoWidthUint64, - EfiCpuIoWidthFifoUint8, - EfiCpuIoWidthFifoUint16, - EfiCpuIoWidthFifoUint32, - EfiCpuIoWidthFifoUint64, - EfiCpuIoWidthFillUint8, - EfiCpuIoWidthFillUint16, - EfiCpuIoWidthFillUint32, - EfiCpuIoWidthFillUint64, - EfiCpuIoWidthMaximum -} EFI_CPU_IO_PROTOCOL_WIDTH; - -/** - Enables a driver to access registers in the PI CPU I/O space. - - The Io.Read() and Io.Write() functions enable a driver to access PCI controller - registers in the PI CPU I/O space. - - The I/O operations are carried out exactly as requested. The caller is responsible - for satisfying any alignment and I/O width restrictions that a PI System on a - platform might require. For example on some platforms, width requests of - EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will - be handled by the driver. - - If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, - or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for - each of the Count operations that is performed. - - If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, - EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is - incremented for each of the Count operations that is performed. The read or - write operation is performed Count times on the same Address. - - If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, - EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is - incremented for each of the Count operations that is performed. The read or - write operation is performed Count times from the first element of Buffer. - - @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. - @param[in] Width Signifies the width of the I/O or Memory operation. - @param[in] Address The base address of the I/O operation. - @param[in] Count The number of I/O operations to perform. The number - of bytes moved is Width size * Count, starting at Address. - @param[in, out] Buffer For read operations, the destination buffer to store the results. - For write operations, the source buffer from which to write data. - - @retval EFI_SUCCESS The data was read from or written to the PI system. - @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. - @retval EFI_INVALID_PARAMETER Buffer is NULL. - @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. - @retval EFI_UNSUPPORTED The address range specified by Address, Width, - and Count is not valid for this PI system. - -**/ -typedef -EFI_STATUS -(EFIAPI *EFI_CPU_IO_PROTOCOL_IO_MEM)( - IN EFI_CPU_IO2_PROTOCOL *This, - IN EFI_CPU_IO_PROTOCOL_WIDTH Width, - IN UINT64 Address, - IN UINTN Count, - IN OUT VOID *Buffer - ); - -/// -/// Service for read and write accesses. -/// -typedef struct { - /// - /// This service provides the various modalities of memory and I/O read. - /// - EFI_CPU_IO_PROTOCOL_IO_MEM Read; - /// - /// This service provides the various modalities of memory and I/O write. - /// - EFI_CPU_IO_PROTOCOL_IO_MEM Write; -} EFI_CPU_IO_PROTOCOL_ACCESS; - -/// -/// Provides the basic memory and I/O interfaces that are used to abstract -/// accesses to devices in a system. -/// -struct _EFI_CPU_IO2_PROTOCOL { - /// - /// Enables a driver to access memory-mapped registers in the EFI system memory space. - /// - EFI_CPU_IO_PROTOCOL_ACCESS Mem; - /// - /// Enables a driver to access registers in the EFI CPU I/O space. - /// - EFI_CPU_IO_PROTOCOL_ACCESS Io; -}; - -extern EFI_GUID gEfiCpuIo2ProtocolGuid; - -#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePathToText.h b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePathToText.h new file mode 100644 index 000000000..edca965bc --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePathToText.h @@ -0,0 +1,87 @@ +/** @file + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL as defined in UEFI 2.0. + This protocol provides service to convert device nodes and paths to text. + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DEVICE_PATH_TO_TEXT_PROTOCOL_H__ +#define __DEVICE_PATH_TO_TEXT_PROTOCOL_H__ + +FILE_LICENCE ( BSD3 ); + +/// +/// Device Path To Text protocol +/// +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { \ + 0x8b843e20, 0x8132, 0x4852, {0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } \ + } + +/** + Convert a device node to its text representation. + + @param DeviceNode Points to the device node to be converted. + @param DisplayOnly If DisplayOnly is TRUE, then the shorter text representation + of the display node is used, where applicable. If DisplayOnly + is FALSE, then the longer text representation of the display node + is used. + @param AllowShortcuts If AllowShortcuts is TRUE, then the shortcut forms of text + representation for a device node can be used, where applicable. + + @retval a_pointer a pointer to the allocated text representation of the device node data + @retval NULL if DeviceNode is NULL or there was insufficient memory. + +**/ +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE)( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DeviceNode, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortcuts + ); + +/** + Convert a device path to its text representation. + + @param DevicePath Points to the device path to be converted. + @param DisplayOnly If DisplayOnly is TRUE, then the shorter text representation + of the display node is used, where applicable. If DisplayOnly + is FALSE, then the longer text representation of the display node + is used. + @param AllowShortcuts The AllowShortcuts is FALSE, then the shortcut forms of + text representation for a device node cannot be used. + + @retval a_pointer a pointer to the allocated text representation of the device node. + @retval NULL if DevicePath is NULL or there was insufficient memory. + +**/ +typedef +CHAR16* +(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH)( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN BOOLEAN DisplayOnly, + IN BOOLEAN AllowShortcuts + ); + +/// +/// This protocol converts device paths and device nodes to text. +/// +typedef struct { + EFI_DEVICE_PATH_TO_TEXT_NODE ConvertDeviceNodeToText; + EFI_DEVICE_PATH_TO_TEXT_PATH ConvertDevicePathToText; +} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL; + +extern EFI_GUID gEfiDevicePathToTextProtocolGuid; + +#endif + + diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h new file mode 100644 index 000000000..198180864 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h @@ -0,0 +1,403 @@ +/** @file + SimpleFileSystem protocol as defined in the UEFI 2.0 specification. + + The SimpleFileSystem protocol is the programmatic access to the FAT (12,16,32) + file system specified in UEFI 2.0. It can also be used to abstract a file + system other than FAT. + + UEFI 2.0 can boot from any valid EFI image contained in a SimpleFileSystem. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SIMPLE_FILE_SYSTEM_H__ +#define __SIMPLE_FILE_SYSTEM_H__ + +FILE_LICENCE ( BSD3 ); + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + { \ + 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; + +typedef struct _EFI_FILE_PROTOCOL EFI_FILE_PROTOCOL; +typedef struct _EFI_FILE_PROTOCOL *EFI_FILE_HANDLE; + +/// +/// Protocol GUID name defined in EFI1.1. +/// +#define SIMPLE_FILE_SYSTEM_PROTOCOL EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID + +/// +/// Protocol name defined in EFI1.1. +/// +typedef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL EFI_FILE_IO_INTERFACE; +typedef EFI_FILE_PROTOCOL EFI_FILE; + +/** + Open the root directory on a volume. + + @param This A pointer to the volume to open the root directory. + @param Root A pointer to the location to return the opened file handle for the + root directory. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_UNSUPPORTED This volume does not support the requested file system type. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. Any existing file handles for this volume are + no longer valid. To access the files on the new medium, the + volume must be reopened with OpenVolume(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ); + +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000 + +/// +/// Revision defined in EFI1.1 +/// +#define EFI_FILE_IO_INTERFACE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION + +struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL { + /// + /// The version of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. The version + /// specified by this specification is 0x00010000. All future revisions + /// must be backwards compatible. + /// + UINT64 Revision; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume; +}; + +/** + Opens a new file relative to the source file's location. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to the source location. This would typically be an open + handle to a directory. + @param NewHandle A pointer to the location to return the opened handle for the new + file. + @param FileName The Null-terminated string of the name of the file to be opened. + The file name may contain the following path modifiers: "\", ".", + and "..". + @param OpenMode The mode to open the file. The only valid combinations that the + file may be opened with are: Read, Read/Write, or Create/Read/Write. + @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the + attribute bits for the newly created file. + + @retval EFI_SUCCESS The file was opened. + @retval EFI_NOT_FOUND The specified file could not be found on the device. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_OPEN)( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +// +// Open modes +// +#define EFI_FILE_MODE_READ 0x0000000000000001ULL +#define EFI_FILE_MODE_WRITE 0x0000000000000002ULL +#define EFI_FILE_MODE_CREATE 0x8000000000000000ULL + +// +// File attributes +// +#define EFI_FILE_READ_ONLY 0x0000000000000001ULL +#define EFI_FILE_HIDDEN 0x0000000000000002ULL +#define EFI_FILE_SYSTEM 0x0000000000000004ULL +#define EFI_FILE_RESERVED 0x0000000000000008ULL +#define EFI_FILE_DIRECTORY 0x0000000000000010ULL +#define EFI_FILE_ARCHIVE 0x0000000000000020ULL +#define EFI_FILE_VALID_ATTR 0x0000000000000037ULL + +/** + Closes a specified file handle. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to close. + + @retval EFI_SUCCESS The file was closed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_CLOSE)( + IN EFI_FILE_PROTOCOL *This + ); + +/** + Close and delete the file handle. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the + handle to the file to delete. + + @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed. + @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_DELETE)( + IN EFI_FILE_PROTOCOL *This + ); + +/** + Reads data from a file. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to read data from. + @param BufferSize On input, the size of the Buffer. On output, the amount of data + returned in Buffer. In both cases, the size is measured in bytes. + @param Buffer The buffer into which the data is read. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. + @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL The BufferSize is too small to read the current directory + entry. BufferSize has been updated with the size + needed to complete the request. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_READ)( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +/** + Writes data to a file. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to write data to. + @param BufferSize On input, the size of the Buffer. On output, the amount of data + actually written. In both cases, the size is measured in bytes. + @param Buffer The buffer of data to write. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to open directory files are not supported. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write-protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_WRITE)( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +/** + Sets a file's current position. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the + file handle to set the requested position on. + @param Position The byte position from the start of the file to set. + + @retval EFI_SUCCESS The position was set. + @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open + directories. + @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_POSITION)( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ); + +/** + Returns a file's current position. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to get the current position on. + @param Position The address to return the file's current position value. + + @retval EFI_SUCCESS The position was returned. + @retval EFI_UNSUPPORTED The request is not valid on open directories. + @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_POSITION)( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ); + +/** + Returns information about a file. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle the requested information is for. + @param InformationType The type identifier for the information being requested. + @param BufferSize On input, the size of Buffer. On output, the amount of data + returned in Buffer. In both cases, the size is measured in bytes. + @param Buffer A pointer to the data buffer to return. The buffer's type is + indicated by InformationType. + + @retval EFI_SUCCESS The information was returned. + @retval EFI_UNSUPPORTED The InformationType is not known. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. + BufferSize has been updated with the size needed to complete + the request. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_GET_INFO)( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +/** + Sets information about a file. + + @param File A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle the information is for. + @param InformationType The type identifier for the information being set. + @param BufferSize The size, in bytes, of Buffer. + @param Buffer A pointer to the data buffer to write. The buffer's type is + indicated by InformationType. + + @retval EFI_SUCCESS The information was set. + @retval EFI_UNSUPPORTED The InformationType is not known. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the media is + read-only. + @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID + and the media is read only. + @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID + and the media is read-only. + @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file to a + file that is already present. + @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_FILE_DIRECTORY + Attribute. + @retval EFI_ACCESS_DENIED An attempt is being made to change the size of a directory. + @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the file was opened + read-only and an attempt is being made to modify a field + other than Attribute. + @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type indicated + by InformationType. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_SET_INFO)( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flushes all modified data associated with a file to a device. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to flush. + + @retval EFI_SUCCESS The data was flushed. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The file or medium is write-protected. + @retval EFI_ACCESS_DENIED The file was opened read-only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_FILE_FLUSH)( + IN EFI_FILE_PROTOCOL *This + ); + +#define EFI_FILE_PROTOCOL_REVISION 0x00010000 +// +// Revision defined in EFI1.1. +// +#define EFI_FILE_REVISION EFI_FILE_PROTOCOL_REVISION + +/// +/// The EFI_FILE_PROTOCOL provides file IO access to supported file systems. +/// An EFI_FILE_PROTOCOL provides access to a file's or directory's contents, +/// and is also a reference to a location in the directory tree of the file system +/// in which the file resides. With any given file handle, other files may be opened +/// relative to this file's location, yielding new file handles. +/// +struct _EFI_FILE_PROTOCOL { + /// + /// The version of the EFI_FILE_PROTOCOL interface. The version specified + /// by this specification is 0x00010000. Future versions are required + /// to be backward compatible to version 1.0. + /// + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; +}; + + +extern EFI_GUID gEfiSimpleFileSystemProtocolGuid; + +#endif diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h index 71d3463bf..9a9f5ab59 100644 --- a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h +++ b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h @@ -5,7 +5,7 @@ which exposes much more state and modifier information from the input device, also allows one to register a notification for a particular keystroke. - Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -276,7 +276,7 @@ EFI_STATUS IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, IN EFI_KEY_DATA *KeyData, IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - OUT EFI_HANDLE *NotifyHandle + OUT VOID **NotifyHandle ); /** @@ -298,7 +298,7 @@ typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)( IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - IN EFI_HANDLE NotificationHandle + IN VOID *NotificationHandle ); diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h index fb20d763a..e792473c1 100644 --- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h +++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h @@ -887,9 +887,9 @@ typedef struct _EFI_IFR_IMAGE { EFI_IMAGE_ID Id; } EFI_IFR_IMAGE; -typedef struct _EFI_IFR_MODAL { +typedef struct _EFI_IFR_MODAL_TAG { EFI_IFR_OP_HEADER Header; -} EFI_IFR_MODAL; +} EFI_IFR_MODAL_TAG; typedef struct _EFI_IFR_LOCKED { EFI_IFR_OP_HEADER Header; @@ -907,6 +907,12 @@ typedef struct _EFI_IFR_DEFAULT { EFI_IFR_TYPE_VALUE Value; } EFI_IFR_DEFAULT; +typedef struct _EFI_IFR_DEFAULT_2 { + EFI_IFR_OP_HEADER Header; + UINT16 DefaultId; + UINT8 Type; +} EFI_IFR_DEFAULT_2; + typedef struct _EFI_IFR_VALUE { EFI_IFR_OP_HEADER Header; } EFI_IFR_VALUE; diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h index 4887157cc..141bccd75 100644 --- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h +++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h @@ -283,7 +283,9 @@ EFI_STATUS @retval EFI_NOT_FOUND 1) There are no EFI_DRIVER_BINDING_PROTOCOL instances present in the system. 2) No drivers were connected to ControllerHandle. - + @retval EFI_SECURITY_VIOLATION + The user has no permission to start UEFI device drivers on the device path + associated with the ControllerHandle or specified by the RemainingDevicePath. **/ typedef EFI_STATUS @@ -850,8 +852,9 @@ EFI_STATUS @param ExitData The pointer to a pointer to a data buffer that includes a Null-terminated string, optionally followed by additional binary data. - @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle or the image - has already been initialized with StartImage. + @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle or the image + has already been initialized with StartImage. + @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started. @return Exit code from image **/ @@ -1138,8 +1141,8 @@ EFI_STATUS /** Installs one or more protocol interfaces into the boot services environment. - @param Handle The handle to install the new protocol interfaces on, or NULL if a new - handle is to be allocated. + @param Handle The pointer to a handle to install the new protocol interfaces on, + or a pointer to NULL if a new handle is to be allocated. @param ... A variable argument list containing pairs of protocol GUIDs and protocol interfaces. @@ -1722,6 +1725,10 @@ EFI_STATUS OUT UINT64 *MaximumVariableSize ); +// +// Firmware should stop at a firmware user interface on next boot +// +#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001 // // EFI Runtime Services Table @@ -2006,50 +2013,46 @@ EFI_STATUS /// /// EFI Boot Key Data /// -typedef union { - struct { - /// - /// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0. - /// - UINT32 Revision : 8; - /// - /// Either the left or right Shift keys must be pressed (1) or must not be pressed (0). - /// - UINT32 ShiftPressed : 1; - /// - /// Either the left or right Control keys must be pressed (1) or must not be pressed (0). - /// - UINT32 ControlPressed : 1; - /// - /// Either the left or right Alt keys must be pressed (1) or must not be pressed (0). - /// - UINT32 AltPressed : 1; - /// - /// Either the left or right Logo keys must be pressed (1) or must not be pressed (0). - /// - UINT32 LogoPressed : 1; - /// - /// The Menu key must be pressed (1) or must not be pressed (0). - /// - UINT32 MenuPressed : 1; - /// - /// The SysReq key must be pressed (1) or must not be pressed (0). - /// - UINT32 SysReqPressed : 1; - UINT32 Reserved : 16; - /// - /// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If - /// zero, then only the shift state is considered. If more than one, then the boot option will - /// only be launched if all of the specified keys are pressed with the same shift state. - /// - UINT32 InputKeyCount : 2; - } Options; - UINT32 PackedValue; -} EFI_BOOT_KEY_DATA; +typedef UINT32 EFI_BOOT_KEY_DATA; +/// +/// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0. +/// +#define EFI_KEY_OPTION_REVISION_MASK 0x000000FF +/// +/// Either the left or right Shift keys must be pressed (1) or must not be pressed (0). +/// +#define EFI_KEY_OPTION_SHIFT_PRESSED_MASK BIT8 +/// +/// Either the left or right Control keys must be pressed (1) or must not be pressed (0). +/// +#define EFI_KEY_OPTION_CONTROL_PRESSED_MASK BIT9 +/// +/// Either the left or right Alt keys must be pressed (1) or must not be pressed (0). +/// +#define EFI_KEY_OPTION_ALT_PRESSED_MASK BIT10 +/// +/// Either the left or right Logo keys must be pressed (1) or must not be pressed (0). +/// +#define EFI_KEY_OPTION_LOGO_PRESSED_MASK BIT11 +/// +/// The Menu key must be pressed (1) or must not be pressed (0). +/// +#define EFI_KEY_OPTION_MENU_PRESSED_MASK BIT12 +/// +/// The SysReq key must be pressed (1) or must not be pressed (0). +/// +#define EFI_KEY_OPTION_SYS_REQ_PRESSED_MASK BIT13 +/// +/// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If +/// zero, then only the shift state is considered. If more than one, then the boot option will +/// only be launched if all of the specified keys are pressed with the same shift state. +/// +#define EFI_KEY_OPTION_INPUT_KEY_COUNT_MASK (BIT30 | BIT31) /// /// EFI Key Option. /// +#pragma pack(1) typedef struct { /// /// Specifies options about how the key will be processed. @@ -2073,6 +2076,7 @@ typedef struct { /// //EFI_INPUT_KEY Keys[]; } EFI_KEY_OPTION; +#pragma pack() // // EFI File location to boot from on removable media devices diff --git a/roms/ipxe/src/include/ipxe/efi/efi.h b/roms/ipxe/src/include/ipxe/efi/efi.h index b5ce7df9e..a98b5588d 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi.h +++ b/roms/ipxe/src/include/ipxe/efi/efi.h @@ -21,6 +21,8 @@ * trailing whitespace. */ +FILE_LICENCE ( GPL2_OR_LATER ); + /* EFI headers rudely redefine NULL */ #undef NULL @@ -54,12 +56,7 @@ /** An EFI protocol used by iPXE */ struct efi_protocol { /** GUID */ - union { - /** EFI protocol GUID */ - EFI_GUID guid; - /** UUID structure understood by iPXE */ - union uuid uuid; - } u; + EFI_GUID guid; /** Variable containing pointer to protocol structure */ void **protocol; }; @@ -77,7 +74,7 @@ struct efi_protocol { */ #define EFI_REQUIRE_PROTOCOL( _protocol, _ptr ) \ struct efi_protocol __ ## _protocol __efi_protocol = { \ - .u.guid = _protocol ## _GUID, \ + .guid = _protocol ## _GUID, \ .protocol = ( ( void ** ) ( void * ) \ ( ( (_ptr) == ( ( _protocol ** ) (_ptr) ) ) ? \ (_ptr) : (_ptr) ) ), \ @@ -86,12 +83,7 @@ struct efi_protocol { /** An EFI configuration table used by iPXE */ struct efi_config_table { /** GUID */ - union { - /** EFI configuration table GUID */ - EFI_GUID guid; - /** UUID structure understood by iPXE */ - union uuid uuid; - } u; + EFI_GUID guid; /** Variable containing pointer to configuration table */ void **table; /** Table is required for operation */ @@ -113,36 +105,68 @@ struct efi_config_table { */ #define EFI_USE_TABLE( _table, _ptr, _required ) \ struct efi_config_table __ ## _table __efi_config_table = { \ - .u.guid = _table ## _GUID, \ + .guid = _table ## _GUID, \ .table = ( ( void ** ) ( void * ) (_ptr) ), \ .required = (_required), \ } -/** Convert a iPXE status code to an EFI status code +/** + * Convert an iPXE status code to an EFI status code * - * FIXME: actually perform some kind of conversion. iPXE error codes - * will be detected as EFI error codes; both have the top bit set, and - * the success return code is zero for both. Anything that just - * reports a numerical error will be OK, anything attempting to - * interpret the value or to display a text equivalent will be - * screwed. + * @v rc iPXE status code + * @ret efirc EFI status code */ -#define RC_TO_EFIRC( rc ) (rc) +#define EFIRC( rc ) ERRNO_TO_PLATFORM ( -(rc) ) -/** Convert an EFI status code to a iPXE status code +/** + * Convert an EFI status code to an iPXE status code * - * FIXME: as above + * @v efirc EFI status code + * @ret rc iPXE status code (before negation) */ -#define EFIRC_TO_RC( efirc ) (efirc) +#define EEFI( efirc ) EPLATFORM ( EINFO_EPLATFORM, efirc ) extern EFI_HANDLE efi_image_handle; extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image; +extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; extern EFI_SYSTEM_TABLE *efi_systab; -extern const char * efi_strerror ( EFI_STATUS efirc ); +extern const char * efi_guid_ntoa ( EFI_GUID *guid ); + +extern void dbg_efi_protocols ( EFI_HANDLE handle ); +extern void dbg_efi_devpath ( EFI_DEVICE_PATH_PROTOCOL *path ); + +#define DBG_EFI_PROTOCOLS_IF( level, handle ) do { \ + if ( DBG_ ## level ) { \ + dbg_efi_protocols ( handle ); \ + } \ + } while ( 0 ) + +#define DBG_EFI_DEVPATH_IF( level, path ) do { \ + if ( DBG_ ## level ) { \ + dbg_efi_devpath ( path ); \ + } \ + } while ( 0 ) + +#define DBGC_EFI_PROTOCOLS_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_EFI_PROTOCOLS_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + +#define DBGC_EFI_DEVPATH_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_EFI_DEVPATH_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + +#define DBGC_EFI_PROTOCOLS( ... ) \ + DBGC_EFI_PROTOCOLS_IF( LOG, ##__VA_ARGS__ ) + +#define DBGC_EFI_DEVPATH( ... ) \ + DBGC_EFI_DEVPATH_IF( LOG, ##__VA_ARGS__ ) + extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ); -extern int efi_download_install ( EFI_HANDLE *device_handle ); -extern void efi_download_uninstall ( EFI_HANDLE device_handle ); #endif /* _IPXE_EFI_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/ipxe_download.h b/roms/ipxe/src/include/ipxe/efi/efi_download.h index 22e3cef08..3ce497221 100644 --- a/roms/ipxe/src/include/ipxe/efi/ipxe_download.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_download.h @@ -151,4 +151,7 @@ struct _IPXE_DOWNLOAD_PROTOCOL { 0x3eaeaebd, 0xdecf, 0x493b, { 0x9b, 0xd1, 0xcd, 0xb2, 0xde, 0xca, 0xe7, 0x19 } \ } +extern int efi_download_install ( EFI_HANDLE *device ); +extern void efi_download_uninstall ( EFI_HANDLE device ); + #endif /* _IPXE_DOWNLOAD_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_driver.h b/roms/ipxe/src/include/ipxe/efi/efi_driver.h index e5872ced3..afa574d08 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_driver.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_driver.h @@ -44,6 +44,7 @@ struct efi_driver { extern EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ); -extern EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ); +extern int efi_driver_install ( struct efi_driver *efidrv ); +extern void efi_driver_uninstall ( struct efi_driver *efidrv ); #endif /* _IPXE_EFI_DRIVER_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_file.h b/roms/ipxe/src/include/ipxe/efi/efi_file.h new file mode 100644 index 000000000..0d75cf5b0 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/efi_file.h @@ -0,0 +1,13 @@ +#ifndef _IPXE_EFI_FILE_H +#define _IPXE_EFI_FILE_H + +/** @file + * + * EFI file protocols + * + */ + +extern int efi_file_install ( EFI_HANDLE *handle ); +extern void efi_file_uninstall ( EFI_HANDLE handle ); + +#endif /* _IPXE_EFI_FILE_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_io.h b/roms/ipxe/src/include/ipxe/efi/efi_io.h deleted file mode 100644 index 2ed96e10d..000000000 --- a/roms/ipxe/src/include/ipxe/efi/efi_io.h +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef _IPXE_EFI_IO_H -#define _IPXE_EFI_IO_H - -/** @file - * - * iPXE I/O API for EFI - * - * EFI runs with flat physical addressing, so the various mappings - * between virtual addresses, I/O addresses and bus addresses are all - * no-ops. I/O is handled using the EFI_CPU_IO_PROTOCOL. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifdef IOAPI_EFI -#define IOAPI_PREFIX_efi -#else -#define IOAPI_PREFIX_efi __efi_ -#endif - -extern unsigned long long efi_ioread ( volatile void *io_addr, - size_t size ); -extern void efi_iowrite ( unsigned long long data, volatile void *io_addr, - size_t size ); -extern void efi_ioreads ( volatile void *io_addr, void *data, - size_t size, unsigned int count ); -extern void efi_iowrites ( volatile void *io_addr, const void *data, - size_t size, unsigned int count ); - -/* - * Physical<->Bus and Bus<->I/O address mappings - * - * EFI runs with flat physical addressing, so these are all no-ops. - * - */ - -static inline __always_inline unsigned long -IOAPI_INLINE ( efi, phys_to_bus ) ( unsigned long phys_addr ) { - return phys_addr; -} - -static inline __always_inline unsigned long -IOAPI_INLINE ( efi, bus_to_phys ) ( unsigned long bus_addr ) { - return bus_addr; -} - -static inline __always_inline void * -IOAPI_INLINE ( efi, ioremap ) ( unsigned long bus_addr, size_t len __unused ) { - return ( ( void * ) bus_addr ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, iounmap ) ( volatile const void *io_addr __unused ) { - /* Nothing to do */ -} - -static inline __always_inline unsigned long -IOAPI_INLINE ( efi, io_to_bus ) ( volatile const void *io_addr ) { - return ( ( unsigned long ) io_addr ); -} - -/* - * I/O functions - * - */ - -static inline __always_inline uint8_t -IOAPI_INLINE ( efi, readb ) ( volatile uint8_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline uint16_t -IOAPI_INLINE ( efi, readw ) ( volatile uint16_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline uint32_t -IOAPI_INLINE ( efi, readl ) ( volatile uint32_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline uint64_t -IOAPI_INLINE ( efi, readq ) ( volatile uint64_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, writeb ) ( uint8_t data, volatile uint8_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, writew ) ( uint16_t data, volatile uint16_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, writel ) ( uint32_t data, volatile uint32_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, writeq ) ( uint64_t data, volatile uint64_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline uint8_t -IOAPI_INLINE ( efi, inb ) ( volatile uint8_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline uint16_t -IOAPI_INLINE ( efi, inw ) ( volatile uint16_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline uint32_t -IOAPI_INLINE ( efi, inl ) ( volatile uint32_t *io_addr ) { - return efi_ioread ( io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, outb ) ( uint8_t data, volatile uint8_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, outw ) ( uint16_t data, volatile uint16_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, outl ) ( uint32_t data, volatile uint32_t *io_addr ) { - efi_iowrite ( data, io_addr, sizeof ( *io_addr ) ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, insb ) ( volatile uint8_t *io_addr, uint8_t *data, - unsigned int count ) { - efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, insw ) ( volatile uint16_t *io_addr, uint16_t *data, - unsigned int count ) { - efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, insl ) ( volatile uint32_t *io_addr, uint32_t *data, - unsigned int count ) { - efi_ioreads ( io_addr, data, sizeof ( *io_addr ), count ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, outsb ) ( volatile uint8_t *io_addr, const uint8_t *data, - unsigned int count ) { - efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, outsw ) ( volatile uint16_t *io_addr, const uint16_t *data, - unsigned int count ) { - efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, outsl ) ( volatile uint32_t *io_addr, const uint32_t *data, - unsigned int count ) { - efi_iowrites ( io_addr, data, sizeof ( *io_addr ), count ); -} - -static inline __always_inline void -IOAPI_INLINE ( efi, mb ) ( void ) { - /* Do nothing; EFI readl()/writel() calls already act as - * memory barriers. - */ -} - -#endif /* _IPXE_EFI_IO_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_pci.h b/roms/ipxe/src/include/ipxe/efi/efi_pci.h index 6429f2109..e6b319709 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_pci.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_pci.h @@ -38,11 +38,11 @@ struct efi_pci_device { extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, EFI_HANDLE device ); -extern EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ); +extern int efipci_enable ( struct efi_pci_device *efipci ); extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device ); extern struct efi_pci_device * efipci_find ( struct device *dev ); -extern EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci, - EFI_HANDLE device ); +extern int efipci_child_add ( struct efi_pci_device *efipci, + EFI_HANDLE device ); extern void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ); extern void efipci_destroy ( struct efi_driver *efidrv, diff --git a/roms/ipxe/src/include/ipxe/efi/efi_reboot.h b/roms/ipxe/src/include/ipxe/efi/efi_reboot.h new file mode 100644 index 000000000..33921b913 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/efi/efi_reboot.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_EFI_REBOOT_H +#define _IPXE_EFI_REBOOT_H + +/** @file + * + * iPXE reboot API for EFI + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#ifdef REBOOT_EFI +#define REBOOT_PREFIX_efi +#else +#define REBOOT_PREFIX_efi __efi_ +#endif + +#endif /* _IPXE_EFI_REBOOT_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_snp.h b/roms/ipxe/src/include/ipxe/efi/efi_snp.h index c86760908..e1b866eb8 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_snp.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_snp.h @@ -16,6 +16,7 @@ #include <ipxe/efi/Protocol/DevicePath.h> #include <ipxe/efi/Protocol/HiiConfigAccess.h> #include <ipxe/efi/Protocol/HiiDatabase.h> +#include <ipxe/efi/Protocol/LoadFile.h> /** An SNP device */ struct efi_snp_device { @@ -31,6 +32,8 @@ struct efi_snp_device { EFI_SIMPLE_NETWORK_PROTOCOL snp; /** The SNP "mode" (parameters) */ EFI_SIMPLE_NETWORK_MODE mode; + /** Started flag */ + int started; /** Outstanding TX packet count (via "interrupt status") * * Used in order to generate TX completions. @@ -49,6 +52,8 @@ struct efi_snp_device { EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii; /** Component name protocol */ EFI_COMPONENT_NAME2_PROTOCOL name2; + /** Load file protocol handle */ + EFI_LOAD_FILE_PROTOCOL load_file; /** HII configuration access protocol */ EFI_HII_CONFIG_ACCESS_PROTOCOL hii; /** HII package list */ @@ -71,5 +76,8 @@ struct efi_snp_device { extern int efi_snp_hii_install ( struct efi_snp_device *snpdev ); extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ); +extern struct efi_snp_device * last_opened_snpdev ( void ); +extern void efi_snp_claim ( void ); +extern void efi_snp_release ( void ); #endif /* _IPXE_EFI_SNP_H */ diff --git a/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h b/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h index 79c18972e..870a089b2 100644 --- a/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h +++ b/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h @@ -76,6 +76,13 @@ UACCESS_INLINE ( efi, memmove_user ) ( userptr_t dest, off_t dest_off, trivial_memmove_user ( dest, dest_off, src, src_off, len ); } +static inline __always_inline int +UACCESS_INLINE ( efi, memcmp_user ) ( userptr_t first, off_t first_off, + userptr_t second, off_t second_off, + size_t len ) { + return trivial_memcmp_user ( first, first_off, second, second_off, len); +} + static inline __always_inline void UACCESS_INLINE ( efi, memset_user ) ( userptr_t buffer, off_t offset, int c, size_t len ) { diff --git a/roms/ipxe/src/include/ipxe/efi/import.pl b/roms/ipxe/src/include/ipxe/efi/import.pl index 2b5d3e939..995514681 100755 --- a/roms/ipxe/src/include/ipxe/efi/import.pl +++ b/roms/ipxe/src/include/ipxe/efi/import.pl @@ -59,6 +59,7 @@ sub try_import_file { open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n"; my @dependencies = (); my $licence; + my $maybe_guard; my $guard; while ( <$infh> ) { # Strip CR and trailing whitespace @@ -77,10 +78,16 @@ sub try_import_file { # Write out line print $outfh "$_\n"; # Apply FILE_LICENCE() immediately after include guard - if ( /^\#define\s+_?_\S+_H_?_$/ ) { - die "Duplicate header guard detected in $infile\n" if $guard; - $guard = 1; - print $outfh "\nFILE_LICENCE ( $licence );\n" if $licence; + if ( defined $maybe_guard ) { + if ( /^\#define\s+_?_${maybe_guard}_?_$/ ) { + die "Duplicate header guard detected in $infile\n" if $guard; + $guard = $maybe_guard; + print $outfh "\nFILE_LICENCE ( $licence );\n" if $licence; + } + undef $maybe_guard; + } + if ( /^#ifndef\s+_?_(\S+)_?_/ ) { + $maybe_guard = $1; } } close $outfh; diff --git a/roms/ipxe/src/include/ipxe/eltorito.h b/roms/ipxe/src/include/ipxe/eltorito.h new file mode 100644 index 000000000..3302b38b6 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/eltorito.h @@ -0,0 +1,103 @@ +#ifndef _IPXE_ELTORITO_H +#define _IPXE_ELTORITO_H + +/** + * @file + * + * El Torito bootable CD-ROM specification + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/iso9660.h> + +/** An El Torito Boot Record Volume Descriptor (fixed portion) */ +struct eltorito_descriptor_fixed { + /** Descriptor type */ + uint8_t type; + /** Identifier ("CD001") */ + uint8_t id[5]; + /** Version, must be 1 */ + uint8_t version; + /** Boot system indicator; must be "EL TORITO SPECIFICATION" */ + uint8_t system_id[32]; +} __attribute__ (( packed )); + +/** An El Torito Boot Record Volume Descriptor */ +struct eltorito_descriptor { + /** Fixed portion */ + struct eltorito_descriptor_fixed fixed; + /** Unused */ + uint8_t unused[32]; + /** Boot catalog sector */ + uint32_t sector; +} __attribute__ (( packed )); + +/** El Torito Boot Record Volume Descriptor block address */ +#define ELTORITO_LBA 17 + +/** An El Torito Boot Catalog Validation Entry */ +struct eltorito_validation_entry { + /** Header ID; must be 1 */ + uint8_t header_id; + /** Platform ID + * + * 0 = 80x86 + * 1 = PowerPC + * 2 = Mac + */ + uint8_t platform_id; + /** Reserved */ + uint16_t reserved; + /** ID string */ + uint8_t id_string[24]; + /** Checksum word */ + uint16_t checksum; + /** Signature; must be 0xaa55 */ + uint16_t signature; +} __attribute__ (( packed )); + +/** El Torito platform IDs */ +enum eltorito_platform_id { + ELTORITO_PLATFORM_X86 = 0x00, + ELTORITO_PLATFORM_POWERPC = 0x01, + ELTORITO_PLATFORM_MAC = 0x02, +}; + +/** A bootable entry in the El Torito Boot Catalog */ +struct eltorito_boot_entry { + /** Boot indicator + * + * Must be @c ELTORITO_BOOTABLE for a bootable ISO image + */ + uint8_t indicator; + /** Media type + * + */ + uint8_t media_type; + /** Load segment */ + uint16_t load_segment; + /** System type */ + uint8_t filesystem; + /** Unused */ + uint8_t reserved_a; + /** Sector count */ + uint16_t length; + /** Starting sector */ + uint32_t start; + /** Unused */ + uint8_t reserved_b[20]; +} __attribute__ (( packed )); + +/** Boot indicator for a bootable ISO image */ +#define ELTORITO_BOOTABLE 0x88 + +/** El Torito media types */ +enum eltorito_media_type { + /** No emulation */ + ELTORITO_NO_EMULATION = 0, +}; + +#endif /* _IPXE_ELTORITO_H */ diff --git a/roms/ipxe/src/include/ipxe/errfile.h b/roms/ipxe/src/include/ipxe/errfile.h index 514e1f8ae..bd12c7cbe 100644 --- a/roms/ipxe/src/include/ipxe/errfile.h +++ b/roms/ipxe/src/include/ipxe/errfile.h @@ -63,6 +63,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_test ( ERRFILE_CORE | 0x00170000 ) #define ERRFILE_xferbuf ( ERRFILE_CORE | 0x00180000 ) #define ERRFILE_pending ( ERRFILE_CORE | 0x00190000 ) +#define ERRFILE_null_reboot ( ERRFILE_CORE | 0x001a0000 ) +#define ERRFILE_pinger ( ERRFILE_CORE | 0x001b0000 ) +#define ERRFILE_fbcon ( ERRFILE_CORE | 0x001c0000 ) +#define ERRFILE_ansicol ( ERRFILE_CORE | 0x001d0000 ) +#define ERRFILE_ansicoldef ( ERRFILE_CORE | 0x001e0000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) @@ -113,8 +118,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_sundance ( ERRFILE_DRIVER | 0x00410000 ) #define ERRFILE_tlan ( ERRFILE_DRIVER | 0x00420000 ) #define ERRFILE_tulip ( ERRFILE_DRIVER | 0x00430000 ) -#define ERRFILE_via_rhine ( ERRFILE_DRIVER | 0x00440000 ) -#define ERRFILE_via_velocity ( ERRFILE_DRIVER | 0x00450000 ) +#define ERRFILE_rhine ( ERRFILE_DRIVER | 0x00440000 ) +#define ERRFILE_velocity ( ERRFILE_DRIVER | 0x00450000 ) #define ERRFILE_w89c840 ( ERRFILE_DRIVER | 0x00460000 ) #define ERRFILE_ipoib ( ERRFILE_DRIVER | 0x00470000 ) #define ERRFILE_e1000_main ( ERRFILE_DRIVER | 0x00480000 ) @@ -148,6 +153,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_skeleton ( ERRFILE_DRIVER | 0x00640000 ) #define ERRFILE_intel ( ERRFILE_DRIVER | 0x00650000 ) #define ERRFILE_myson ( ERRFILE_DRIVER | 0x00660000 ) +#define ERRFILE_intelx ( ERRFILE_DRIVER | 0x00670000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) @@ -182,7 +188,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_slam ( ERRFILE_NET | 0x00160000 ) #define ERRFILE_ib_sma ( ERRFILE_NET | 0x00170000 ) #define ERRFILE_ib_packet ( ERRFILE_NET | 0x00180000 ) -#define ERRFILE_icmp ( ERRFILE_NET | 0x00190000 ) +#define ERRFILE_icmpv4 ( ERRFILE_NET | 0x00190000 ) #define ERRFILE_ib_qset ( ERRFILE_NET | 0x001a0000 ) #define ERRFILE_ib_gma ( ERRFILE_NET | 0x001b0000 ) #define ERRFILE_ib_pathrec ( ERRFILE_NET | 0x001c0000 ) @@ -206,6 +212,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_fcoe ( ERRFILE_NET | 0x002e0000 ) #define ERRFILE_fcns ( ERRFILE_NET | 0x002f0000 ) #define ERRFILE_vlan ( ERRFILE_NET | 0x00300000 ) +#define ERRFILE_oncrpc ( ERRFILE_NET | 0x00310000 ) +#define ERRFILE_portmap ( ERRFILE_NET | 0x00320000 ) +#define ERRFILE_nfs ( ERRFILE_NET | 0x00330000 ) +#define ERRFILE_nfs_open ( ERRFILE_NET | 0x00340000 ) +#define ERRFILE_mount ( ERRFILE_NET | 0x00350000 ) +#define ERRFILE_oncrpc_iob ( ERRFILE_NET | 0x00360000 ) +#define ERRFILE_neighbour ( ERRFILE_NET | 0x00370000 ) +#define ERRFILE_socket ( ERRFILE_NET | 0x00380000 ) +#define ERRFILE_icmp ( ERRFILE_NET | 0x00390000 ) +#define ERRFILE_ping ( ERRFILE_NET | 0x003a0000 ) +#define ERRFILE_dhcpv6 ( ERRFILE_NET | 0x003b0000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) @@ -213,6 +230,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_segment ( ERRFILE_IMAGE | 0x00030000 ) #define ERRFILE_efi_image ( ERRFILE_IMAGE | 0x00040000 ) #define ERRFILE_embedded ( ERRFILE_IMAGE | 0x00050000 ) +#define ERRFILE_pnm ( ERRFILE_IMAGE | 0x00060000 ) +#define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 ) #define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 ) #define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 ) @@ -265,6 +284,21 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_nslookup ( ERRFILE_OTHER | 0x00300000 ) #define ERRFILE_efi_snp_hii ( ERRFILE_OTHER | 0x00310000 ) #define ERRFILE_readline ( ERRFILE_OTHER | 0x00320000 ) +#define ERRFILE_efi_bofm ( ERRFILE_OTHER | 0x00330000 ) +#define ERRFILE_efi_console ( ERRFILE_OTHER | 0x00340000 ) +#define ERRFILE_efi_debug ( ERRFILE_OTHER | 0x00350000 ) +#define ERRFILE_efi_download ( ERRFILE_OTHER | 0x00360000 ) +#define ERRFILE_efi_driver ( ERRFILE_OTHER | 0x00370000 ) +#define ERRFILE_efi_file ( ERRFILE_OTHER | 0x00380000 ) +#define ERRFILE_efi_init ( ERRFILE_OTHER | 0x00390000 ) +#define ERRFILE_efi_timer ( ERRFILE_OTHER | 0x003a0000 ) +#define ERRFILE_efi_umalloc ( ERRFILE_OTHER | 0x003b0000 ) +#define ERRFILE_linux_pci ( ERRFILE_OTHER | 0x003c0000 ) +#define ERRFILE_pci_settings ( ERRFILE_OTHER | 0x003d0000 ) +#define ERRFILE_efi_reboot ( ERRFILE_OTHER | 0x003e0000 ) +#define ERRFILE_memmap_settings ( ERRFILE_OTHER | 0x003f0000 ) +#define ERRFILE_param_cmd ( ERRFILE_OTHER | 0x00400000 ) +#define ERRFILE_deflate ( ERRFILE_OTHER | 0x00410000 ) /** @} */ diff --git a/roms/ipxe/src/include/ipxe/errno/efi.h b/roms/ipxe/src/include/ipxe/errno/efi.h new file mode 100644 index 000000000..2d2c50176 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/errno/efi.h @@ -0,0 +1,134 @@ +#ifndef _IPXE_ERRNO_EFI_H +#define _IPXE_ERRNO_EFI_H + +/** + * @file + * + * EFI platform error codes + * + * We derive our platform error codes from the possible values for + * EFI_STATUS defined in the UEFI specification. + * + * EFI_STATUS codes are 32/64-bit values consisting of a top bit which + * is set for errors and clear for warnings, and a mildly undefined + * code of low bits indicating the precise error/warning code. Errors + * and warnings have completely separate namespaces. + * + * We assume that no EFI_STATUS code will ever be defined which uses + * more than bits 0-6 of the low bits. We then choose to encode our + * platform-specific error by mapping bit 31/63 of the EFI_STATUS to + * bit 7 of the platform-specific error code, and preserving bits 0-6 + * as-is. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/efi/efi.h> +#include <ipxe/efi/Uefi/UefiBaseType.h> + +/** Bit shift for EFI error/warning bit */ +#define EFI_ERR_SHIFT ( 8 * ( sizeof ( EFI_STATUS ) - 1 ) ) + +/** + * Convert platform error code to platform component of iPXE error code + * + * @v platform Platform error code + * @ret errno Platform component of iPXE error code + */ +#define PLATFORM_TO_ERRNO( platform ) \ + ( ( (platform) | \ + ( ( ( EFI_STATUS ) (platform) ) >> EFI_ERR_SHIFT ) ) & 0xff ) + +/** + * Convert iPXE error code to platform error code + * + * @v errno iPXE error code + * @ret platform Platform error code + */ +#define ERRNO_TO_PLATFORM( errno ) \ + ( ( ( ( EFI_STATUS ) (errno) & 0x80 ) << EFI_ERR_SHIFT ) | \ + ( (errno) & 0x7f ) ) + +/* Platform-specific error codes */ +#define PLATFORM_ENOERR EFI_SUCCESS +#define PLATFORM_E2BIG EFI_BUFFER_TOO_SMALL +#define PLATFORM_EACCES EFI_ACCESS_DENIED +#define PLATFORM_EADDRINUSE EFI_ALREADY_STARTED +#define PLATFORM_EADDRNOTAVAIL EFI_NOT_READY +#define PLATFORM_EAFNOSUPPORT EFI_UNSUPPORTED +#define PLATFORM_EAGAIN EFI_NOT_READY +#define PLATFORM_EALREADY EFI_ALREADY_STARTED +#define PLATFORM_EBADF EFI_INVALID_PARAMETER +#define PLATFORM_EBADMSG EFI_PROTOCOL_ERROR +#define PLATFORM_EBUSY EFI_NO_RESPONSE +#define PLATFORM_ECANCELED EFI_ABORTED +#define PLATFORM_ECHILD EFI_NOT_FOUND +#define PLATFORM_ECONNABORTED EFI_ABORTED +#define PLATFORM_ECONNREFUSED EFI_NO_RESPONSE +#define PLATFORM_ECONNRESET EFI_ABORTED +#define PLATFORM_EDEADLK EFI_NOT_READY +#define PLATFORM_EDESTADDRREQ EFI_PROTOCOL_ERROR +#define PLATFORM_EDOM EFI_INVALID_PARAMETER +#define PLATFORM_EDQUOT EFI_VOLUME_FULL +#define PLATFORM_EEXIST EFI_WRITE_PROTECTED +#define PLATFORM_EFAULT EFI_INVALID_PARAMETER +#define PLATFORM_EFBIG EFI_END_OF_MEDIA +#define PLATFORM_EHOSTUNREACH EFI_NO_RESPONSE +#define PLATFORM_EIDRM EFI_INVALID_PARAMETER +#define PLATFORM_EILSEQ EFI_INVALID_PARAMETER +#define PLATFORM_EINPROGRESS EFI_ALREADY_STARTED +#define PLATFORM_EINTR EFI_NOT_READY +#define PLATFORM_EINVAL EFI_INVALID_PARAMETER +#define PLATFORM_EIO EFI_PROTOCOL_ERROR +#define PLATFORM_EISCONN EFI_ALREADY_STARTED +#define PLATFORM_EISDIR EFI_PROTOCOL_ERROR +#define PLATFORM_ELOOP EFI_VOLUME_CORRUPTED +#define PLATFORM_EMFILE EFI_OUT_OF_RESOURCES +#define PLATFORM_EMLINK EFI_OUT_OF_RESOURCES +#define PLATFORM_EMSGSIZE EFI_BAD_BUFFER_SIZE +#define PLATFORM_EMULTIHOP EFI_INVALID_PARAMETER +#define PLATFORM_ENAMETOOLONG EFI_INVALID_PARAMETER +#define PLATFORM_ENETDOWN EFI_NO_RESPONSE +#define PLATFORM_ENETRESET EFI_ABORTED +#define PLATFORM_ENETUNREACH EFI_NO_RESPONSE +#define PLATFORM_ENFILE EFI_OUT_OF_RESOURCES +#define PLATFORM_ENOBUFS EFI_OUT_OF_RESOURCES +#define PLATFORM_ENODATA EFI_NO_RESPONSE +#define PLATFORM_ENODEV EFI_DEVICE_ERROR +#define PLATFORM_ENOENT EFI_NOT_FOUND +#define PLATFORM_ENOEXEC EFI_LOAD_ERROR +#define PLATFORM_ENOLCK EFI_OUT_OF_RESOURCES +#define PLATFORM_ENOLINK EFI_OUT_OF_RESOURCES +#define PLATFORM_ENOMEM EFI_OUT_OF_RESOURCES +#define PLATFORM_ENOMSG EFI_PROTOCOL_ERROR +#define PLATFORM_ENOPROTOOPT EFI_UNSUPPORTED +#define PLATFORM_ENOSPC EFI_VOLUME_FULL +#define PLATFORM_ENOSR EFI_OUT_OF_RESOURCES +#define PLATFORM_ENOSTR EFI_PROTOCOL_ERROR +#define PLATFORM_ENOSYS EFI_UNSUPPORTED +#define PLATFORM_ENOTCONN EFI_NOT_STARTED +#define PLATFORM_ENOTDIR EFI_VOLUME_CORRUPTED +#define PLATFORM_ENOTEMPTY EFI_VOLUME_CORRUPTED +#define PLATFORM_ENOTSOCK EFI_INVALID_PARAMETER +#define PLATFORM_ENOTSUP EFI_UNSUPPORTED +#define PLATFORM_ENOTTY EFI_UNSUPPORTED +#define PLATFORM_ENXIO EFI_NOT_FOUND +#define PLATFORM_EOPNOTSUPP EFI_UNSUPPORTED +#define PLATFORM_EOVERFLOW EFI_BUFFER_TOO_SMALL +#define PLATFORM_EPERM EFI_ACCESS_DENIED +#define PLATFORM_EPIPE EFI_ABORTED +#define PLATFORM_EPROTO EFI_PROTOCOL_ERROR +#define PLATFORM_EPROTONOSUPPORT EFI_UNSUPPORTED +#define PLATFORM_EPROTOTYPE EFI_INVALID_PARAMETER +#define PLATFORM_ERANGE EFI_BUFFER_TOO_SMALL +#define PLATFORM_EROFS EFI_WRITE_PROTECTED +#define PLATFORM_ESPIPE EFI_END_OF_FILE +#define PLATFORM_ESRCH EFI_NOT_STARTED +#define PLATFORM_ESTALE EFI_PROTOCOL_ERROR +#define PLATFORM_ETIME EFI_TIMEOUT +#define PLATFORM_ETIMEDOUT EFI_TIMEOUT +#define PLATFORM_ETXTBSY EFI_MEDIA_CHANGED +#define PLATFORM_EWOULDBLOCK EFI_NOT_READY +#define PLATFORM_EXDEV EFI_VOLUME_CORRUPTED + +#endif /* _IPXE_ERRNO_EFI_H */ diff --git a/roms/ipxe/src/include/ipxe/errno/linux.h b/roms/ipxe/src/include/ipxe/errno/linux.h new file mode 100644 index 000000000..11309b4ad --- /dev/null +++ b/roms/ipxe/src/include/ipxe/errno/linux.h @@ -0,0 +1,113 @@ +#ifndef _IPXE_ERRNO_LINUX_H +#define _IPXE_ERRNO_LINUX_H + +/** + * @file + * + * Linux platform error codes + * + * Linux error codes all fit inside 8 bits, so we just use them + * directly as our platform error codes. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Convert platform error code to platform component of iPXE error code + * + * @v platform Platform error code + * @ret errno Platform component of iPXE error code + */ +#define PLATFORM_TO_ERRNO( platform ) ( (platform) & 0xff ) + +/** + * Convert iPXE error code to platform error code + * + * @v errno iPXE error code + * @ret platform Platform error code + */ +#define ERRNO_TO_PLATFORM( errno ) ( (errno) & 0xff ) + +/* Platform-specific error codes */ +#define PLATFORM_ENOERR 0 +#define PLATFORM_E2BIG 7 +#define PLATFORM_EACCES 13 +#define PLATFORM_EADDRINUSE 98 +#define PLATFORM_EADDRNOTAVAIL 99 +#define PLATFORM_EAFNOSUPPORT 97 +#define PLATFORM_EAGAIN 11 +#define PLATFORM_EALREADY 114 +#define PLATFORM_EBADF 9 +#define PLATFORM_EBADMSG 74 +#define PLATFORM_EBUSY 16 +#define PLATFORM_ECANCELED 125 +#define PLATFORM_ECHILD 10 +#define PLATFORM_ECONNABORTED 103 +#define PLATFORM_ECONNREFUSED 111 +#define PLATFORM_ECONNRESET 104 +#define PLATFORM_EDEADLK 35 +#define PLATFORM_EDESTADDRREQ 89 +#define PLATFORM_EDOM 33 +#define PLATFORM_EDQUOT 122 +#define PLATFORM_EEXIST 17 +#define PLATFORM_EFAULT 14 +#define PLATFORM_EFBIG 27 +#define PLATFORM_EHOSTUNREACH 113 +#define PLATFORM_EIDRM 43 +#define PLATFORM_EILSEQ 84 +#define PLATFORM_EINPROGRESS 115 +#define PLATFORM_EINTR 4 +#define PLATFORM_EINVAL 22 +#define PLATFORM_EIO 5 +#define PLATFORM_EISCONN 106 +#define PLATFORM_EISDIR 21 +#define PLATFORM_ELOOP 40 +#define PLATFORM_EMFILE 24 +#define PLATFORM_EMLINK 31 +#define PLATFORM_EMSGSIZE 90 +#define PLATFORM_EMULTIHOP 72 +#define PLATFORM_ENAMETOOLONG 36 +#define PLATFORM_ENETDOWN 100 +#define PLATFORM_ENETRESET 102 +#define PLATFORM_ENETUNREACH 101 +#define PLATFORM_ENFILE 23 +#define PLATFORM_ENOBUFS 105 +#define PLATFORM_ENODATA 61 +#define PLATFORM_ENODEV 19 +#define PLATFORM_ENOENT 2 +#define PLATFORM_ENOEXEC 8 +#define PLATFORM_ENOLCK 37 +#define PLATFORM_ENOLINK 67 +#define PLATFORM_ENOMEM 12 +#define PLATFORM_ENOMSG 42 +#define PLATFORM_ENOPROTOOPT 92 +#define PLATFORM_ENOSPC 28 +#define PLATFORM_ENOSR 63 +#define PLATFORM_ENOSTR 60 +#define PLATFORM_ENOSYS 38 +#define PLATFORM_ENOTCONN 107 +#define PLATFORM_ENOTDIR 20 +#define PLATFORM_ENOTEMPTY 39 +#define PLATFORM_ENOTSOCK 88 +#define PLATFORM_ENOTSUP PLATFORM_EOPNOTSUPP +#define PLATFORM_ENOTTY 25 +#define PLATFORM_ENXIO 6 +#define PLATFORM_EOPNOTSUPP 95 +#define PLATFORM_EOVERFLOW 75 +#define PLATFORM_EPERM 1 +#define PLATFORM_EPIPE 32 +#define PLATFORM_EPROTO 71 +#define PLATFORM_EPROTONOSUPPORT 93 +#define PLATFORM_EPROTOTYPE 91 +#define PLATFORM_ERANGE 34 +#define PLATFORM_EROFS 30 +#define PLATFORM_ESPIPE 29 +#define PLATFORM_ESRCH 3 +#define PLATFORM_ESTALE 116 +#define PLATFORM_ETIME 62 +#define PLATFORM_ETIMEDOUT 110 +#define PLATFORM_ETXTBSY 26 +#define PLATFORM_EWOULDBLOCK PLATFORM_EAGAIN +#define PLATFORM_EXDEV 18 + +#endif /* _IPXE_ERRNO_LINUX_H */ diff --git a/roms/ipxe/src/include/ipxe/ethernet.h b/roms/ipxe/src/include/ipxe/ethernet.h index 1794ff67e..5ffc45b73 100644 --- a/roms/ipxe/src/include/ipxe/ethernet.h +++ b/roms/ipxe/src/include/ipxe/ethernet.h @@ -91,6 +91,7 @@ extern const char * eth_ntoa ( const void *ll_addr ); extern int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ); extern int eth_eth_addr ( const void *ll_addr, void *eth_addr ); +extern int eth_eui64 ( const void *ll_addr, void *eui64 ); extern struct net_device * alloc_etherdev ( size_t priv_size ); #endif /* _IPXE_ETHERNET_H */ diff --git a/roms/ipxe/src/include/ipxe/fbcon.h b/roms/ipxe/src/include/ipxe/fbcon.h new file mode 100644 index 000000000..0538449ac --- /dev/null +++ b/roms/ipxe/src/include/ipxe/fbcon.h @@ -0,0 +1,155 @@ +#ifndef _IPXE_FBCON_H +#define _IPXE_FBCON_H + +/** @file + * + * Frame buffer console + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/ansiesc.h> +#include <ipxe/uaccess.h> + +struct pixel_buffer; + +/** Character width, in pixels */ +#define FBCON_CHAR_WIDTH 9 + +/** Character height, in pixels */ +#define FBCON_CHAR_HEIGHT 16 + +/** Bold colour modifier (RGB value) */ +#define FBCON_BOLD 0x555555 + +/** Transparent background magic colour (raw colour value) */ +#define FBCON_TRANSPARENT 0xffffffff + +/** A font glyph */ +struct fbcon_font_glyph { + /** Row bitmask */ + uint8_t bitmask[FBCON_CHAR_HEIGHT]; +} __attribute__ (( packed )); + +/** A font definition */ +struct fbcon_font { + /** Character glyphs */ + userptr_t start; +} __attribute__ (( packed )); + +/** A frame buffer geometry + * + * The geometry is defined in terms of "entities" (which can be either + * pixels or characters). + */ +struct fbcon_geometry { + /** Width (number of entities per displayed row) */ + unsigned int width; + /** Height (number of entities per displayed column) */ + unsigned int height; + /** Length of a single entity */ + size_t len; + /** Stride (offset between vertically adjacent entities) */ + size_t stride; +}; + +/** A frame buffer margin */ +struct fbcon_margin { + /** Left margin */ + unsigned int left; + /** Right margin */ + unsigned int right; + /** Top margin */ + unsigned int top; + /** Bottom margin */ + unsigned int bottom; +}; + +/** A frame buffer colour mapping */ +struct fbcon_colour_map { + /** Red scale (right shift amount from 24-bit RGB) */ + uint8_t red_scale; + /** Green scale (right shift amount from 24-bit RGB) */ + uint8_t green_scale; + /** Blue scale (right shift amount from 24-bit RGB) */ + uint8_t blue_scale; + /** Red LSB */ + uint8_t red_lsb; + /** Green LSB */ + uint8_t green_lsb; + /** Blue LSB */ + uint8_t blue_lsb; +}; + +/** A frame buffer text cell */ +struct fbcon_text_cell { + /** Foreground colour */ + uint32_t foreground; + /** Background colour */ + uint32_t background; + /** Character */ + unsigned int character; +}; + +/** A frame buffer text array */ +struct fbcon_text { + /** Stored text cells */ + userptr_t start; +}; + +/** A frame buffer background picture */ +struct fbcon_picture { + /** Start address */ + userptr_t start; +}; + +/** A frame buffer console */ +struct fbcon { + /** Start address */ + userptr_t start; + /** Length of one complete displayed screen */ + size_t len; + /** Pixel geometry */ + struct fbcon_geometry *pixel; + /** Character geometry */ + struct fbcon_geometry character; + /** Margin */ + struct fbcon_margin margin; + /** Indent to first character (in bytes) */ + size_t indent; + /** Colour mapping */ + struct fbcon_colour_map *map; + /** Font definition */ + struct fbcon_font *font; + /** Text foreground raw colour */ + uint32_t foreground; + /** Text background raw colour */ + uint32_t background; + /** Bold colour modifier raw colour */ + uint32_t bold; + /** Text cursor X position */ + unsigned int xpos; + /** Text cursor Y position */ + unsigned int ypos; + /** ANSI escape sequence context */ + struct ansiesc_context ctx; + /** Text array */ + struct fbcon_text text; + /** Background picture */ + struct fbcon_picture picture; + /** Display cursor */ + int show_cursor; +}; + +extern int fbcon_init ( struct fbcon *fbcon, userptr_t start, + struct fbcon_geometry *pixel, + struct fbcon_margin *margin, + struct fbcon_colour_map *map, + struct fbcon_font *font, + struct pixel_buffer *pixbuf ); +extern void fbcon_fini ( struct fbcon *fbcon ); +extern void fbcon_putchar ( struct fbcon *fbcon, int character ); + +#endif /* _IPXE_FBCON_H */ diff --git a/roms/ipxe/src/include/ipxe/fc.h b/roms/ipxe/src/include/ipxe/fc.h index 6689f394e..6fdef092d 100644 --- a/roms/ipxe/src/include/ipxe/fc.h +++ b/roms/ipxe/src/include/ipxe/fc.h @@ -60,7 +60,7 @@ struct sockaddr_fc { */ char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t ) - sizeof ( struct fc_port_id ) ]; -} __attribute__ (( may_alias )); +} __attribute__ (( packed, may_alias )); extern struct fc_port_id fc_empty_port_id; extern struct fc_port_id fc_f_port_id; diff --git a/roms/ipxe/src/include/ipxe/features.h b/roms/ipxe/src/include/ipxe/features.h index 0c92f5be9..d8b8b2184 100644 --- a/roms/ipxe/src/include/ipxe/features.h +++ b/roms/ipxe/src/include/ipxe/features.h @@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define DHCP_EB_FEATURE_VLAN 0x26 /**< VLAN support */ #define DHCP_EB_FEATURE_MENU 0x27 /**< Menu support */ #define DHCP_EB_FEATURE_SDI 0x28 /**< SDI image support */ +#define DHCP_EB_FEATURE_NFS 0x29 /**< NFS protocol */ /** @} */ diff --git a/roms/ipxe/src/include/ipxe/fragment.h b/roms/ipxe/src/include/ipxe/fragment.h new file mode 100644 index 000000000..e311ad1e4 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/fragment.h @@ -0,0 +1,72 @@ +#ifndef _IPXE_FRAGMENT_H +#define _IPXE_FRAGMENT_H + +/** @file + * + * Fragment reassembly + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/list.h> +#include <ipxe/iobuf.h> +#include <ipxe/retry.h> + +/** Fragment reassembly timeout */ +#define FRAGMENT_TIMEOUT ( TICKS_PER_SEC / 2 ) + +/** A fragment reassembly buffer */ +struct fragment { + /* List of fragment reassembly buffers */ + struct list_head list; + /** Reassembled packet */ + struct io_buffer *iobuf; + /** Length of non-fragmentable portion of reassembled packet */ + size_t hdrlen; + /** Reassembly timer */ + struct retry_timer timer; + /** Fragment reassembler */ + struct fragment_reassembler *fragments; +}; + +/** A fragment reassembler */ +struct fragment_reassembler { + /** List of fragment reassembly buffers */ + struct list_head list; + /** + * Check if fragment matches fragment reassembly buffer + * + * @v fragment Fragment reassembly buffer + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret is_fragment Fragment matches this reassembly buffer + */ + int ( * is_fragment ) ( struct fragment *fragment, + struct io_buffer *iobuf, size_t hdrlen ); + /** + * Get fragment offset + * + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret offset Offset + */ + size_t ( * fragment_offset ) ( struct io_buffer *iobuf, size_t hdrlen ); + /** + * Check if more fragments exist + * + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret more_frags More fragments exist + */ + int ( * more_fragments ) ( struct io_buffer *iobuf, size_t hdrlen ); + /** Associated IP statistics */ + struct ip_statistics *stats; +}; + +extern struct io_buffer * +fragment_reassemble ( struct fragment_reassembler *fragments, + struct io_buffer *iobuf, size_t *hdrlen ); + +#endif /* _IPXE_FRAGMENT_H */ diff --git a/roms/ipxe/src/include/ipxe/icmp.h b/roms/ipxe/src/include/ipxe/icmp.h index e402ce40e..0480ddfaf 100644 --- a/roms/ipxe/src/include/ipxe/icmp.h +++ b/roms/ipxe/src/include/ipxe/icmp.h @@ -9,6 +9,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include <stdint.h> +#include <ipxe/iobuf.h> +#include <ipxe/socket.h> +#include <ipxe/tcpip.h> +#include <ipxe/tables.h> + /** An ICMP header */ struct icmp_header { /** Type */ @@ -19,7 +25,49 @@ struct icmp_header { uint16_t chksum; } __attribute__ (( packed )); -#define ICMP_ECHO_RESPONSE 0 +/** An ICMP echo request/reply */ +struct icmp_echo { + /** ICMPv6 header */ + struct icmp_header icmp; + /** Identifier */ + uint16_t ident; + /** Sequence number */ + uint16_t sequence; + /** Data */ + uint8_t data[0]; +} __attribute__ (( packed )); + +/** An ICMP echo protocol */ +struct icmp_echo_protocol { + /** Address family */ + sa_family_t family; + /** Request type */ + uint8_t request; + /** Reply type */ + uint8_t reply; + /** TCP/IP protocol */ + struct tcpip_protocol *tcpip_protocol; + /** Include network-layer checksum within packet */ + int net_checksum; +}; + +/** ICMP echo protocol table */ +#define ICMP_ECHO_PROTOCOLS \ + __table ( struct icmp_echo_protocol, "icmp_echo_protocols" ) + +/** Declare an ICMP echo protocol */ +#define __icmp_echo_protocol __table_entry ( ICMP_ECHO_PROTOCOLS, 01 ) + +#define ICMP_ECHO_REPLY 0 #define ICMP_ECHO_REQUEST 8 +extern int icmp_tx_echo_request ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_dest ); + +extern int icmp_rx_echo_request ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_src, + struct icmp_echo_protocol *echo_protocol ); +extern int icmp_rx_echo_reply ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_src ); + #endif /* _IPXE_ICMP_H */ diff --git a/roms/ipxe/src/include/ipxe/icmp6.h b/roms/ipxe/src/include/ipxe/icmp6.h deleted file mode 100644 index 1d433408d..000000000 --- a/roms/ipxe/src/include/ipxe/icmp6.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _IPXE_ICMP6_H -#define _IPXE_ICMP6_H - -/** @file - * - * ICMP6 protocol - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <ipxe/ip6.h> -#include <ipxe/ndp.h> - -#define ICMP6_NSOLICIT 135 -#define ICMP6_NADVERT 136 - -extern struct tcpip_protocol icmp6_protocol __tcpip_protocol; - -struct icmp6_header { - uint8_t type; - uint8_t code; - uint16_t csum; - /* Message body */ -}; - -struct neighbour_solicit { - uint8_t type; - uint8_t code; - uint16_t csum; - uint32_t reserved; - struct in6_addr target; - /* "Compulsory" options */ - uint8_t opt_type; - uint8_t opt_len; - /* FIXME: hack alert */ - uint8_t opt_ll_addr[6]; -}; - -struct neighbour_advert { - uint8_t type; - uint8_t code; - uint16_t csum; - uint8_t flags; - uint8_t reserved; - struct in6_addr target; - uint8_t opt_type; - uint8_t opt_len; - /* FIXME: hack alert */ - uint8_t opt_ll_addr[6]; -}; - -#define ICMP6_FLAGS_ROUTER 0x80 -#define ICMP6_FLAGS_SOLICITED 0x40 -#define ICMP6_FLAGS_OVERRIDE 0x20 - -int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src, struct in6_addr *dest ); - -#endif /* _IPXE_ICMP6_H */ diff --git a/roms/ipxe/src/include/ipxe/icmpv6.h b/roms/ipxe/src/include/ipxe/icmpv6.h new file mode 100644 index 000000000..b5ea54eab --- /dev/null +++ b/roms/ipxe/src/include/ipxe/icmpv6.h @@ -0,0 +1,63 @@ +#ifndef _IPXE_ICMP6_H +#define _IPXE_ICMP6_H + +/** @file + * + * ICMPv6 protocol + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/tables.h> +#include <ipxe/iobuf.h> +#include <ipxe/netdevice.h> +#include <ipxe/icmp.h> + +/** An ICMPv6 handler */ +struct icmpv6_handler { + /** Type */ + unsigned int type; + /** Process received packet + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v sin6_src Source socket address + * @v sin6_dest Destination socket address + * @ret rc Return status code + * + * This function takes ownership of the I/O buffer. + */ + int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + struct sockaddr_in6 *sin6_dest ); +}; + +/** ICMPv6 handler table */ +#define ICMPV6_HANDLERS __table ( struct icmpv6_handler, "icmpv6_handlers" ) + +/** Declare an ICMPv6 handler */ +#define __icmpv6_handler __table_entry ( ICMPV6_HANDLERS, 01 ) + +/** ICMPv6 echo request */ +#define ICMPV6_ECHO_REQUEST 128 + +/** ICMPv6 echo reply */ +#define ICMPV6_ECHO_REPLY 129 + +/** ICMPv6 router solicitation */ +#define ICMPV6_ROUTER_SOLICITATION 133 + +/** ICMPv6 router advertisement */ +#define ICMPV6_ROUTER_ADVERTISEMENT 134 + +/** ICMPv6 neighbour solicitation */ +#define ICMPV6_NEIGHBOUR_SOLICITATION 135 + +/** ICMPv6 neighbour advertisement */ +#define ICMPV6_NEIGHBOUR_ADVERTISEMENT 136 + +extern struct tcpip_protocol icmpv6_protocol __tcpip_protocol; + +#endif /* _IPXE_ICMP6_H */ diff --git a/roms/ipxe/src/include/ipxe/image.h b/roms/ipxe/src/include/ipxe/image.h index 6022dce66..5d7080a75 100644 --- a/roms/ipxe/src/include/ipxe/image.h +++ b/roms/ipxe/src/include/ipxe/image.h @@ -16,6 +16,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/refcnt.h> struct uri; +struct pixel_buffer; struct image_type; /** An executable image */ @@ -74,9 +75,10 @@ struct image { struct image_type { /** Name of this image type */ char *name; - /** Probe image + /** + * Probe image * - * @v image Executable image + * @v image Image * @ret rc Return status code * * Return success if the image is of this image type. @@ -85,10 +87,18 @@ struct image_type { /** * Execute image * - * @v image Executable image + * @v image Image * @ret rc Return status code */ int ( * exec ) ( struct image *image ); + /** + * Create pixel buffer from image + * + * @v image Image + * @v pixbuf Pixel buffer to fill in + * @ret rc Return status code + */ + int ( * pixbuf ) ( struct image *image, struct pixel_buffer **pixbuf ); }; /** @@ -159,6 +169,7 @@ extern int image_replace ( struct image *replacement ); extern int image_select ( struct image *image ); extern struct image * image_find_selected ( void ); extern int image_set_trust ( int require_trusted, int permanent ); +extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ); /** * Increment reference count on an image diff --git a/roms/ipxe/src/include/ipxe/in.h b/roms/ipxe/src/include/ipxe/in.h index 20f1ce267..36032470c 100644 --- a/roms/ipxe/src/include/ipxe/in.h +++ b/roms/ipxe/src/include/ipxe/in.h @@ -50,6 +50,19 @@ struct in6_addr { #define s6_addr32 in6_u.u6_addr32 }; +#define IN6_IS_ADDR_UNSPECIFIED( addr ) \ + ( ( ( ( ( const uint32_t * ) (addr) )[0] ) | \ + ( ( ( const uint32_t * ) (addr) )[1] ) | \ + ( ( ( const uint32_t * ) (addr) )[2] ) | \ + ( ( ( const uint32_t * ) (addr) )[3] ) ) == 0 ) + +#define IN6_IS_ADDR_MULTICAST( addr ) \ + ( *( ( const uint8_t * ) (addr) ) == 0xff ) + +#define IN6_IS_ADDR_LINKLOCAL( addr ) \ + ( ( *( ( const uint16_t * ) (addr) ) & htons ( 0xffc0 ) ) == \ + htonl ( 0xfe80 ) ) + /** * IPv4 socket address */ @@ -59,20 +72,23 @@ struct sockaddr_in { * Always set to @c AF_INET for IPv4 addresses */ sa_family_t sin_family; + /** Flags (part of struct @c sockaddr_tcpip) */ + uint16_t sin_flags; /** TCP/IP port (part of struct @c sockaddr_tcpip) */ uint16_t sin_port; /** IPv4 address */ struct in_addr sin_addr; /** Padding * - * This ensures that a struct @c sockaddr_tcpip is large - * enough to hold a socket address for any TCP/IP address - * family. + * This ensures that a struct @c sockaddr_in is large enough + * to hold a socket address for any TCP/IP address family. */ - char pad[ sizeof ( struct sockaddr ) - sizeof ( sa_family_t ) - - sizeof ( uint16_t ) - - sizeof ( struct in_addr ) ]; -} __attribute__ (( may_alias )); + char pad[ sizeof ( struct sockaddr ) - + ( sizeof ( sa_family_t ) /* sin_family */ + + sizeof ( uint16_t ) /* sin_flags */ + + sizeof ( uint16_t ) /* sin_port */ + + sizeof ( struct in_addr ) /* sin_addr */ ) ]; +} __attribute__ (( packed, may_alias )); /** * IPv6 socket address @@ -82,23 +98,35 @@ struct sockaddr_in6 { * * Always set to @c AF_INET6 for IPv6 addresses */ - sa_family_t sin_family; + sa_family_t sin6_family; + /** Flags (part of struct @c sockaddr_tcpip) */ + uint16_t sin6_flags; /** TCP/IP port (part of struct @c sockaddr_tcpip) */ - uint16_t sin_port; - uint32_t sin6_flowinfo; /* Flow number */ - struct in6_addr sin6_addr; /* 128-bit destination address */ - uint32_t sin6_scope_id; /* Scope ID */ -} __attribute__ (( may_alias )); + uint16_t sin6_port; + /** Scope ID + * + * For link-local addresses, this is the network device index. + */ + uint16_t sin6_scope_id; + /** IPv6 address */ + struct in6_addr sin6_addr; + /** Padding + * + * This ensures that a struct @c sockaddr_in6 is large + * enough to hold a socket address for any TCP/IP address + * family. + */ + char pad[ sizeof ( struct sockaddr ) - + ( sizeof ( sa_family_t ) /* sin6_family */ + + sizeof ( uint16_t ) /* sin6_flags */ + + sizeof ( uint16_t ) /* sin6_port */ + + sizeof ( uint16_t ) /* sin6_scope_id */ + + sizeof ( struct in6_addr ) /* sin6_addr */ ) ]; +} __attribute__ (( packed, may_alias )); extern int inet_aton ( const char *cp, struct in_addr *inp ); extern char * inet_ntoa ( struct in_addr in ); - -/* Adding the following for IP6 support - * - -extern int inet6_aton ( const char *cp, struct in6_addr *inp ); -extern char * inet6_ntoa ( struct in_addr in ); - - */ +extern int inet6_aton ( const char *string, struct in6_addr *in ); +extern char * inet6_ntoa ( const struct in6_addr *in ); #endif /* _IPXE_IN_H */ diff --git a/roms/ipxe/src/include/ipxe/io.h b/roms/ipxe/src/include/ipxe/io.h index b4d88fe89..b8b8aa313 100644 --- a/roms/ipxe/src/include/ipxe/io.h +++ b/roms/ipxe/src/include/ipxe/io.h @@ -53,7 +53,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func ) /* Include all architecture-independent I/O API headers */ -#include <ipxe/efi/efi_io.h> /* Include all architecture-dependent I/O API headers */ #include <bits/io.h> diff --git a/roms/ipxe/src/include/ipxe/ip.h b/roms/ipxe/src/include/ipxe/ip.h index ca508e274..1a93a552e 100644 --- a/roms/ipxe/src/include/ipxe/ip.h +++ b/roms/ipxe/src/include/ipxe/ip.h @@ -70,22 +70,15 @@ struct ipv4_miniroute { struct in_addr gateway; }; -/* IPv4 fragment reassembly buffer */ -struct ipv4_fragment { - /* List of fragment reassembly buffers */ - struct list_head list; - /** Reassembled packet */ - struct io_buffer *iobuf; - /** Current offset */ - size_t offset; - /** Reassembly timer */ - struct retry_timer timer; -}; - extern struct list_head ipv4_miniroutes; extern struct net_protocol ipv4_protocol __net_protocol; extern int ipv4_has_any_addr ( struct net_device *netdev ); +extern int parse_ipv4_setting ( const struct setting_type *type, + const char *value, void *buf, size_t len ); +extern int format_ipv4_setting ( const struct setting_type *type, + const void *raw, size_t raw_len, char *buf, + size_t len ); #endif /* _IPXE_IP_H */ diff --git a/roms/ipxe/src/include/ipxe/ip6.h b/roms/ipxe/src/include/ipxe/ip6.h deleted file mode 100644 index e9584bd6f..000000000 --- a/roms/ipxe/src/include/ipxe/ip6.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _IPXE_IP6_H -#define _IPXE_IP6_H - -/** @file - * - * IP6 protocol - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdint.h> -#include <ipxe/in.h> -#include <ipxe/netdevice.h> -#include <ipxe/tcpip.h> - -/* IP6 constants */ - -#define IP6_VERSION 0x6 -#define IP6_HOP_LIMIT 255 - -/** - * I/O buffer contents - * This is duplicated in tcp.h and here. Ideally it should go into iobuf.h - */ -#define MAX_HDR_LEN 100 -#define MAX_IOB_LEN 1500 -#define MIN_IOB_LEN MAX_HDR_LEN + 100 /* To account for padding by LL */ - -#define IP6_EQUAL( in6_addr1, in6_addr2 ) \ - ( memcmp ( ( char* ) &( in6_addr1 ), ( char* ) &( in6_addr2 ),\ - sizeof ( struct in6_addr ) ) == 0 ) - -#define IS_UNSPECIFIED( addr ) \ - ( ( (addr).in6_u.u6_addr32[0] == 0x00000000 ) && \ - ( (addr).in6_u.u6_addr32[1] == 0x00000000 ) && \ - ( (addr).in6_u.u6_addr32[2] == 0x00000000 ) && \ - ( (addr).in6_u.u6_addr32[3] == 0x00000000 ) ) -/* IP6 header */ -struct ip6_header { - uint32_t ver_traffic_class_flow_label; - uint16_t payload_len; - uint8_t nxt_hdr; - uint8_t hop_limit; - struct in6_addr src; - struct in6_addr dest; -}; - -/* IP6 pseudo header */ -struct ipv6_pseudo_header { - struct in6_addr src; - struct in6_addr dest; - uint8_t zero_padding; - uint8_t nxt_hdr; - uint16_t len; -}; - -/* Next header numbers */ -#define IP6_HOPBYHOP 0x00 -#define IP6_ROUTING 0x43 -#define IP6_FRAGMENT 0x44 -#define IP6_AUTHENTICATION 0x51 -#define IP6_DEST_OPTS 0x60 -#define IP6_ESP 0x50 -#define IP6_ICMP6 0x58 -#define IP6_NO_HEADER 0x59 - -struct io_buffer; - -extern struct net_protocol ipv6_protocol __net_protocol; -extern struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol; -extern char * inet6_ntoa ( struct in6_addr in6 ); - -extern int add_ipv6_address ( struct net_device *netdev, - struct in6_addr prefix, int prefix_len, - struct in6_addr address, - struct in6_addr gateway ); -extern void del_ipv6_address ( struct net_device *netdev ); - -#endif /* _IPXE_IP6_H */ diff --git a/roms/ipxe/src/include/ipxe/ipstat.h b/roms/ipxe/src/include/ipxe/ipstat.h new file mode 100644 index 000000000..c554c1859 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/ipstat.h @@ -0,0 +1,187 @@ +#ifndef _IPXE_IPSTATS_H +#define _IPXE_IPSTATS_H + +/** @file + * + * IP statistics + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/tables.h> + +struct io_buffer; + +/** IP system statistics + * + * Definitions are taken from the RFC4293 section 5 + * "ipSystemStatsEntry" table. + * + * To minimise code size, we use "unsigned long" as the counter + * variable type regardless of whether this type is 32-bit or 64-bit. + * On a 32-bit build (e.g. the standard BIOS build), this means that + * we omit the "high capacity" 64-bit counters (prefixed with "HC"). + * This reduces the code size required to maintain the counter values, + * and avoids the need to support the "%lld" format in vsprintf.c + * (which would require dragging in the 64-bit division library on a + * standard 32-bit build). Since total available memory in a 32-bit + * environment is limited to 4GB, it is unlikely that we will overflow + * even the 32-bit octet counters under normal operation. + * + * Counters relating to packet forwarding are omitted, since iPXE + * includes no functionality for acting as a router. + * + * Counters related to output fragmentation are omitted, since iPXE + * has no support for fragmenting transmitted packets. + * + * The ipSystemStatsInDiscards and ipSystemStatsOutDiscards counters + * are omitted, since they will always be zero. + * + * Separate octet counters for multicast packets are omitted to save + * code size. + */ +struct ip_statistics { + /** ipSystemStatsInReceives + * + * The total number of input IP datagrams received, including + * those received in error. + */ + unsigned long in_receives; + /** ipSystemStatsInOctets + * + * The total number of octets received in input IP datagrams, + * including those received in error. Octets from datagrams + * counted in ipSystemStatsInReceives MUST be counted here. + */ + unsigned long in_octets; + /** ipSystemStatsInHdrErrors + * + * The number of input IP datagrams discarded due to errors in + * their IP headers, including version number mismatch, other + * format errors, hop count exceeded, errors discovered in + * processing their IP options, etc. + */ + unsigned long in_hdr_errors; + /** ipSystemStatsInAddrErrors + * + * The number of input IP datagrams discarded because the IP + * address in their IP header's destination field was not a + * valid address to be received at this entity. This count + * includes invalid addresses (e.g., ::0). For entities that + * are not IP routers and therefore do not forward datagrams, + * this counter includes datagrams discarded because the + * destination address was not a local address. + */ + unsigned long in_addr_errors; + /** ipSystemStatsInUnknownProtos + * + * The number of locally-addressed IP datagrams received + * successfully but discarded because of an unknown or + * unsupported protocol. + */ + unsigned long in_unknown_protos; + /** ipSystemStatsInTruncatedPkts + * + * The number of input IP datagrams discarded because the + * datagram frame didn't carry enough data. + */ + unsigned long in_truncated_pkts; + /** ipSystemStatsReasmReqds + * + * The number of IP fragments received that needed to be + * reassembled at this interface. + */ + unsigned long reasm_reqds; + /** ipSystemStatsReasmOks + * + * The number of IP datagrams successfully reassembled. + */ + unsigned long reasm_oks; + /** ipSystemStatsReasmFails + * + * The number of failures detected by the IP re-assembly + * algorithm (for whatever reason: timed out, errors, etc.). + * Note that this is not necessarily a count of discarded IP + * fragments since some algorithms (notably the algorithm in + * RFC 815) can lose track of the number of fragments by + * combining them as they are received. + */ + unsigned long reasm_fails; + /** ipSystemStatsInDelivers + * + * The total number of datagrams successfully delivered to IP + * user-protocols (including ICMP). + */ + unsigned long in_delivers; + /** ipSystemStatsOutRequests + * + * The total number of IP datagrams that local IP user- + * protocols (including ICMP) supplied to IP in requests for + * transmission. + */ + unsigned long out_requests; + /** ipSystemStatsOutNoRoutes + * + * The number of locally generated IP datagrams discarded + * because no route could be found to transmit them to their + * destination. + */ + unsigned long out_no_routes; + /** ipSystemStatsOutTransmits + * + * The total number of IP datagrams that this entity supplied + * to the lower layers for transmission. This includes + * datagrams generated locally and those forwarded by this + * entity. + */ + unsigned long out_transmits; + /** ipSystemStatsOutOctets + * + * The total number of octets in IP datagrams delivered to the + * lower layers for transmission. Octets from datagrams + * counted in ipSystemStatsOutTransmits MUST be counted here. + */ + unsigned long out_octets; + /** ipSystemStatsInMcastPkts + * + * The number of IP multicast datagrams received. + */ + unsigned long in_mcast_pkts; + /** ipSystemStatsOutMcastPkts + * + * The number of IP multicast datagrams transmitted. + */ + unsigned long out_mcast_pkts; + /** ipSystemStatsInBcastPkts + * + * The number of IP broadcast datagrams received. + */ + unsigned long in_bcast_pkts; + /** ipSystemStatsOutBcastPkts + * + * The number of IP broadcast datagrams transmitted. + */ + unsigned long out_bcast_pkts; +}; + +/** An IP system statistics family */ +struct ip_statistics_family { + /** IP version */ + unsigned int version; + /** Statistics */ + struct ip_statistics *stats; +}; + +/** IP system statistics family table */ +#define IP_STATISTICS_FAMILIES \ + __table ( struct ip_statistics_family, "ip_statistics_families" ) + +/** Declare an IP system statistics family */ +#define __ip_statistics_family( order ) \ + __table_entry ( IP_STATISTICS_FAMILIES, order ) + +#define IP_STATISTICS_IPV4 01 +#define IP_STATISTICS_IPV6 02 + +#endif /* _IPXE_IPSTATS_H */ diff --git a/roms/ipxe/src/include/ipxe/ipv6.h b/roms/ipxe/src/include/ipxe/ipv6.h new file mode 100644 index 000000000..48aaf677e --- /dev/null +++ b/roms/ipxe/src/include/ipxe/ipv6.h @@ -0,0 +1,256 @@ +#ifndef _IPXE_IPV6_H +#define _IPXE_IPV6_H + +/** @file + * + * IPv6 protocol + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <string.h> +#include <byteswap.h> +#include <ipxe/in.h> +#include <ipxe/list.h> +#include <ipxe/netdevice.h> + +/** IPv6 version */ +#define IPV6_VER 0x60000000UL + +/** IPv6 version mask */ +#define IPV6_MASK_VER 0xf0000000UL + +/** IPv6 maximum hop limit */ +#define IPV6_HOP_LIMIT 0xff + +/** IPv6 header */ +struct ipv6_header { + /** Version (4 bits), Traffic class (8 bits), Flow label (20 bits) */ + uint32_t ver_tc_label; + /** Payload length, including any extension headers */ + uint16_t len; + /** Next header type */ + uint8_t next_header; + /** Hop limit */ + uint8_t hop_limit; + /** Source address */ + struct in6_addr src; + /** Destination address */ + struct in6_addr dest; +} __attribute__ (( packed )); + +/** IPv6 extension header common fields */ +struct ipv6_extension_header_common { + /** Next header type */ + uint8_t next_header; + /** Header extension length (excluding first 8 bytes) */ + uint8_t len; +} __attribute__ (( packed )); + +/** IPv6 type-length-value options */ +struct ipv6_option { + /** Type */ + uint8_t type; + /** Length */ + uint8_t len; + /** Value */ + uint8_t value[0]; +} __attribute__ (( packed )); + +/** IPv6 option types */ +enum ipv6_option_type { + /** Pad1 */ + IPV6_OPT_PAD1 = 0x00, + /** PadN */ + IPV6_OPT_PADN = 0x01, +}; + +/** Test if IPv6 option can be safely ignored */ +#define IPV6_CAN_IGNORE_OPT( type ) ( ( (type) & 0xc0 ) == 0x00 ) + +/** IPv6 option-based extension header */ +struct ipv6_options_header { + /** Extension header common fields */ + struct ipv6_extension_header_common common; + /** Options */ + struct ipv6_option options[0]; +} __attribute__ (( packed )); + +/** IPv6 routing header */ +struct ipv6_routing_header { + /** Extension header common fields */ + struct ipv6_extension_header_common common; + /** Routing type */ + uint8_t type; + /** Segments left */ + uint8_t remaining; + /** Type-specific data */ + uint8_t data[0]; +} __attribute__ (( packed )); + +/** IPv6 fragment header */ +struct ipv6_fragment_header { + /** Extension header common fields */ + struct ipv6_extension_header_common common; + /** Fragment offset (13 bits), reserved, more fragments (1 bit) */ + uint16_t offset_more; + /** Identification */ + uint32_t ident; +} __attribute__ (( packed )); + +/** Fragment offset mask */ +#define IPV6_MASK_OFFSET 0xfff8 + +/** More fragments */ +#define IPV6_MASK_MOREFRAGS 0x0001 + +/** IPv6 extension header */ +union ipv6_extension_header { + /** Extension header common fields */ + struct ipv6_extension_header_common common; + /** Minimum size padding */ + uint8_t pad[8]; + /** Generic options header */ + struct ipv6_options_header options; + /** Hop-by-hop options header */ + struct ipv6_options_header hopbyhop; + /** Routing header */ + struct ipv6_routing_header routing; + /** Fragment header */ + struct ipv6_fragment_header fragment; + /** Destination options header */ + struct ipv6_options_header destination; +}; + +/** IPv6 header types */ +enum ipv6_header_type { + /** IPv6 hop-by-hop options header type */ + IPV6_HOPBYHOP = 0, + /** IPv6 routing header type */ + IPV6_ROUTING = 43, + /** IPv6 fragment header type */ + IPV6_FRAGMENT = 44, + /** IPv6 no next header type */ + IPV6_NO_HEADER = 59, + /** IPv6 destination options header type */ + IPV6_DESTINATION = 60, +}; + +/** IPv6 pseudo-header */ +struct ipv6_pseudo_header { + /** Source address */ + struct in6_addr src; + /** Destination address */ + struct in6_addr dest; + /** Upper-layer packet length */ + uint32_t len; + /** Zero padding */ + uint8_t zero[3]; + /** Next header */ + uint8_t next_header; +} __attribute__ (( packed )); + +/** An IPv6 address/routing table entry */ +struct ipv6_miniroute { + /** List of miniroutes */ + struct list_head list; + + /** Network device */ + struct net_device *netdev; + + /** IPv6 address (or prefix if no address is defined) */ + struct in6_addr address; + /** Prefix length */ + unsigned int prefix_len; + /** IPv6 prefix mask (derived from prefix length) */ + struct in6_addr prefix_mask; + /** Router address */ + struct in6_addr router; + /** Flags */ + unsigned int flags; +}; + +/** IPv6 address/routing table entry flags */ +enum ipv6_miniroute_flags { + /** Routing table entry address is valid */ + IPV6_HAS_ADDRESS = 0x0001, + /** Routing table entry router address is valid */ + IPV6_HAS_ROUTER = 0x0002, +}; + +/** + * Construct local IPv6 address via EUI-64 + * + * @v addr Prefix to be completed + * @v netdev Network device + * @ret prefix_len Prefix length, or negative error + */ +static inline int ipv6_eui64 ( struct in6_addr *addr, + struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + const void *ll_addr = netdev->ll_addr; + int rc; + + if ( ( rc = ll_protocol->eui64 ( ll_addr, &addr->s6_addr[8] ) ) != 0 ) + return rc; + addr->s6_addr[8] ^= 0x02; + return 64; +} + +/** + * Construct link-local address via EUI-64 + * + * @v addr Zeroed address to construct + * @v netdev Network device + * @ret prefix_len Prefix length, or negative error + */ +static inline int ipv6_link_local ( struct in6_addr *addr, + struct net_device *netdev ) { + + addr->s6_addr16[0] = htons ( 0xfe80 ); + return ipv6_eui64 ( addr, netdev ); +} + +/** + * Construct solicited-node multicast address + * + * @v addr Zeroed address to construct + * @v unicast Unicast address + */ +static inline void ipv6_solicited_node ( struct in6_addr *addr, + const struct in6_addr *unicast ) { + + addr->s6_addr16[0] = htons ( 0xff02 ); + addr->s6_addr[11] = 1; + addr->s6_addr[12] = 0xff; + memcpy ( &addr->s6_addr[13], &unicast->s6_addr[13], 3 ); +} + +/** + * Construct all-routers multicast address + * + * @v addr Zeroed address to construct + */ +static inline void ipv6_all_routers ( struct in6_addr *addr ) { + addr->s6_addr16[0] = htons ( 0xff02 ); + addr->s6_addr[15] = 2; +} + +extern struct list_head ipv6_miniroutes; + +extern struct net_protocol ipv6_protocol __net_protocol; + +extern int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ); +extern int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix, + unsigned int prefix_len, struct in6_addr *router ); +extern int ipv6_set_address ( struct net_device *netdev, + struct in6_addr *address ); +extern int parse_ipv6_setting ( const struct setting_type *type, + const char *value, void *buf, size_t len ); +extern int format_ipv6_setting ( const struct setting_type *type, + const void *raw, size_t raw_len, char *buf, + size_t len ); + +#endif /* _IPXE_IPV6_H */ diff --git a/roms/ipxe/src/include/ipxe/iso9660.h b/roms/ipxe/src/include/ipxe/iso9660.h new file mode 100644 index 000000000..02c2ae377 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/iso9660.h @@ -0,0 +1,44 @@ +#ifndef _IPXE_ISO9660_H +#define _IPXE_ISO9660_H + +/** + * @file + * + * ISO9660 CD-ROM specification + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> + +/** ISO9660 block size */ +#define ISO9660_BLKSIZE 2048 + +/** An ISO9660 Primary Volume Descriptor (fixed portion) */ +struct iso9660_primary_descriptor_fixed { + /** Descriptor type */ + uint8_t type; + /** Identifier ("CD001") */ + uint8_t id[5]; +} __attribute__ (( packed )); + +/** An ISO9660 Primary Volume Descriptor */ +struct iso9660_primary_descriptor { + /** Fixed portion */ + struct iso9660_primary_descriptor_fixed fixed; +} __attribute__ (( packed )); + +/** ISO9660 Primary Volume Descriptor type */ +#define ISO9660_TYPE_PRIMARY 0x01 + +/** ISO9660 Primary Volume Descriptor block address */ +#define ISO9660_PRIMARY_LBA 16 + +/** ISO9660 Boot Volume Descriptor type */ +#define ISO9660_TYPE_BOOT 0x00 + +/** ISO9660 identifier */ +#define ISO9660_ID "CD001" + +#endif /* _IPXE_ISO9660_H */ diff --git a/roms/ipxe/src/include/ipxe/isqrt.h b/roms/ipxe/src/include/ipxe/isqrt.h new file mode 100644 index 000000000..58ed42f0c --- /dev/null +++ b/roms/ipxe/src/include/ipxe/isqrt.h @@ -0,0 +1,14 @@ +#ifndef _IPXE_ISQRT_H +#define _IPXE_ISQRT_H + +/** @file + * + * Integer square root + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern unsigned long isqrt ( unsigned long value ); + +#endif /* _IPXE_ISQRT_H */ diff --git a/roms/ipxe/src/include/ipxe/job.h b/roms/ipxe/src/include/ipxe/job.h index c2232fc17..a2369f7c2 100644 --- a/roms/ipxe/src/include/ipxe/job.h +++ b/roms/ipxe/src/include/ipxe/job.h @@ -30,9 +30,9 @@ struct job_progress { unsigned long total; }; -extern void job_progress ( struct interface *intf, - struct job_progress *progress ); +extern int job_progress ( struct interface *intf, + struct job_progress *progress ); #define job_progress_TYPE( object_type ) \ - typeof ( void ( object_type, struct job_progress *progress ) ) + typeof ( int ( object_type, struct job_progress *progress ) ) #endif /* _IPXE_JOB_H */ diff --git a/roms/ipxe/src/include/ipxe/linux.h b/roms/ipxe/src/include/ipxe/linux.h index dac508ea6..a01ace3de 100644 --- a/roms/ipxe/src/include/ipxe/linux.h +++ b/roms/ipxe/src/include/ipxe/linux.h @@ -30,6 +30,14 @@ FILE_LICENCE(GPL2_OR_LATER); #include <ipxe/device.h> #include <ipxe/settings.h> +/** + * Convert a Linux error number to an iPXE status code + * + * @v errno Linux error number + * @ret rc iPXE status code (before negation) + */ +#define ELINUX( errno ) EPLATFORM ( EINFO_EPLATFORM, errno ) + /** A linux device */ struct linux_device { /** Generic device */ diff --git a/roms/ipxe/src/include/ipxe/linux/linux_pci.h b/roms/ipxe/src/include/ipxe/linux/linux_pci.h new file mode 100644 index 000000000..439166733 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/linux/linux_pci.h @@ -0,0 +1,130 @@ +#ifndef _IPXE_LINUX_PCI_H +#define _IPXE_LINUX_PCI_H + +/** @file + * + * iPXE PCI API for Linux + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#ifdef PCIAPI_LINUX +#define PCIAPI_PREFIX_linux +#else +#define PCIAPI_PREFIX_linux __linux_ +#endif + +struct pci_device; + +extern int linux_pci_read ( struct pci_device *pci, unsigned long where, + unsigned long *value, size_t len ); +extern int linux_pci_write ( struct pci_device *pci, unsigned long where, + unsigned long value, size_t len ); + +/** + * Read byte from PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_read_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t *value ) { + int rc; + unsigned long tmp; + + rc = linux_pci_read ( pci, where, &tmp, sizeof ( *value ) ); + *value = tmp; + return rc; +} + +/** + * Read word from PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_read_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t *value ) { + int rc; + unsigned long tmp; + + rc = linux_pci_read ( pci, where, &tmp, sizeof ( *value ) ); + *value = tmp; + return rc; +} + +/** + * Read dword from PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_read_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t *value ) { + int rc; + unsigned long tmp; + + rc = linux_pci_read ( pci, where, &tmp, sizeof ( *value ) ); + *value = tmp; + return rc; +} + +/** + * Write byte to PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_write_config_byte ) ( struct pci_device *pci, + unsigned int where, + uint8_t value ) { + return linux_pci_write ( pci, where, value, sizeof ( value ) ); +} + +/** + * Write word to PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_write_config_word ) ( struct pci_device *pci, + unsigned int where, + uint16_t value ) { + return linux_pci_write ( pci, where, value, sizeof ( value ) ); +} + +/** + * Write dword to PCI configuration space + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_write_config_dword ) ( struct pci_device *pci, + unsigned int where, + uint32_t value ) { + return linux_pci_write ( pci, where, value, sizeof ( value ) ); +} + +#endif /* _IPXE_LINUX_PCI_H */ diff --git a/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h b/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h index e4dfdd357..e4d16d9e0 100644 --- a/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h +++ b/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h @@ -89,6 +89,12 @@ UACCESS_INLINE(linux, memmove_user)(userptr_t dest, off_t dest_off, userptr_t sr trivial_memmove_user(dest, dest_off, src, src_off, len); } +static inline __always_inline int +UACCESS_INLINE(linux, memcmp_user)(userptr_t first, off_t first_off, userptr_t second, off_t second_off, size_t len) +{ + return trivial_memcmp_user(first, first_off, second, second_off, len); +} + static inline __always_inline void UACCESS_INLINE(linux, memset_user)(userptr_t buffer, off_t offset, int c, size_t len) { diff --git a/roms/ipxe/src/include/ipxe/menu.h b/roms/ipxe/src/include/ipxe/menu.h index 993b027ea..f2b3caccc 100644 --- a/roms/ipxe/src/include/ipxe/menu.h +++ b/roms/ipxe/src/include/ipxe/menu.h @@ -43,7 +43,7 @@ extern struct menu_item * add_menu_item ( struct menu *menu, const char *label, int is_default ); extern void destroy_menu ( struct menu *menu ); extern struct menu * find_menu ( const char *name ); -extern int show_menu ( struct menu *menu, unsigned int timeout_ms, +extern int show_menu ( struct menu *menu, unsigned long timeout, const char *select, struct menu_item **selected ); #endif /* _IPXE_MENU_H */ diff --git a/roms/ipxe/src/include/ipxe/mii.h b/roms/ipxe/src/include/ipxe/mii.h index cf462418a..f53ad4a62 100644 --- a/roms/ipxe/src/include/ipxe/mii.h +++ b/roms/ipxe/src/include/ipxe/mii.h @@ -78,6 +78,37 @@ mii_write ( struct mii_interface *mii, unsigned int reg, unsigned int data ) { return mii->op->write ( mii, reg, data ); } +/** + * Dump MII registers (for debugging) + * + * @v mii MII interface + */ +static inline void +mii_dump ( struct mii_interface *mii ) { + unsigned int i; + int data; + + /* Do nothing unless debug output is enabled */ + if ( ! DBG_LOG ) + return; + + /* Dump basic MII register set */ + for ( i = 0 ; i < 16 ; i++ ) { + if ( ( i % 8 ) == 0 ) { + DBGC ( mii, "MII %p registers %02x-%02x:", + mii, i, ( i + 7 ) ); + } + data = mii_read ( mii, i ); + if ( data >= 0 ) { + DBGC ( mii, " %04x", data ); + } else { + DBGC ( mii, " XXXX" ); + } + if ( ( i % 8 ) == 7 ) + DBGC ( mii, "\n" ); + } +} + /** Maximum time to wait for a reset, in milliseconds */ #define MII_RESET_MAX_WAIT_MS 500 diff --git a/roms/ipxe/src/include/ipxe/monojob.h b/roms/ipxe/src/include/ipxe/monojob.h index 3d8b31c0e..aedc37eca 100644 --- a/roms/ipxe/src/include/ipxe/monojob.h +++ b/roms/ipxe/src/include/ipxe/monojob.h @@ -13,6 +13,6 @@ struct interface; extern struct interface monojob; -extern int monojob_wait ( const char *string ); +extern int monojob_wait ( const char *string, unsigned long timeout ); #endif /* _IPXE_MONOJOB_H */ diff --git a/roms/ipxe/src/include/ipxe/mount.h b/roms/ipxe/src/include/ipxe/mount.h new file mode 100644 index 000000000..ca958117a --- /dev/null +++ b/roms/ipxe/src/include/ipxe/mount.h @@ -0,0 +1,76 @@ +#ifndef _IPXE_MOUNT_H +#define _IPXE_MOUNT_H + +#include <ipxe/nfs.h> + +/** @file + * + * NFS MOUNT protocol. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** NFS MOUNT protocol number */ +#define ONCRPC_MOUNT 100005 +/** NFS MOUNT protocol version */ +#define MOUNT_VERS 3 + + +/** No error */ +#define MNT3_OK 0 +/** Not owner */ +#define MNT3ERR_PERM 1 +/** No such file or directory */ +#define MNT3ERR_NOENT 2 +/** I/O error */ +#define MNT3ERR_IO 5 +/** Permission denied */ +#define MNT3ERR_ACCES 13 +/** Not a directory */ +#define MNT3ERR_NOTDIR 20 +/** Invalid argument */ +#define MNT3ERR_INVAL 22 +/** Filename too long */ +#define MNT3ERR_NAMETOOLONG 63 +/** Operation not supported */ +#define MNT3ERR_NOTSUPP 10004 +/** A failure on the server */ +#define MNT3ERR_SERVERFAULT 10006 + + +/** + * A MOUNT MNT reply + * + */ +struct mount_mnt_reply { + /** Reply status */ + uint32_t status; + /** Root file handle */ + struct nfs_fh fh; +}; + +/** + * Prepare an ONC RPC session to be used as a MOUNT session + * + * @v session ONC RPC session + * @v credential ONC RPC credential + * + * The credential parameter must not be NULL, use 'oncrpc_auth_none' if you + * don't want a particular scheme to be used. + */ +static inline void mount_init_session ( struct oncrpc_session *session, + struct oncrpc_cred *credential ) { + oncrpc_init_session ( session, credential, &oncrpc_auth_none, + ONCRPC_MOUNT, MOUNT_VERS ); +} + +int mount_mnt ( struct interface *intf, struct oncrpc_session *session, + const char *mountpoint ); +int mount_umnt ( struct interface *intf, struct oncrpc_session *session, + const char *mountpoint ); + +int mount_get_mnt_reply ( struct mount_mnt_reply *mnt_reply, + struct oncrpc_reply *reply ); + +#endif /* _IPXE_MOUNT_H */ diff --git a/roms/ipxe/src/include/ipxe/ndp.h b/roms/ipxe/src/include/ipxe/ndp.h index 42bb2fe00..7388f938e 100644 --- a/roms/ipxe/src/include/ipxe/ndp.h +++ b/roms/ipxe/src/include/ipxe/ndp.h @@ -1,21 +1,206 @@ +#ifndef _IPXE_NDP_H +#define _IPXE_NDP_H + +/** @file + * + * Neighbour discovery protocol + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> -#include <byteswap.h> -#include <string.h> -#include <ipxe/icmp6.h> -#include <ipxe/ip6.h> #include <ipxe/in.h> -#include <ipxe/netdevice.h> -#include <ipxe/iobuf.h> -#include <ipxe/tcpip.h> - -#define NDP_STATE_INVALID 0 -#define NDP_STATE_INCOMPLETE 1 -#define NDP_STATE_REACHABLE 2 -#define NDP_STATE_DELAY 3 -#define NDP_STATE_PROBE 4 -#define NDP_STATE_STALE 5 - -int ndp_resolve ( struct net_device *netdev, struct in6_addr *src, - struct in6_addr *dest, void *dest_ll_addr ); -int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, - struct sockaddr_tcpip *st_dest ); +#include <ipxe/ipv6.h> +#include <ipxe/icmpv6.h> +#include <ipxe/neighbour.h> + +/** An NDP option header */ +struct ndp_option_header { + /** Type */ + uint8_t type; + /** Length (in blocks of 8 bytes) */ + uint8_t blocks; +} __attribute__ (( packed )); + +/** NDP option block size */ +#define NDP_OPTION_BLKSZ 8U + +/** NDP source link-layer address option */ +#define NDP_OPT_LL_SOURCE 1 + +/** NDP target link-layer address option */ +#define NDP_OPT_LL_TARGET 2 + +/** NDP source or target link-layer address option */ +struct ndp_ll_addr_option { + /** NDP option header */ + struct ndp_option_header header; + /** Link-layer address */ + uint8_t ll_addr[0]; +} __attribute__ (( packed )); + +/** NDP prefix information option */ +#define NDP_OPT_PREFIX 3 + +/** NDP prefix information */ +struct ndp_prefix_information_option { + /** NDP option header */ + struct ndp_option_header header; + /** Prefix length */ + uint8_t prefix_len; + /** Flags */ + uint8_t flags; + /** Valid lifetime */ + uint32_t valid; + /** Preferred lifetime */ + uint32_t preferred; + /** Reserved */ + uint32_t reserved; + /** Prefix */ + struct in6_addr prefix; +} __attribute__ (( packed )); + +/** NDP on-link flag */ +#define NDP_PREFIX_ON_LINK 0x80 + +/** NDP autonomous address configuration flag */ +#define NDP_PREFIX_AUTONOMOUS 0x40 + +/** NDP recursive DNS server option */ +#define NDP_OPT_RDNSS 25 + +/** NDP recursive DNS server */ +struct ndp_rdnss_option { + /** NDP option header */ + struct ndp_option_header header; + /** Reserved */ + uint16_t reserved; + /** Lifetime */ + uint32_t lifetime; + /** Addresses */ + struct in6_addr addresses[0]; +} __attribute__ (( packed )); + +/** NDP DNS search list option */ +#define NDP_OPT_DNSSL 31 + +/** NDP DNS search list */ +struct ndp_dnssl_option { + /** NDP option header */ + struct ndp_option_header header; + /** Reserved */ + uint16_t reserved; + /** Lifetime */ + uint32_t lifetime; + /** Domain names */ + uint8_t names[0]; +} __attribute__ (( packed )); + +/** An NDP option */ +union ndp_option { + /** Option header */ + struct ndp_option_header header; + /** Source or target link-layer address option */ + struct ndp_ll_addr_option ll_addr; + /** Prefix information option */ + struct ndp_prefix_information_option prefix; + /** Recursive DNS server option */ + struct ndp_rdnss_option rdnss; + /** DNS search list option */ + struct ndp_dnssl_option dnssl; +} __attribute__ (( packed )); + +/** An NDP neighbour solicitation or advertisement header */ +struct ndp_neighbour_header { + /** ICMPv6 header */ + struct icmp_header icmp; + /** Flags */ + uint8_t flags; + /** Reserved */ + uint8_t reserved[3]; + /** Target address */ + struct in6_addr target; + /** Options */ + union ndp_option option[0]; +} __attribute__ (( packed )); + +/** NDP router flag */ +#define NDP_NEIGHBOUR_ROUTER 0x80 + +/** NDP solicited flag */ +#define NDP_NEIGHBOUR_SOLICITED 0x40 + +/** NDP override flag */ +#define NDP_NEIGHBOUR_OVERRIDE 0x20 + +/** An NDP router advertisement header */ +struct ndp_router_advertisement_header { + /** ICMPv6 header */ + struct icmp_header icmp; + /** Current hop limit */ + uint8_t hop_limit; + /** Flags */ + uint8_t flags; + /** Router lifetime */ + uint16_t lifetime; + /** Reachable time */ + uint32_t reachable; + /** Retransmission timer */ + uint32_t retransmit; + /** Options */ + union ndp_option option[0]; +} __attribute__ (( packed )); + +/** NDP managed address configuration */ +#define NDP_ROUTER_MANAGED 0x80 + +/** NDP other configuration */ +#define NDP_ROUTER_OTHER 0x40 + +/** An NDP router solicitation header */ +struct ndp_router_solicitation_header { + /** ICMPv6 header */ + struct icmp_header icmp; + /** Reserved */ + uint32_t reserved; + /** Options */ + union ndp_option option[0]; +} __attribute__ (( packed )); + +/** An NDP header */ +union ndp_header { + /** ICMPv6 header */ + struct icmp_header icmp; + /** Neighbour solicitation or advertisement header */ + struct ndp_neighbour_header neigh; + /** Router solicitation header */ + struct ndp_router_solicitation_header rsol; + /** Router advertisement header */ + struct ndp_router_advertisement_header radv; +} __attribute__ (( packed )); + +extern struct neighbour_discovery ndp_discovery; + +/** + * Transmit packet, determining link-layer address via NDP + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @v ll_source Source link-layer address + * @ret rc Return status code + */ +static inline int ndp_tx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *net_dest, const void *net_source, + const void *ll_source ) { + + return neighbour_tx ( iobuf, netdev, &ipv6_protocol, net_dest, + &ndp_discovery, net_source, ll_source ); +} + +/** NDP settings block name */ +#define NDP_SETTINGS_NAME "ndp" + +#endif /* _IPXE_NDP_H */ diff --git a/roms/ipxe/src/include/ipxe/neighbour.h b/roms/ipxe/src/include/ipxe/neighbour.h new file mode 100644 index 000000000..f2a3946f1 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/neighbour.h @@ -0,0 +1,88 @@ +#ifndef _IPXE_NEIGHBOUR_H +#define _IPXE_NEIGHBOUR_H + +/** @file + * + * Neighbour discovery + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/refcnt.h> +#include <ipxe/list.h> +#include <ipxe/netdevice.h> +#include <ipxe/retry.h> + +/** A neighbour discovery protocol */ +struct neighbour_discovery { + /** Name */ + const char *name; + /** + * Transmit neighbour discovery request + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @ret rc Return status code + */ + int ( * tx_request ) ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *net_source ); +}; + +/** A neighbour cache entry */ +struct neighbour { + /** Reference count */ + struct refcnt refcnt; + /** List of neighbour cache entries */ + struct list_head list; + + /** Network device */ + struct net_device *netdev; + /** Network-layer protocol */ + struct net_protocol *net_protocol; + /** Network-layer destination address */ + uint8_t net_dest[MAX_NET_ADDR_LEN]; + /** Link-layer destination address */ + uint8_t ll_dest[MAX_LL_ADDR_LEN]; + + /** Neighbour discovery protocol (if any) */ + struct neighbour_discovery *discovery; + /** Network-layer source address (if any) */ + uint8_t net_source[MAX_NET_ADDR_LEN]; + /** Retransmission timer */ + struct retry_timer timer; + + /** Pending I/O buffers */ + struct list_head tx_queue; +}; + +/** + * Test if neighbour cache entry has a valid link-layer address + * + * @v neighbour Neighbour cache entry + * @ret has_ll_dest Neighbour cache entry has a valid link-layer address + */ +static inline __attribute__ (( always_inline )) int +neighbour_has_ll_dest ( struct neighbour *neighbour ) { + return ( ! timer_running ( &neighbour->timer ) ); +} + +extern struct list_head neighbours; + +extern int neighbour_tx ( struct io_buffer *iobuf, struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, + struct neighbour_discovery *discovery, + const void *net_source, const void *ll_source ); +extern int neighbour_update ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *ll_dest ); +extern int neighbour_define ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *ll_dest ); + +#endif /* _IPXE_NEIGHBOUR_H */ diff --git a/roms/ipxe/src/include/ipxe/net80211.h b/roms/ipxe/src/include/ipxe/net80211.h index 771872c82..9ed0fa9b1 100644 --- a/roms/ipxe/src/include/ipxe/net80211.h +++ b/roms/ipxe/src/include/ipxe/net80211.h @@ -1093,7 +1093,8 @@ struct net80211_wlan /** 802.11 encryption key setting */ -extern struct setting net80211_key_setting __setting ( SETTING_NETDEV_EXTRA ); +extern const struct setting +net80211_key_setting __setting ( SETTING_NETDEV_EXTRA, key ); /** @@ -1183,25 +1184,4 @@ static inline u16 net80211_cts_duration ( struct net80211_device *dev, net80211_duration ( dev, size, dev->rates[dev->rate] ) ); } -/** 802.11 device setting tag magic */ -#define NET80211_SETTING_TAG_MAGIC 0x8211 - -/** - * Construct 802.11 setting tag - * - * @v id Unique identifier - * @ret tag Setting tag - */ -#define NET80211_SETTING_TAG( id ) \ - NETDEV_SETTING_TAG ( ( NET80211_SETTING_TAG_MAGIC << 8 ) | (id) ) - -/** SSID setting tag */ -#define NET80211_SETTING_TAG_SSID NET80211_SETTING_TAG ( 0x01 ) - -/** Active scanning setting tag */ -#define NET80211_SETTING_TAG_ACTIVE_SCAN NET80211_SETTING_TAG ( 0x02 ) - -/** Wireless key setting tag */ -#define NET80211_SETTING_TAG_KEY NET80211_SETTING_TAG ( 0x03 ) - #endif diff --git a/roms/ipxe/src/include/ipxe/net80211_err.h b/roms/ipxe/src/include/ipxe/net80211_err.h index 2175b1438..7df3d0d85 100644 --- a/roms/ipxe/src/include/ipxe/net80211_err.h +++ b/roms/ipxe/src/include/ipxe/net80211_err.h @@ -553,81 +553,83 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Make return status code from 802.11 status code */ #define E80211_STATUS( stat ) \ - EUNIQ ( ( ( stat & 0x20 ) ? EHOSTUNREACH : ECONNREFUSED ), \ - ( stat &0x1f ), \ - ECONNREFUSED_FAILURE, \ - ECONNREFUSED_CAPAB_UNSUPP, \ - ECONNREFUSED_REASSOC_INVALID, \ - ECONNREFUSED_ASSOC_DENIED, \ - ECONNREFUSED_AUTH_ALGO_UNSUPP, \ - ECONNREFUSED_AUTH_SEQ_INVALID, \ - ECONNREFUSED_AUTH_CHALL_INVALID, \ - ECONNREFUSED_AUTH_TIMEOUT, \ - ECONNREFUSED_ASSOC_NO_ROOM, \ - ECONNREFUSED_ASSOC_NEED_RATE, \ - ECONNREFUSED_ASSOC_NEED_SHORT_PMBL, \ - ECONNREFUSED_ASSOC_NEED_PBCC, \ - ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY, \ - ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT, \ - ECONNREFUSED_ASSOC_BAD_POWER, \ - ECONNREFUSED_ASSOC_BAD_CHANNELS, \ - ECONNREFUSED_ASSOC_NEED_SHORT_SLOT, \ - ECONNREFUSED_ASSOC_NEED_DSSS_OFDM, \ - EHOSTUNREACH_QOS_FAILURE, \ - EHOSTUNREACH_QOS_NO_ROOM, \ - EHOSTUNREACH_LINK_IS_HORRIBLE, \ - EHOSTUNREACH_ASSOC_NEED_QOS, \ - EHOSTUNREACH_REQUEST_DECLINED, \ - EHOSTUNREACH_REQUEST_INVALID, \ - EHOSTUNREACH_TS_NOT_CREATED_AGAIN, \ - EHOSTUNREACH_INVALID_IE, \ - EHOSTUNREACH_GROUP_CIPHER_INVALID, \ - EHOSTUNREACH_PAIR_CIPHER_INVALID, \ - EHOSTUNREACH_AKMP_INVALID, \ - EHOSTUNREACH_RSN_VERSION_UNSUPP, \ - EHOSTUNREACH_RSN_CAPAB_INVALID, \ - EHOSTUNREACH_CIPHER_REJECTED, \ - EHOSTUNREACH_TS_NOT_CREATED_WAIT, \ - EHOSTUNREACH_DIRECT_LINK_FORBIDDEN, \ - EHOSTUNREACH_DEST_NOT_PRESENT, \ - EHOSTUNREACH_DEST_NOT_QOS, \ - EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH ) + ( ( (stat) & 0x20 ) ? \ + EUNIQ ( EINFO_EHOSTUNREACH, ( (stat) & 0x1f ), \ + EHOSTUNREACH_QOS_FAILURE, \ + EHOSTUNREACH_QOS_NO_ROOM, \ + EHOSTUNREACH_LINK_IS_HORRIBLE, \ + EHOSTUNREACH_ASSOC_NEED_QOS, \ + EHOSTUNREACH_REQUEST_DECLINED, \ + EHOSTUNREACH_REQUEST_INVALID, \ + EHOSTUNREACH_TS_NOT_CREATED_AGAIN, \ + EHOSTUNREACH_INVALID_IE, \ + EHOSTUNREACH_GROUP_CIPHER_INVALID, \ + EHOSTUNREACH_PAIR_CIPHER_INVALID, \ + EHOSTUNREACH_AKMP_INVALID, \ + EHOSTUNREACH_RSN_VERSION_UNSUPP, \ + EHOSTUNREACH_RSN_CAPAB_INVALID, \ + EHOSTUNREACH_CIPHER_REJECTED, \ + EHOSTUNREACH_TS_NOT_CREATED_WAIT, \ + EHOSTUNREACH_DIRECT_LINK_FORBIDDEN, \ + EHOSTUNREACH_DEST_NOT_PRESENT, \ + EHOSTUNREACH_DEST_NOT_QOS, \ + EHOSTUNREACH_ASSOC_LISTEN_TOO_HIGH ) : \ + EUNIQ ( EINFO_ECONNREFUSED, ( (stat) & 0x1f ), \ + ECONNREFUSED_FAILURE, \ + ECONNREFUSED_CAPAB_UNSUPP, \ + ECONNREFUSED_REASSOC_INVALID, \ + ECONNREFUSED_ASSOC_DENIED, \ + ECONNREFUSED_AUTH_ALGO_UNSUPP, \ + ECONNREFUSED_AUTH_SEQ_INVALID, \ + ECONNREFUSED_AUTH_CHALL_INVALID, \ + ECONNREFUSED_AUTH_TIMEOUT, \ + ECONNREFUSED_ASSOC_NO_ROOM, \ + ECONNREFUSED_ASSOC_NEED_RATE, \ + ECONNREFUSED_ASSOC_NEED_SHORT_PMBL, \ + ECONNREFUSED_ASSOC_NEED_PBCC, \ + ECONNREFUSED_ASSOC_NEED_CHAN_AGILITY, \ + ECONNREFUSED_ASSOC_NEED_SPECTRUM_MGMT, \ + ECONNREFUSED_ASSOC_BAD_POWER, \ + ECONNREFUSED_ASSOC_BAD_CHANNELS, \ + ECONNREFUSED_ASSOC_NEED_SHORT_SLOT, \ + ECONNREFUSED_ASSOC_NEED_DSSS_OFDM ) ) /** Make return status code from 802.11 reason code */ #define E80211_REASON( reas ) \ - EUNIQ ( ( ( reas & 0x20 ) ? ENETRESET : ECONNRESET ), \ - ( reas & 0x1f ), \ - ECONNRESET_UNSPECIFIED, \ - ECONNRESET_AUTH_NO_LONGER_VALID, \ - ECONNRESET_LEAVING, \ - ECONNRESET_INACTIVITY, \ - ECONNRESET_OUT_OF_RESOURCES, \ - ECONNRESET_NEED_AUTH, \ - ECONNRESET_NEED_ASSOC, \ - ECONNRESET_LEAVING_TO_ROAM, \ - ECONNRESET_REASSOC_INVALID, \ - ECONNRESET_BAD_POWER, \ - ECONNRESET_BAD_CHANNELS, \ - ECONNRESET_INVALID_IE, \ - ECONNRESET_MIC_FAILURE, \ - ECONNRESET_4WAY_TIMEOUT, \ - ECONNRESET_GROUPKEY_TIMEOUT, \ - ECONNRESET_4WAY_INVALID, \ - ECONNRESET_GROUP_CIPHER_INVALID, \ - ECONNRESET_PAIR_CIPHER_INVALID, \ - ECONNRESET_AKMP_INVALID, \ - ECONNRESET_RSN_VERSION_INVALID, \ - ECONNRESET_RSN_CAPAB_INVALID, \ - ECONNRESET_8021X_FAILURE, \ - ECONNRESET_CIPHER_REJECTED, \ - ENETRESET_QOS_UNSPECIFIED, \ - ENETRESET_QOS_OUT_OF_RESOURCES, \ - ENETRESET_LINK_IS_HORRIBLE, \ - ENETRESET_INVALID_TXOP, \ - ENETRESET_REQUESTED_LEAVING, \ - ENETRESET_REQUESTED_NO_USE, \ - ENETRESET_REQUESTED_NEED_SETUP, \ - ENETRESET_REQUESTED_TIMEOUT, \ - ENETRESET_CIPHER_UNSUPPORTED ) + ( ( (reas) & 0x20 ) ? \ + EUNIQ ( EINFO_ENETRESET, ( (reas) & 0x1f ), \ + ENETRESET_QOS_UNSPECIFIED, \ + ENETRESET_QOS_OUT_OF_RESOURCES, \ + ENETRESET_LINK_IS_HORRIBLE, \ + ENETRESET_INVALID_TXOP, \ + ENETRESET_REQUESTED_LEAVING, \ + ENETRESET_REQUESTED_NO_USE, \ + ENETRESET_REQUESTED_NEED_SETUP, \ + ENETRESET_REQUESTED_TIMEOUT, \ + ENETRESET_CIPHER_UNSUPPORTED ) : \ + EUNIQ ( EINFO_ECONNRESET, ( (reas) & 0x1f ), \ + ECONNRESET_UNSPECIFIED, \ + ECONNRESET_AUTH_NO_LONGER_VALID, \ + ECONNRESET_LEAVING, \ + ECONNRESET_INACTIVITY, \ + ECONNRESET_OUT_OF_RESOURCES, \ + ECONNRESET_NEED_AUTH, \ + ECONNRESET_NEED_ASSOC, \ + ECONNRESET_LEAVING_TO_ROAM, \ + ECONNRESET_REASSOC_INVALID, \ + ECONNRESET_BAD_POWER, \ + ECONNRESET_BAD_CHANNELS, \ + ECONNRESET_INVALID_IE, \ + ECONNRESET_MIC_FAILURE, \ + ECONNRESET_4WAY_TIMEOUT, \ + ECONNRESET_GROUPKEY_TIMEOUT, \ + ECONNRESET_4WAY_INVALID, \ + ECONNRESET_GROUP_CIPHER_INVALID, \ + ECONNRESET_PAIR_CIPHER_INVALID, \ + ECONNRESET_AKMP_INVALID, \ + ECONNRESET_RSN_VERSION_INVALID, \ + ECONNRESET_RSN_CAPAB_INVALID, \ + ECONNRESET_8021X_FAILURE, \ + ECONNRESET_CIPHER_REJECTED ) ) #endif /* _IPXE_NET80211_ERR_H */ diff --git a/roms/ipxe/src/include/ipxe/netdevice.h b/roms/ipxe/src/include/ipxe/netdevice.h index e5dbd996b..6ef9cb1e5 100644 --- a/roms/ipxe/src/include/ipxe/netdevice.h +++ b/roms/ipxe/src/include/ipxe/netdevice.h @@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/tables.h> #include <ipxe/refcnt.h> #include <ipxe/settings.h> +#include <ipxe/interface.h> struct io_buffer; struct net_device; @@ -44,7 +45,7 @@ struct device; #define MAX_LL_HEADER_LEN 36 /** Maximum length of a network-layer address */ -#define MAX_NET_ADDR_LEN 4 +#define MAX_NET_ADDR_LEN 16 /** Maximum length of a network-layer header * @@ -175,8 +176,17 @@ struct ll_protocol { * * @v ll_addr Link-layer address * @v eth_addr Ethernet-compatible address to fill in + * @ret rc Return status code */ int ( * eth_addr ) ( const void *ll_addr, void *eth_addr ); + /** + * Generate EUI-64 address + * + * @v ll_addr Link-layer address + * @v eui64 EUI-64 address to fill in + * @ret rc Return status code + */ + int ( * eui64 ) ( const void *ll_addr, void *eui64 ); /** Link-layer protocol * * This is an ARPHRD_XXX constant, in network byte order. @@ -283,6 +293,48 @@ struct net_device_stats { struct net_device_error errors[NETDEV_MAX_UNIQUE_ERRORS]; }; +/** A network device configuration */ +struct net_device_configuration { + /** Network device */ + struct net_device *netdev; + /** Network device configurator */ + struct net_device_configurator *configurator; + /** Configuration status */ + int rc; + /** Job control interface */ + struct interface job; +}; + +/** A network device configurator */ +struct net_device_configurator { + /** Name */ + const char *name; + /** Check applicability of configurator + * + * @v netdev Network device + * @ret applies Configurator applies to this network device + */ + int ( * applies ) ( struct net_device *netdev ); + /** Start configuring network device + * + * @v job Job control interface + * @v netdev Network device + * @ret rc Return status code + */ + int ( * start ) ( struct interface *job, struct net_device *netdev ); +}; + +/** Network device configurator table */ +#define NET_DEVICE_CONFIGURATORS \ + __table ( struct net_device_configurator, "net_device_configurators" ) + +/** Declare a network device configurator */ +#define __net_device_configurator \ + __table_entry ( NET_DEVICE_CONFIGURATORS, 01 ) + +/** Maximum length of a network device name */ +#define NETDEV_NAME_LEN 12 + /** * A network device * @@ -300,8 +352,10 @@ struct net_device { struct list_head list; /** List of open network devices */ struct list_head open_list; + /** Index of this network device */ + unsigned int index; /** Name of this network device */ - char name[12]; + char name[NETDEV_NAME_LEN]; /** Underlying hardware device */ struct device *dev; @@ -346,6 +400,8 @@ struct net_device { size_t max_pkt_len; /** TX packet queue */ struct list_head tx_queue; + /** Deferred TX packet queue */ + struct list_head tx_deferred; /** RX packet queue */ struct list_head rx_queue; /** TX statistics */ @@ -358,6 +414,9 @@ struct net_device { /** Driver private data */ void *priv; + + /** Network device configurations (variable length) */ + struct net_device_configuration configs[0]; }; /** Network device is open */ @@ -409,38 +468,6 @@ struct net_driver { /** Declare a network driver */ #define __net_driver __table_entry ( NET_DRIVERS, 01 ) -/** Network device setting tag magic - * - * All DHCP option settings are deemed to be valid as network device - * settings. There are also some extra non-DHCP settings (such as - * "mac"), which are marked as being valid network device settings by - * using a magic tag value. - */ -#define NETDEV_SETTING_TAG_MAGIC 0xeb - -/** - * Construct network device setting tag - * - * @v id Unique identifier - * @ret tag Setting tag - */ -#define NETDEV_SETTING_TAG( id ) ( ( NETDEV_SETTING_TAG_MAGIC << 24 ) | (id) ) - -/** - * Check if tag is a network device setting tag - * - * @v tag Setting tag - * @ret is_ours Tag is a network device setting tag - */ -#define IS_NETDEV_SETTING_TAG( tag ) \ - ( ( (tag) >> 24 ) == NETDEV_SETTING_TAG_MAGIC ) - -/** MAC address setting tag */ -#define NETDEV_SETTING_TAG_MAC NETDEV_SETTING_TAG ( 0x01 ) - -/** Bus ID setting tag */ -#define NETDEV_SETTING_TAG_BUS_ID NETDEV_SETTING_TAG ( 0x02 ) - extern struct list_head net_devices; extern struct net_device_operations null_netdev_operations; extern struct settings_operations netdev_settings_operations; @@ -548,6 +575,35 @@ netdev_settings_init ( struct net_device *netdev ) { } /** + * Get network device configuration + * + * @v netdev Network device + * @v configurator Network device configurator + * @ret config Network device configuration + */ +static inline struct net_device_configuration * +netdev_configuration ( struct net_device *netdev, + struct net_device_configurator *configurator ) { + + return &netdev->configs[ table_index ( NET_DEVICE_CONFIGURATORS, + configurator ) ]; +} + +/** + * Check if configurator applies to network device + * + * @v netdev Network device + * @v configurator Network device configurator + * @ret applies Configurator applies to network device + */ +static inline int +netdev_configurator_applies ( struct net_device *netdev, + struct net_device_configurator *configurator ) { + return ( ( configurator->applies == NULL ) || + configurator->applies ( netdev ) ); +} + +/** * Check link state of network device * * @v netdev Network device @@ -602,9 +658,13 @@ netdev_rx_frozen ( struct net_device *netdev ) { return ( netdev->state & NETDEV_RX_FROZEN ); } +extern void netdev_rx_freeze ( struct net_device *netdev ); +extern void netdev_rx_unfreeze ( struct net_device *netdev ); extern void netdev_link_err ( struct net_device *netdev, int rc ); extern void netdev_link_down ( struct net_device *netdev ); extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); +extern void netdev_tx_defer ( struct net_device *netdev, + struct io_buffer *iobuf ); extern void netdev_tx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ); extern void netdev_tx_complete_err ( struct net_device *netdev, @@ -622,6 +682,7 @@ extern void netdev_close ( struct net_device *netdev ); extern void unregister_netdev ( struct net_device *netdev ); extern void netdev_irq ( struct net_device *netdev, int enable ); extern struct net_device * find_netdev ( const char *name ); +extern struct net_device * find_netdev_by_index ( unsigned int index ); extern struct net_device * find_netdev_by_location ( unsigned int bus_type, unsigned int location ); extern struct net_device * last_opened_netdev ( void ); @@ -632,6 +693,13 @@ extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, uint16_t net_proto, const void *ll_dest, const void *ll_source, unsigned int flags ); extern void net_poll ( void ); +extern struct net_device_configurator * +find_netdev_configurator ( const char *name ); +extern int netdev_configure ( struct net_device *netdev, + struct net_device_configurator *configurator ); +extern int netdev_configure_all ( struct net_device *netdev ); +extern int netdev_configuration_in_progress ( struct net_device *netdev ); +extern int netdev_configuration_ok ( struct net_device *netdev ); /** * Complete network transmission @@ -667,24 +735,4 @@ netdev_link_up ( struct net_device *netdev ) { netdev_link_err ( netdev, 0 ); } -/** - * Freeze network device receive queue processing - * - * @v netdev Network device - */ -static inline __attribute__ (( always_inline )) void -netdev_rx_freeze ( struct net_device *netdev ) { - netdev->state |= NETDEV_RX_FROZEN; -} - -/** - * Unfreeze network device receive queue processing - * - * @v netdev Network device - */ -static inline __attribute__ (( always_inline )) void -netdev_rx_unfreeze ( struct net_device *netdev ) { - netdev->state &= ~NETDEV_RX_FROZEN; -} - #endif /* _IPXE_NETDEVICE_H */ diff --git a/roms/ipxe/src/include/ipxe/nfs.h b/roms/ipxe/src/include/ipxe/nfs.h new file mode 100644 index 000000000..498ed5a27 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/nfs.h @@ -0,0 +1,157 @@ +#ifndef _IPXE_NFS_H +#define _IPXE_NFS_H + +#include <stdint.h> +#include <ipxe/oncrpc.h> + +/** @file + * + * Network File System protocol. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** NFS protocol number */ +#define ONCRPC_NFS 100003 + +/** NFS protocol version */ +#define NFS_VERS 3 + +/** No error*/ +#define NFS3_OK 0 +/** Not owner */ +#define NFS3ERR_PERM 1 +/** No such file or directory */ +#define NFS3ERR_NOENT 2 +/** I/O error */ +#define NFS3ERR_IO 5 +/** No such device or address */ +#define NFS3ERR_NXIO 6 +/** Permission denied */ +#define NFS3ERR_ACCES 13 +/** The file specified already exists */ +#define NFS3ERR_EXIST 17 +/** Attempt to do a cross-device hard link */ +#define NFS3ERR_XDEV 18 +/** No such device */ +#define NFS3ERR_NODEV 19 +/** Not a directory */ +#define NFS3ERR_NOTDIR 20 + /**Is a directory */ +#define NFS3ERR_ISDIR 21 +/** Invalid argument */ +#define NFS3ERR_INVAL 22 +/** Filename too long */ +#define NFS3ERR_NAMETOOLONG 63 +/** Invalid file handle */ +#define NFS3ERR_STALE 70 +/** Too many levels of remote in path */ +#define NFS3ERR_REMOTE 71 +/** Illegal NFS file handle */ +#define NFS3ERR_BADHANDLE 10001 +/** READDIR or READDIRPLUS cookie is stale */ +#define NFS3ERR_BAD_COOKIE 10003 +/** Operation not supported */ +#define NFS3ERR_NOTSUPP 10004 +/** Buffer or request is too small */ +#define NFS3ERR_TOOSMALL 10005 +/** An error occurred on the server which does not map to any of the legal NFS + * version 3 protocol error values */ +#define NFS3ERR_SERVERFAULT 10006 +/** The server initiated the request, but was not able to complete it in a + * timely fashion */ +#define NFS3ERR_JUKEBOX 10008 + +enum nfs_attr_type { + NFS_ATTR_SYMLINK = 5, +}; + +/** + * A NFS file handle + * + */ +struct nfs_fh { + uint8_t fh[64]; + size_t size; +}; + +/** + * A NFS LOOKUP reply + * + */ +struct nfs_lookup_reply { + /** Reply status */ + uint32_t status; + /** Entity type */ + enum nfs_attr_type ent_type; + /** File handle */ + struct nfs_fh fh; +}; + +/** + * A NFS READLINK reply + * + */ +struct nfs_readlink_reply { + /** Reply status */ + uint32_t status; + /** File path length */ + uint32_t path_len; + /** File path */ + char *path; +}; + + +/** + * A NFS READ reply + * + */ +struct nfs_read_reply { + /** Reply status */ + uint32_t status; + /** File size */ + uint64_t filesize; + /** Bytes read */ + uint32_t count; + /** End-of-File indicator */ + uint32_t eof; + /** Data length */ + uint32_t data_len; + /** Data read */ + void *data; +}; + +size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh ); +size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh ); + +/** + * Prepare an ONC RPC session to be used as a NFS session + * + * @v session ONC RPC session + * @v credential ONC RPC credential + * + * The credential parameter must not be NULL, use 'oncrpc_auth_none' if you + * don't want a particular scheme to be used. + */ +static inline void nfs_init_session ( struct oncrpc_session *session, + struct oncrpc_cred *credential ) { + oncrpc_init_session ( session, credential, &oncrpc_auth_none, + ONCRPC_NFS, NFS_VERS ); +} + +int nfs_lookup ( struct interface *intf, struct oncrpc_session *session, + const struct nfs_fh *fh, const char *filename ); +int nfs_readlink ( struct interface *intf, struct oncrpc_session *session, + const struct nfs_fh *fh ); +int nfs_read ( struct interface *intf, struct oncrpc_session *session, + const struct nfs_fh *fh, uint64_t offset, uint32_t count ); + +int nfs_get_lookup_reply ( struct nfs_lookup_reply *lookup_reply, + struct oncrpc_reply *reply ); +int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply, + struct oncrpc_reply *reply ); +int nfs_get_read_reply ( struct nfs_read_reply *read_reply, + struct oncrpc_reply *reply ); + +#endif /* _IPXE_NFS_H */ diff --git a/roms/ipxe/src/include/ipxe/nfs_open.h b/roms/ipxe/src/include/ipxe/nfs_open.h new file mode 100644 index 000000000..caba977f7 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/nfs_open.h @@ -0,0 +1,12 @@ +#ifndef _IPXE_NFS_OPEN_H +#define _IPXE_NFS_OPEN_H + +/** @file + * + * Network File System protocol. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#endif /* _IPXE_NFS_OPEN_H */ diff --git a/roms/ipxe/src/include/ipxe/null_reboot.h b/roms/ipxe/src/include/ipxe/null_reboot.h new file mode 100644 index 000000000..3de36c5b3 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/null_reboot.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_NULL_REBOOT_H +#define _IPXE_NULL_REBOOT_H + +/** @file + * + * iPXE do-nothing reboot API + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#ifdef REBOOT_NULL +#define REBOOT_PREFIX_null +#else +#define REBOOT_PREFIX_null __null_ +#endif + +#endif /* _IPXE_NULL_REBOOT_H */ diff --git a/roms/ipxe/src/include/ipxe/nvo.h b/roms/ipxe/src/include/ipxe/nvo.h index 487f8b3f2..1a629da78 100644 --- a/roms/ipxe/src/include/ipxe/nvo.h +++ b/roms/ipxe/src/include/ipxe/nvo.h @@ -45,7 +45,8 @@ struct nvo_block { /** Name of non-volatile options settings block */ #define NVO_SETTINGS_NAME "nvo" -extern int nvo_applies ( struct settings *settings, struct setting *setting ); +extern int nvo_applies ( struct settings *settings, + const struct setting *setting ); extern void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs, size_t address, size_t len, int ( * resize ) ( struct nvo_block *nvo, size_t len ), diff --git a/roms/ipxe/src/include/ipxe/ocsp.h b/roms/ipxe/src/include/ipxe/ocsp.h index fe825fd06..387e28f81 100644 --- a/roms/ipxe/src/include/ipxe/ocsp.h +++ b/roms/ipxe/src/include/ipxe/ocsp.h @@ -28,6 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define OCSP_STATUS_SIG_REQUIRED 0x05 #define OCSP_STATUS_UNAUTHORIZED 0x06 +struct ocsp_check; + /** An OCSP request */ struct ocsp_request { /** Request builder */ @@ -36,12 +38,29 @@ struct ocsp_request { struct asn1_cursor cert_id; }; +/** An OCSP responder */ +struct ocsp_responder { + /** + * Check if certificate is the responder's certificate + * + * @v ocsp OCSP check + * @v cert Certificate + * @ret difference Difference as returned by memcmp() + */ + int ( * compare ) ( struct ocsp_check *ocsp, + struct x509_certificate *cert ); + /** Responder ID */ + struct asn1_cursor id; +}; + /** An OCSP response */ struct ocsp_response { /** Raw response */ void *data; /** Raw tbsResponseData */ struct asn1_cursor tbs; + /** Responder */ + struct ocsp_responder responder; /** Time at which status is known to be correct */ time_t this_update; /** Time at which newer status information will be available */ diff --git a/roms/ipxe/src/include/ipxe/oncrpc.h b/roms/ipxe/src/include/ipxe/oncrpc.h new file mode 100644 index 000000000..76c1260f2 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/oncrpc.h @@ -0,0 +1,128 @@ +#ifndef _IPXE_ONCRPC_H +#define _IPXE_ONCRPC_H + +#include <stdint.h> +#include <ipxe/interface.h> +#include <ipxe/iobuf.h> + +/** @file + * + * SUN ONC RPC protocol. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** ONC RCP Version */ +#define ONCRPC_VERS 2 + +/** ONC RPC Null Authentication */ +#define ONCRPC_AUTH_NONE 0 + +/** ONC RPC System Authentication (also called UNIX Authentication) */ +#define ONCRPC_AUTH_SYS 1 + +/** Size of an ONC RPC header */ +#define ONCRPC_HEADER_SIZE ( 11 * sizeof ( uint32_t ) ) + +#define ONCRPC_FIELD( type, value ) { oncrpc_ ## type, { .type = value } } +#define ONCRPC_SUBFIELD( type, args... ) \ + { oncrpc_ ## type, { .type = { args } } } + +#define ONCRPC_FIELD_END { oncrpc_none, { } } + +/** Enusure that size is a multiple of four */ +#define oncrpc_align( size ) ( ( (size) + 3 ) & ~3 ) + +/** + * Calculate the length of a string, including padding bytes. + * + * @v str String + * @ret size Length of the padded string + */ +#define oncrpc_strlen( str ) ( oncrpc_align ( strlen ( str ) ) + \ + sizeof ( uint32_t ) ) + +struct oncrpc_cred { + uint32_t flavor; + uint32_t length; +}; + +struct oncrpc_cred_sys { + struct oncrpc_cred credential; + uint32_t stamp; + char *hostname; + uint32_t uid; + uint32_t gid; + uint32_t aux_gid_len; + uint32_t aux_gid[16]; +}; + +struct oncrpc_reply +{ + struct oncrpc_cred *verifier; + uint32_t rpc_id; + uint32_t reply_state; + uint32_t accept_state; + uint32_t frame_size; + struct io_buffer *data; +}; + +struct oncrpc_session { + struct oncrpc_reply pending_reply; + struct oncrpc_cred *credential; + struct oncrpc_cred *verifier; + uint32_t rpc_id; + uint32_t prog_name; + uint32_t prog_vers; +}; + +enum oncrpc_field_type { + oncrpc_none = 0, + oncrpc_int32, + oncrpc_int64, + oncrpc_str, + oncrpc_array, + oncrpc_intarray, + oncrpc_cred, +}; + +union oncrpc_field_value { + struct { + size_t length; + const void *ptr; + } array; + + struct { + size_t length; + const uint32_t *ptr; + } intarray; + + int64_t int64; + int32_t int32; + const char *str; + const struct oncrpc_cred *cred; +}; + +struct oncrpc_field { + enum oncrpc_field_type type; + union oncrpc_field_value value; +}; + +extern struct oncrpc_cred oncrpc_auth_none; + +int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys ); +void oncrpc_init_session ( struct oncrpc_session *session, + struct oncrpc_cred *credential, + struct oncrpc_cred *verifier, uint32_t prog_name, + uint32_t prog_vers ); + +int oncrpc_call ( struct interface *intf, struct oncrpc_session *session, + uint32_t proc_name, const struct oncrpc_field fields[] ); + +size_t oncrpc_compute_size ( const struct oncrpc_field fields[] ); + +int oncrpc_get_reply ( struct oncrpc_session *session, + struct oncrpc_reply *reply, struct io_buffer *io_buf ); + +#endif /* _IPXE_ONCRPC_H */ diff --git a/roms/ipxe/src/include/ipxe/oncrpc_iob.h b/roms/ipxe/src/include/ipxe/oncrpc_iob.h new file mode 100644 index 000000000..4858d96b5 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/oncrpc_iob.h @@ -0,0 +1,102 @@ +#ifndef _IPXE_ONCRPC_IOB_H +#define _IPXE_ONCRPC_IOB_H + +#include <stdint.h> +#include <string.h> +#include <ipxe/iobuf.h> +#include <ipxe/refcnt.h> +#include <ipxe/oncrpc.h> + +/** @file + * + * SUN ONC RPC protocol. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Add a string to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v val String + * @ret size Size of the data written + */ +#define oncrpc_iob_add_string( buf, str ) \ +( { \ + const char * _str = (str); \ + oncrpc_iob_add_array ( (buf), strlen ( _str ), _str ); \ +} ) + +/** + * Get a 32 bits integer from the beginning of an I/O buffer + * + * @v buf I/O buffer + * @ret int Integer + */ + +#define oncrpc_iob_get_int( buf ) \ +( { \ + uint32_t *_val; \ + _val = (buf)->data; \ + iob_pull ( (buf), sizeof ( uint32_t ) ); \ + ntohl ( *_val ); \ +} ) + +/** + * Get a 64 bits integer from the beginning of an I/O buffer + * + * @v buf I/O buffer + * @ret int Integer + */ +#define oncrpc_iob_get_int64( buf ) \ +( { \ + uint64_t *_val; \ + _val = (buf)->data; \ + iob_pull ( (buf), sizeof ( uint64_t ) ); \ + ntohll ( *_val ); \ +} ) + + +size_t oncrpc_iob_add_fields ( struct io_buffer *io_buf, + const struct oncrpc_field fields[] ); + +size_t oncrpc_iob_add_array ( struct io_buffer *io_buf, size_t length, + const void *data ); + +size_t oncrpc_iob_add_intarray ( struct io_buffer *io_buf, size_t length, + const uint32_t *array ); + +size_t oncrpc_iob_add_cred ( struct io_buffer *io_buf, + const struct oncrpc_cred *cred ); + +size_t oncrpc_iob_get_cred ( struct io_buffer *io_buf, + struct oncrpc_cred *cred ); + +/** + * Add a 32 bits integer to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v val Integer + * @ret size Size of the data written + */ +static inline size_t oncrpc_iob_add_int ( struct io_buffer *io_buf, + uint32_t val ) { + * ( uint32_t * ) iob_put ( io_buf, sizeof ( val ) ) = htonl ( val ); + return ( sizeof ( val) ); +} + +/** + * Add a 64 bits integer to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v val Integer + * @ret size Size of the data written + */ +static inline size_t oncrpc_iob_add_int64 ( struct io_buffer *io_buf, + uint64_t val ) { + * ( uint64_t * ) iob_put ( io_buf, sizeof ( val ) ) = htonll ( val ); + return ( sizeof ( val) ); +} + +#endif /* _IPXE_ONCRPC_IOB_H */ diff --git a/roms/ipxe/src/include/ipxe/params.h b/roms/ipxe/src/include/ipxe/params.h new file mode 100644 index 000000000..c2d82d9cf --- /dev/null +++ b/roms/ipxe/src/include/ipxe/params.h @@ -0,0 +1,83 @@ +#ifndef _IPXE_PARAMS_H +#define _IPXE_PARAMS_H + +/** @file + * + * Form parameters + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/list.h> +#include <ipxe/refcnt.h> + +/** A form parameter list */ +struct parameters { + /** Reference count */ + struct refcnt refcnt; + /** List of all parameter lists */ + struct list_head list; + /** Name */ + const char *name; + /** Parameters */ + struct list_head entries; +}; + +/** A form parameter */ +struct parameter { + /** List of form parameters */ + struct list_head list; + /** Key */ + const char *key; + /** Value */ + const char *value; +}; + +/** + * Increment form parameter list reference count + * + * @v params Parameter list, or NULL + * @ret params Parameter list as passed in + */ +static inline __attribute__ (( always_inline )) struct parameters * +params_get ( struct parameters *params ) { + ref_get ( ¶ms->refcnt ); + return params; +} + +/** + * Decrement form parameter list reference count + * + * @v params Parameter list, or NULL + */ +static inline __attribute__ (( always_inline )) void +params_put ( struct parameters *params ) { + ref_put ( ¶ms->refcnt ); +} + +/** + * Claim ownership of form parameter list + * + * @v params Parameter list + * @ret params Parameter list + */ +static inline __attribute__ (( always_inline )) struct parameters * +claim_parameters ( struct parameters *params ) { + + /* Remove from list of parameter lists */ + list_del ( ¶ms->list ); + + return params; +} + +/** Iterate over all form parameters in a list */ +#define for_each_param( param, params ) \ + list_for_each_entry ( (param), &(params)->entries, list ) + +extern struct parameters * find_parameters ( const char *name ); +extern struct parameters * create_parameters ( const char *name ); +extern struct parameter * add_parameter ( struct parameters *params, + const char *key, const char *value ); + +#endif /* _IPXE_PARAMS_H */ diff --git a/roms/ipxe/src/include/ipxe/parseopt.h b/roms/ipxe/src/include/ipxe/parseopt.h index b492a51e5..840de7497 100644 --- a/roms/ipxe/src/include/ipxe/parseopt.h +++ b/roms/ipxe/src/include/ipxe/parseopt.h @@ -11,9 +11,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> #include <stddef.h> +#include <ipxe/settings.h> struct net_device; +struct net_device_configurator; struct menu; +struct parameters; /** A command-line option descriptor */ struct option_descriptor { @@ -31,7 +34,7 @@ struct option_descriptor { * @v value Option value to fill in * @ret rc Return status code */ - int ( * parse ) ( const char *text, void *value ); + int ( * parse ) ( char *text, void *value ); }; /** @@ -43,9 +46,9 @@ struct option_descriptor { * @ret _parse Generic option parser */ #define OPTION_PARSER( _struct, _field, _parse ) \ - ( ( int ( * ) ( const char *text, void *value ) ) \ + ( ( int ( * ) ( char *text, void *value ) ) \ ( ( ( ( typeof ( _parse ) * ) NULL ) == \ - ( ( int ( * ) ( const char *text, \ + ( ( int ( * ) ( char *text, \ typeof ( ( ( _struct * ) NULL )->_field ) * ) ) \ NULL ) ) ? _parse : _parse ) ) @@ -114,12 +117,31 @@ struct command_descriptor { .usage = _usage, \ } -extern int parse_string ( const char *text, const char **value ); -extern int parse_integer ( const char *text, unsigned int *value ); -extern int parse_netdev ( const char *text, struct net_device **netdev ); -extern int parse_menu ( const char *text, struct menu **menu ); -extern int parse_flag ( const char *text __unused, int *flag ); -extern int parse_key ( const char *text, unsigned int *key ); +/** A parsed named setting */ +struct named_setting { + /** Settings block */ + struct settings *settings; + /** Setting */ + struct setting setting; +}; + +extern int parse_string ( char *text, char **value ); +extern int parse_integer ( char *text, unsigned int *value ); +extern int parse_timeout ( char *text, unsigned long *value ); +extern int parse_netdev ( char *text, struct net_device **netdev ); +extern int +parse_netdev_configurator ( char *text, + struct net_device_configurator **configurator ); +extern int parse_menu ( char *text, struct menu **menu ); +extern int parse_flag ( char *text __unused, int *flag ); +extern int parse_key ( char *text, unsigned int *key ); +extern int parse_settings ( char *text, struct settings **settings ); +extern int parse_setting ( char *text, struct named_setting *setting, + get_child_settings_t get_child ); +extern int parse_existing_setting ( char *text, struct named_setting *setting ); +extern int parse_autovivified_setting ( char *text, + struct named_setting *setting ); +extern int parse_parameters ( char *text, struct parameters **params ); extern void print_usage ( struct command_descriptor *cmd, char **argv ); extern int reparse_options ( int argc, char **argv, struct command_descriptor *cmd, void *opts ); diff --git a/roms/ipxe/src/include/ipxe/pci.h b/roms/ipxe/src/include/ipxe/pci.h index a6ed484f1..692771ebe 100644 --- a/roms/ipxe/src/include/ipxe/pci.h +++ b/roms/ipxe/src/include/ipxe/pci.h @@ -351,6 +351,7 @@ struct pci_driver { #define PCI_FUNC( busdevfn ) ( ( (busdevfn) >> 0 ) & 0x07 ) #define PCI_BUSDEVFN( bus, slot, func ) \ ( ( (bus) << 8 ) | ( (slot) << 3 ) | ( (func) << 0 ) ) +#define PCI_FIRST_FUNC( busdevfn ) ( (busdevfn) & ~0x07 ) #define PCI_BASE_CLASS( class ) ( (class) >> 16 ) #define PCI_SUB_CLASS( class ) ( ( (class) >> 8 ) & 0xff ) @@ -385,6 +386,7 @@ extern void adjust_pci_device ( struct pci_device *pci ); extern unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg ); extern int pci_read_config ( struct pci_device *pci ); +extern int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ); extern int pci_find_driver ( struct pci_device *pci ); extern int pci_probe ( struct pci_device *pci ); extern void pci_remove ( struct pci_device *pci ); diff --git a/roms/ipxe/src/include/ipxe/pci_io.h b/roms/ipxe/src/include/ipxe/pci_io.h index 7368cf48b..781b77fe1 100644 --- a/roms/ipxe/src/include/ipxe/pci_io.h +++ b/roms/ipxe/src/include/ipxe/pci_io.h @@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Include all architecture-independent I/O API headers */ #include <ipxe/efi/efi_pci_api.h> +#include <ipxe/linux/linux_pci.h> /* Include all architecture-dependent I/O API headers */ #include <bits/pci_io.h> diff --git a/roms/ipxe/src/include/ipxe/pending.h b/roms/ipxe/src/include/ipxe/pending.h index 51afb4370..e6a369813 100644 --- a/roms/ipxe/src/include/ipxe/pending.h +++ b/roms/ipxe/src/include/ipxe/pending.h @@ -9,8 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#include <ipxe/list.h> - /** A pending operation */ struct pending_operation { /** Pending count */ @@ -21,14 +19,24 @@ struct pending_operation { * Check if an operation is pending * * @v pending Pending operation - * @v is_pending Operation is pending + * @ret is_pending Operation is pending */ static inline int is_pending ( struct pending_operation *pending ) { return ( pending->count != 0 ); } +extern int pending_total; + +/** + * Check if any operations are pending + * + * @ret have_pending Some operations are pending + */ +static inline int have_pending ( void ) { + return ( pending_total != 0 ); +} + extern void pending_get ( struct pending_operation *pending ); extern void pending_put ( struct pending_operation *pending ); -extern int pending_wait ( unsigned long timeout ); #endif /* _IPXE_PENDING_H */ diff --git a/roms/ipxe/src/include/ipxe/ping.h b/roms/ipxe/src/include/ipxe/ping.h new file mode 100644 index 000000000..6cd376b6f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/ping.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_PING_H +#define _IPXE_PING_H + +/** @file + * + * ICMP ping protocol + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/iobuf.h> +#include <ipxe/tcpip.h> + +extern int ping_rx ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_src ); + +#endif /* _IPXE_PING_H */ diff --git a/roms/ipxe/src/include/ipxe/pinger.h b/roms/ipxe/src/include/ipxe/pinger.h new file mode 100644 index 000000000..2d8403313 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/pinger.h @@ -0,0 +1,23 @@ +#ifndef _IPXE_PINGER_H +#define _IPXE_PINGER_H + +/** @file + * + * ICMP ping sender + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/interface.h> +#include <ipxe/socket.h> + +extern int create_pinger ( struct interface *job, const char *hostname, + unsigned long timeout, size_t len, + void ( * callback ) ( struct sockaddr *peer, + unsigned int sequence, + size_t len, + int rc ) ); + +#endif /* _IPXE_PINGER_H */ diff --git a/roms/ipxe/src/include/ipxe/pixbuf.h b/roms/ipxe/src/include/ipxe/pixbuf.h new file mode 100644 index 000000000..106b666e6 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/pixbuf.h @@ -0,0 +1,55 @@ +#ifndef _IPXE_PIXBUF_H +#define _IPXE_PIXBUF_H + +/** @file + * + * Pixel buffer + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stddef.h> +#include <ipxe/refcnt.h> +#include <ipxe/uaccess.h> + +/** A pixel buffer */ +struct pixel_buffer { + /** Reference count */ + struct refcnt refcnt; + /** Width */ + unsigned int width; + /** Height */ + unsigned int height; + /** 32-bit (8:8:8:8) xRGB pixel data, in host-endian order */ + userptr_t data; + /** Total length */ + size_t len; +}; + +/** + * Get reference to pixel buffer + * + * @v pixbuf Pixel buffer + * @ret pixbuf Pixel buffer + */ +static inline __attribute__ (( always_inline )) struct pixel_buffer * +pixbuf_get ( struct pixel_buffer *pixbuf ) { + ref_get ( &pixbuf->refcnt ); + return pixbuf; +} + +/** + * Drop reference to pixel buffer + * + * @v pixbuf Pixel buffer + */ +static inline __attribute__ (( always_inline )) void +pixbuf_put ( struct pixel_buffer *pixbuf ) { + ref_put ( &pixbuf->refcnt ); +} + +extern struct pixel_buffer * alloc_pixbuf ( unsigned int width, + unsigned int height ); + +#endif /* _IPXE_PIXBUF_H */ diff --git a/roms/ipxe/src/include/ipxe/png.h b/roms/ipxe/src/include/ipxe/png.h new file mode 100644 index 000000000..f51d1e6fe --- /dev/null +++ b/roms/ipxe/src/include/ipxe/png.h @@ -0,0 +1,179 @@ +#ifndef _IPXE_PNG_H +#define _IPXE_PNG_H + +/** @file + * + * Portable Network Graphics (PNG) format + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <byteswap.h> +#include <ipxe/image.h> + +/** A PNG file signature */ +struct png_signature { + /** Signature bytes */ + uint8_t bytes[8]; +} __attribute__ (( packed )); + +/** PNG file signature */ +#define PNG_SIGNATURE { { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n' } } + +/** A PNG chunk header */ +struct png_chunk_header { + /** Length of the chunk (excluding header and footer) */ + uint32_t len; + /** Chunk type */ + uint32_t type; +} __attribute__ (( packed )); + +/** A PNG chunk footer */ +struct png_chunk_footer { + /** CRC */ + uint32_t crc; +} __attribute__ (( packed )); + +/** PNG chunk type property bits */ +enum png_chunk_type_bits { + /** Chunk is ancillary */ + PNG_CHUNK_ANCILLARY = 0x20000000UL, + /** Chunk is private */ + PNG_CHUNK_PRIVATE = 0x00200000UL, + /** Reserved */ + PNG_CHUNK_RESERVED = 0x00002000UL, + /** Chunk is safe to copy */ + PNG_CHUNK_SAFE = 0x00000020UL, +}; + +/** + * Canonicalise PNG chunk type + * + * @v type Raw chunk type + * @ret type Canonicalised chunk type (excluding property bits) + */ +static inline __attribute__ (( always_inline )) uint32_t +png_canonical_type ( uint32_t type ) { + return ( type & ~( htonl ( PNG_CHUNK_ANCILLARY | PNG_CHUNK_PRIVATE | + PNG_CHUNK_RESERVED | PNG_CHUNK_SAFE ) ) ); +} + +/** + * Define a canonical PNG chunk type + * + * @v first First letter (in upper case) + * @v second Second letter (in upper case) + * @v third Third letter (in upper case) + * @v fourth Fourth letter (in upper case) + * @ret type Canonical chunk type + */ +#define PNG_TYPE( first, second, third, fourth ) \ + ( ( (first) << 24 ) | ( (second) << 16 ) | ( (third) << 8 ) | (fourth) ) + +/** PNG image header chunk type */ +#define PNG_TYPE_IHDR PNG_TYPE ( 'I', 'H', 'D', 'R' ) + +/** A PNG image header */ +struct png_image_header { + /** Width */ + uint32_t width; + /** Height */ + uint32_t height; + /** Bit depth */ + uint8_t depth; + /** Colour type */ + uint8_t colour_type; + /** Compression method */ + uint8_t compression; + /** Filter method */ + uint8_t filter; + /** Interlace method */ + uint8_t interlace; +} __attribute__ (( packed )); + +/** PNG colour type bits */ +enum png_colour_type { + /** Palette is used */ + PNG_COLOUR_TYPE_PALETTE = 0x01, + /** RGB colour is used */ + PNG_COLOUR_TYPE_RGB = 0x02, + /** Alpha channel is used */ + PNG_COLOUR_TYPE_ALPHA = 0x04, +}; + +/** PNG colour type mask */ +#define PNG_COLOUR_TYPE_MASK 0x07 + +/** PNG compression methods */ +enum png_compression_method { + /** DEFLATE compression with 32kB sliding window */ + PNG_COMPRESSION_DEFLATE = 0x00, + /** First unknown compression method */ + PNG_COMPRESSION_UNKNOWN = 0x01, +}; + +/** PNG filter methods */ +enum png_filter_method { + /** Adaptive filtering with five basic types */ + PNG_FILTER_BASIC = 0x00, + /** First unknown filter method */ + PNG_FILTER_UNKNOWN = 0x01, +}; + +/** PNG interlace methods */ +enum png_interlace_method { + /** No interlacing */ + PNG_INTERLACE_NONE = 0x00, + /** Adam7 interlacing */ + PNG_INTERLACE_ADAM7 = 0x01, + /** First unknown interlace method */ + PNG_INTERLACE_UNKNOWN = 0x02, +}; + +/** PNG palette chunk type */ +#define PNG_TYPE_PLTE PNG_TYPE ( 'P', 'L', 'T', 'E' ) + +/** A PNG palette entry */ +struct png_palette_entry { + /** Red */ + uint8_t red; + /** Green */ + uint8_t green; + /** Blue */ + uint8_t blue; +} __attribute__ (( packed )); + +/** A PNG palette chunk */ +struct png_palette { + /** Palette entries */ + struct png_palette_entry entries[0]; +} __attribute__ (( packed )); + +/** Maximum number of PNG palette entries */ +#define PNG_PALETTE_COUNT 256 + +/** PNG image data chunk type */ +#define PNG_TYPE_IDAT PNG_TYPE ( 'I', 'D', 'A', 'T' ) + +/** PNG basic filter types */ +enum png_basic_filter_type { + /** No filtering */ + PNG_FILTER_BASIC_NONE = 0, + /** Left byte used as predictor */ + PNG_FILTER_BASIC_SUB = 1, + /** Above byte used as predictor */ + PNG_FILTER_BASIC_UP = 2, + /** Above and left bytes used as predictors */ + PNG_FILTER_BASIC_AVERAGE = 3, + /** Paeth filter */ + PNG_FILTER_BASIC_PAETH = 4, +}; + +/** PNG image end chunk type */ +#define PNG_TYPE_IEND PNG_TYPE ( 'I', 'E', 'N', 'D' ) + +extern struct image_type png_image_type __image_type ( PROBE_NORMAL ); + +#endif /* _IPXE_PNG_H */ diff --git a/roms/ipxe/src/include/ipxe/pnm.h b/roms/ipxe/src/include/ipxe/pnm.h new file mode 100644 index 000000000..536c14d5f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/pnm.h @@ -0,0 +1,86 @@ +#ifndef _IPXE_PNM_H +#define _IPXE_PNM_H + +/** @file + * + * Portable anymap format (PNM) + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/uaccess.h> +#include <ipxe/image.h> + +/** PNM signature */ +struct pnm_signature { + /** Magic byte ('P') */ + char magic; + /** PNM type */ + char type; + /** Whitespace */ + char space; +} __attribute__ (( packed )); + +/** PNM magic byte */ +#define PNM_MAGIC 'P' + +/** PNM context */ +struct pnm_context { + /** PNM type */ + struct pnm_type *type; + /** Current byte offset */ + size_t offset; + /** Maximum length of ASCII values */ + size_t ascii_len; + /** Maximum pixel value */ + unsigned int max; +}; + +/** Default maximum length of ASCII values */ +#define PNM_ASCII_LEN 16 + +/** PNM type */ +struct pnm_type { + /** PNM type */ + char type; + /** Number of scalar values per pixel */ + uint8_t depth; + /** Number of pixels per composite value */ + uint8_t packing; + /** Flags */ + uint8_t flags; + /** Extract scalar value + * + * @v image PNM image + * @v pnm PNM context + * @ret value Value, or negative error + */ + int ( * scalar ) ( struct image *image, struct pnm_context *pnm ); + /** Convert composite value to 24-bit RGB + * + * @v composite Composite value + * @v index Pixel index within this composite value + * @ret rgb 24-bit RGB value + */ + uint32_t ( * rgb ) ( uint32_t composite, unsigned int index ); +}; + +/** PNM flags */ +enum pnm_flags { + /** Bitmap format + * + * If set, this flag indicates that: + * + * - the maximum scalar value is predefined as being equal to + * (2^packing-1), and is not present within the file, and + * + * - the maximum length of ASCII values is 1. + */ + PNM_BITMAP = 0x01, +}; + +extern struct image_type pnm_image_type __image_type ( PROBE_NORMAL ); + +#endif /* _IPXE_PNM_H */ diff --git a/roms/ipxe/src/include/ipxe/portmap.h b/roms/ipxe/src/include/ipxe/portmap.h new file mode 100644 index 000000000..9b735bbca --- /dev/null +++ b/roms/ipxe/src/include/ipxe/portmap.h @@ -0,0 +1,63 @@ +#ifndef _IPXE_PORTMAP_H +#define _IPXE_PORTMAP_H + +#include <stdint.h> +#include <ipxe/oncrpc.h> + +/** @file + * + * SUN ONC RPC protocol. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** PORTMAP default port */ +#define PORTMAP_PORT 111 + +/** PORTMAP protocol number */ +#define ONCRPC_PORTMAP 100000 + +/** PORTMAP version */ +#define PORTMAP_VERS 2 + + +/** TCP protocol number */ +#define PORTMAP_PROTO_TCP 6 +/** UDB protocol number */ +#define PORTMAP_PROTO_UDP 17 + + +/** + * A PORTMAP GETPORT reply + * + */ +struct portmap_getport_reply { + /** Port returned */ + uint32_t port; +}; + + +/** + * Prepare an ONC RPC session to be used as a PORTMAP session + * + * @v session ONC RPC session + * @v credential ONC RPC credential + * + * The credential parameter must not be NULL, use 'oncrpc_auth_none' if you + * don't want a particular scheme to be used. + */ +static inline void portmap_init_session ( struct oncrpc_session *session, + struct oncrpc_cred *credential) { + oncrpc_init_session ( session, credential, &oncrpc_auth_none, + ONCRPC_PORTMAP, PORTMAP_VERS ); +} + + +int portmap_getport ( struct interface *intf, struct oncrpc_session *session, + uint32_t prog, uint32_t vers, uint32_t proto ); +int portmap_get_getport_reply ( struct portmap_getport_reply *getport_reply, + struct oncrpc_reply *reply ); + + +#endif /* _IPXE_PORTMAP_H */ diff --git a/roms/ipxe/src/include/ipxe/privkey.h b/roms/ipxe/src/include/ipxe/privkey.h new file mode 100644 index 000000000..39049ac9f --- /dev/null +++ b/roms/ipxe/src/include/ipxe/privkey.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_PRIVKEY_H +#define _IPXE_PRIVKEY_H + +/** @file + * + * Private key + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/asn1.h> + +extern struct asn1_cursor private_key; + +#endif /* _IPXE_PRIVKEY_H */ diff --git a/roms/ipxe/src/include/ipxe/process.h b/roms/ipxe/src/include/ipxe/process.h index 9b7579817..2c76ff260 100644 --- a/roms/ipxe/src/include/ipxe/process.h +++ b/roms/ipxe/src/include/ipxe/process.h @@ -174,7 +174,7 @@ process_running ( struct process *process ) { * */ #define PERMANENT_PROCESS( name, step ) \ -struct process_descriptor name ## _desc = PROC_DESC_PURE ( step ); \ +static struct process_descriptor name ## _desc = PROC_DESC_PURE ( step ); \ struct process name __permanent_process = { \ .list = LIST_HEAD_INIT ( name.list ), \ .desc = & name ## _desc, \ diff --git a/roms/ipxe/src/include/ipxe/profile.h b/roms/ipxe/src/include/ipxe/profile.h index 60dd53a32..d4fc4f90f 100644 --- a/roms/ipxe/src/include/ipxe/profile.h +++ b/roms/ipxe/src/include/ipxe/profile.h @@ -9,72 +9,114 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#include <stdint.h> +#include <bits/profile.h> +#include <ipxe/tables.h> + +#ifdef NDEBUG +#define PROFILING 0 +#else +#define PROFILING 1 +#endif /** * A data structure for storing profiling information */ -union profiler { - /** Timestamp (in CPU-specific "ticks") */ - uint64_t timestamp; - /** Registers returned by rdtsc. +struct profiler { + /** Name */ + const char *name; + /** Start timestamp */ + unsigned long started; + /** Stop timestamp */ + unsigned long stopped; + /** Number of samples */ + unsigned int count; + /** Mean sample value (scaled) */ + unsigned long mean; + /** Mean sample value MSB + * + * This is the highest bit set in the raw (unscaled) value + * (i.e. one less than would be returned by flsl(raw_mean)). + */ + unsigned int mean_msb; + /** Accumulated variance (scaled) */ + unsigned long long accvar; + /** Accumulated variance MSB * - * This part should really be architecture-specific code. + * This is the highest bit set in the raw (unscaled) value + * (i.e. one less than would be returned by flsll(raw_accvar)). */ - struct { - uint32_t eax; - uint32_t edx; - } rdtsc; + unsigned int accvar_msb; }; +/** Profiler table */ +#define PROFILERS __table ( struct profiler, "profilers" ) + +/** Declare a profiler */ +#if PROFILING +#define __profiler __table_entry ( PROFILERS, 01 ) +#else +#define __profiler +#endif + +extern void profile_update ( struct profiler *profiler, unsigned long sample ); +extern unsigned long profile_mean ( struct profiler *profiler ); +extern unsigned long profile_variance ( struct profiler *profiler ); +extern unsigned long profile_stddev ( struct profiler *profiler ); + /** - * Static per-object profiler, for use with simple_profile() + * Start profiling + * + * @v profiler Profiler + * @v started Start timestamp */ -static union profiler simple_profiler; +static inline __attribute__ (( always_inline )) void +profile_start_at ( struct profiler *profiler, unsigned long started ) { + + /* If profiling is active then record start timestamp */ + if ( PROFILING ) + profiler->started = started; +} /** - * Perform profiling - * - * @v profiler Profiler data structure - * @ret delta Elapsed ticks since last call to profile(). - * - * Call profile() both before and after the code you wish to measure. - * The "after" call will return the measurement. For example: + * Start profiling * - * @code - * - * profile ( &profiler ); - * ... do something here ... - * printf ( "It took %ld ticks to execute\n", profile ( &profiler ) ); - * - * @endcode + * @v profiler Profiler */ -static inline __attribute__ (( always_inline )) unsigned long -profile ( union profiler *profiler ) { - uint64_t last_timestamp = profiler->timestamp; - - __asm__ __volatile__ ( "rdtsc" : - "=a" ( profiler->rdtsc.eax ), - "=d" ( profiler->rdtsc.edx ) ); - return ( profiler->timestamp - last_timestamp ); +static inline __attribute__ (( always_inline )) void +profile_start ( struct profiler *profiler ) { + + /* If profiling is active then record start timestamp */ + if ( PROFILING ) + profile_start_at ( profiler, profile_timestamp() ); } /** - * Perform profiling + * Record profiling result * - * @ret delta Elapsed ticks since last call to profile(). - * - * When you only need one profiler, you can avoid the hassle of - * creating your own @c profiler data structure by using - * simple_profile() instead. + * @v profiler Profiler + * @v stopped Stop timestamp + */ +static inline __attribute__ (( always_inline )) void +profile_stop_at ( struct profiler *profiler, unsigned long stopped ) { + + /* If profiling is active then record end timestamp and update stats */ + if ( PROFILING ) { + profiler->stopped = stopped; + profile_update ( profiler, ( stopped - profiler->started ) ); + } +} + +/** + * Record profiling result * - * simple_profile() is equivalent to profile(&simple_profiler), where - * @c simple_profiler is a @c profiler data structure that is static - * to each object which includes @c profile.h. + * @v profiler Profiler */ -static inline __attribute__ (( always_inline )) unsigned long -simple_profile ( void ) { - return profile ( &simple_profiler ); +static inline __attribute__ (( always_inline )) void +profile_stop ( struct profiler *profiler ) { + + /* If profiling is active then record end timestamp and update stats */ + if ( PROFILING ) + profile_stop_at ( profiler, profile_timestamp() ); } #endif /* _IPXE_PROFILE_H */ diff --git a/roms/ipxe/src/include/ipxe/reboot.h b/roms/ipxe/src/include/ipxe/reboot.h new file mode 100644 index 000000000..97e0d5fb6 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/reboot.h @@ -0,0 +1,68 @@ +#ifndef _IPXE_REBOOT_H +#define _IPXE_REBOOT_H + +/** @file + * + * iPXE reboot API + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <ipxe/api.h> +#include <config/reboot.h> + +/** + * Calculate static inline reboot API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define REBOOT_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( REBOOT_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide an reboot API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_REBOOT( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( REBOOT_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline reboot API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_REBOOT_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( REBOOT_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent reboot API headers */ +#include <ipxe/null_reboot.h> +#include <ipxe/efi/efi_reboot.h> + +/* Include all architecture-dependent reboot API headers */ +#include <bits/reboot.h> + +/** + * Reboot system + * + * @v warm Perform a warm reboot + */ +void reboot ( int warm ); + +/** + * Power off system + * + * @ret rc Return status code + * + * This function may fail, since not all systems support being powered + * off by software. + */ +int poweroff ( void ); + +#endif /* _IPXE_REBOOT_H */ diff --git a/roms/ipxe/src/include/ipxe/settings.h b/roms/ipxe/src/include/ipxe/settings.h index 3f8876020..d6929ecd0 100644 --- a/roms/ipxe/src/include/ipxe/settings.h +++ b/roms/ipxe/src/include/ipxe/settings.h @@ -16,6 +16,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct settings; struct in_addr; +struct in6_addr; union uuid; /** A setting */ @@ -32,40 +33,28 @@ struct setting { * This identifies the type of setting (e.g. string, IPv4 * address, etc.). */ - struct setting_type *type; + const struct setting_type *type; /** Setting tag, if applicable * * The setting tag is a numerical description of the setting * (such as a DHCP option number, or an SMBIOS structure and * field number). - * - * Users can construct tags for settings that are not - * explicitly known to iPXE using the generic syntax for - * numerical settings. For example, the setting name "60" - * will be interpreted as referring to DHCP option 60 (the - * vendor class identifier). - * - * This creates a potential for namespace collisions, since - * the interpretation of the numerical description will vary - * according to the settings block. When a user attempts to - * fetch a generic numerical setting, we need to ensure that - * only the intended settings block interprets the numerical - * description. (For example, we do not want to attempt to - * retrieve the subnet mask from SMBIOS, or the system UUID - * from DHCP.) - * - * This potential problem is resolved by allowing the setting - * tag to include a "magic" value indicating the - * interpretation to be placed upon the numerical description. */ unsigned int tag; + /** Setting scope (or NULL) + * + * For historic reasons, a NULL scope with a non-zero tag + * indicates a DHCPv4 option setting. + */ + const struct settings_scope *scope; }; /** Configuration setting table */ #define SETTINGS __table ( struct setting, "settings" ) /** Declare a configuration setting */ -#define __setting( setting_order ) __table_entry ( SETTINGS, setting_order ) +#define __setting( setting_order, name ) \ + __table_entry ( SETTINGS, setting_order.name ) /** @defgroup setting_order Setting ordering * @{ @@ -73,8 +62,8 @@ struct setting { #define SETTING_NETDEV 01 /**< Network device settings */ #define SETTING_NETDEV_EXTRA 02 /**< Network device additional settings */ -#define SETTING_IPv4 03 /**< IPv4 settings */ -#define SETTING_IPv4_EXTRA 04 /**< IPv4 additional settings */ +#define SETTING_IP 03 /**< IPv4 settings */ +#define SETTING_IP_EXTRA 04 /**< IPv4 additional settings */ #define SETTING_BOOT 05 /**< Generic boot settings */ #define SETTING_BOOT_EXTRA 06 /**< Generic boot additional settings */ #define SETTING_SANBOOT 07 /**< SAN boot settings */ @@ -90,6 +79,12 @@ struct setting { /** Settings block operations */ struct settings_operations { + /** Redirect to underlying settings block (if applicable) + * + * @v settings Settings block + * @ret settings Underlying settings block + */ + struct settings * ( * redirect ) ( struct settings *settings ); /** Check applicability of setting * * @v settings Settings block @@ -97,7 +92,7 @@ struct settings_operations { * @ret applies Setting applies within this settings block */ int ( * applies ) ( struct settings *settings, - struct setting *setting ); + const struct setting *setting ); /** Store value of setting * * @v settings Settings block @@ -106,7 +101,8 @@ struct settings_operations { * @v len Length of setting data * @ret rc Return status code */ - int ( * store ) ( struct settings *settings, struct setting *setting, + int ( * store ) ( struct settings *settings, + const struct setting *setting, const void *data, size_t len ); /** Fetch value of setting * @@ -134,12 +130,6 @@ struct settings { struct refcnt *refcnt; /** Name */ const char *name; - /** Tag magic - * - * This value will be ORed in to any numerical tags - * constructed by parse_setting_name(). - */ - unsigned int tag_magic; /** Parent settings block */ struct settings *parent; /** Sibling settings blocks */ @@ -148,9 +138,45 @@ struct settings { struct list_head children; /** Settings block operations */ struct settings_operations *op; + /** Default scope for numerical settings constructed for this block */ + const struct settings_scope *default_scope; }; /** + * A setting scope + * + * Users can construct tags for settings that are not explicitly known + * to iPXE using the generic syntax for numerical settings. For + * example, the setting name "60" will be interpreted as referring to + * DHCP option 60 (the vendor class identifier). + * + * This creates a potential for namespace collisions, since the + * interpretation of the numerical description will vary according to + * the settings block. When a user attempts to fetch a generic + * numerical setting, we need to ensure that only the intended + * settings blocks interpret this numerical description. (For + * example, we do not want to attempt to retrieve the subnet mask from + * SMBIOS, or the system UUID from DHCP.) + * + * This potential problem is resolved by including a user-invisible + * "scope" within the definition of each setting. Settings blocks may + * use this to determine whether or not the setting is applicable. + * Any settings constructed from a numerical description + * (e.g. "smbios/1.4.0") will be assigned the default scope of the + * settings block specified in the description (e.g. "smbios"); this + * provides behaviour matching the user's expectations in most + * circumstances. + */ +struct settings_scope { + /** Dummy field + * + * This is included only to ensure that pointers to different + * scopes always compare differently. + */ + uint8_t dummy; +} __attribute__ (( packed )); + +/** * A setting type * * This represents a type of setting (e.g. string, IPv4 address, @@ -162,24 +188,48 @@ struct setting_type { * This is the name exposed to the user (e.g. "string"). */ const char *name; - /** Parse formatted setting value + /** Parse formatted string to setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ - int ( * parse ) ( const char *value, void *buf, size_t len ); - /** Format setting value + int ( * parse ) ( const struct setting_type *type, const char *value, + void *buf, size_t len ); + /** Format setting value as a string * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ - int ( * format ) ( const void *raw, size_t raw_len, char *buf, - size_t len ); + int ( * format ) ( const struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ); + /** Convert number to setting value + * + * @v type Setting type + * @v value Numeric value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ + int ( * denumerate ) ( const struct setting_type *type, + unsigned long value, + void *buf, size_t len ); + /** Convert setting value to number + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v value Numeric value to fill in + * @ret rc Return status code + */ + int ( * numerate ) ( const struct setting_type *type, const void *raw, + size_t raw_len, unsigned long *value ); }; /** Configuration setting type table */ @@ -207,6 +257,31 @@ struct settings_applicator { /** Declare a settings applicator */ #define __settings_applicator __table_entry ( SETTINGS_APPLICATORS, 01 ) +/** A built-in setting */ +struct builtin_setting { + /** Setting */ + const struct setting *setting; + /** Fetch setting value + * + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ + int ( * fetch ) ( void *data, size_t len ); +}; + +/** Built-in settings table */ +#define BUILTIN_SETTINGS __table ( struct builtin_setting, "builtin_settings" ) + +/** Declare a built-in setting */ +#define __builtin_setting __table_entry ( BUILTIN_SETTINGS, 01 ) + +/** Built-in setting scope */ +extern const struct settings_scope builtin_scope; + +/** IPv6 setting scope */ +extern const struct settings_scope ipv6_scope; + /** * A generic settings block * @@ -218,9 +293,12 @@ struct generic_settings { struct list_head list; }; +/** A child settings block locator function */ +typedef struct settings * ( *get_child_settings_t ) ( struct settings *settings, + const char *name ); extern struct settings_operations generic_settings_operations; extern int generic_settings_store ( struct settings *settings, - struct setting *setting, + const struct setting *setting, const void *data, size_t len ); extern int generic_settings_fetch ( struct settings *settings, struct setting *setting, @@ -231,97 +309,148 @@ extern int register_settings ( struct settings *settings, struct settings *parent, const char *name ); extern void unregister_settings ( struct settings *settings ); +extern struct settings * settings_target ( struct settings *settings ); extern int setting_applies ( struct settings *settings, - struct setting *setting ); -extern int store_setting ( struct settings *settings, struct setting *setting, + const struct setting *setting ); +extern int store_setting ( struct settings *settings, + const struct setting *setting, const void *data, size_t len ); -extern int fetch_setting ( struct settings *settings, struct setting *setting, +extern int fetch_setting ( struct settings *settings, + const struct setting *setting, + struct settings **origin, struct setting *fetched, void *data, size_t len ); -extern struct settings * fetch_setting_origin ( struct settings *settings, - struct setting *setting ); -extern int fetch_setting_len ( struct settings *settings, - struct setting *setting ); extern int fetch_setting_copy ( struct settings *settings, - struct setting *setting, void **data ); + const struct setting *setting, + struct settings **origin, + struct setting *fetched, void **data ); +extern int fetch_raw_setting ( struct settings *settings, + const struct setting *setting, + void *data, size_t len ); +extern int fetch_raw_setting_copy ( struct settings *settings, + const struct setting *setting, + void **data ); extern int fetch_string_setting ( struct settings *settings, - struct setting *setting, + const struct setting *setting, char *data, size_t len ); extern int fetch_string_setting_copy ( struct settings *settings, - struct setting *setting, + const struct setting *setting, char **data ); extern int fetch_ipv4_array_setting ( struct settings *settings, - struct setting *setting, - struct in_addr *inp, - unsigned int count ); + const struct setting *setting, + struct in_addr *inp, unsigned int count ); extern int fetch_ipv4_setting ( struct settings *settings, - struct setting *setting, struct in_addr *inp ); + const struct setting *setting, + struct in_addr *inp ); +extern int fetch_ipv6_array_setting ( struct settings *settings, + const struct setting *setting, + struct in6_addr *inp, unsigned int count); +extern int fetch_ipv6_setting ( struct settings *settings, + const struct setting *setting, + struct in6_addr *inp ); extern int fetch_int_setting ( struct settings *settings, - struct setting *setting, long *value ); + const struct setting *setting, long *value ); extern int fetch_uint_setting ( struct settings *settings, - struct setting *setting, + const struct setting *setting, unsigned long *value ); extern long fetch_intz_setting ( struct settings *settings, - struct setting *setting ); + const struct setting *setting ); extern unsigned long fetch_uintz_setting ( struct settings *settings, - struct setting *setting ); + const struct setting *setting ); extern int fetch_uuid_setting ( struct settings *settings, - struct setting *setting, union uuid *uuid ); + const struct setting *setting, + union uuid *uuid ); extern void clear_settings ( struct settings *settings ); -extern int setting_cmp ( struct setting *a, struct setting *b ); +extern int setting_cmp ( const struct setting *a, const struct setting *b ); extern struct settings * find_child_settings ( struct settings *parent, const char *name ); +extern struct settings * autovivify_child_settings ( struct settings *parent, + const char *name ); extern const char * settings_name ( struct settings *settings ); extern struct settings * find_settings ( const char *name ); extern struct setting * find_setting ( const char *name ); - -extern int setting_name ( struct settings *settings, struct setting *setting, +extern int parse_setting_name ( char *name, get_child_settings_t get_child, + struct settings **settings, + struct setting *setting ); +extern int setting_name ( struct settings *settings, + const struct setting *setting, char *buf, size_t len ); -extern int fetchf_setting ( struct settings *settings, struct setting *setting, +extern int setting_format ( const struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ); +extern int setting_parse ( const struct setting_type *type, const char *value, + void *buf, size_t len ); +extern int setting_numerate ( const struct setting_type *type, const void *raw, + size_t raw_len, unsigned long *value ); +extern int setting_denumerate ( const struct setting_type *type, + unsigned long value, void *buf, size_t len ); +extern int fetchf_setting ( struct settings *settings, + const struct setting *setting, + struct settings **origin, struct setting *fetched, char *buf, size_t len ); +extern int fetchf_setting_copy ( struct settings *settings, + const struct setting *setting, + struct settings **origin, + struct setting *fetched, char **value ); extern int storef_setting ( struct settings *settings, - struct setting *setting, - const char *value ); -extern int store_named_setting ( const char *name, - struct setting_type *default_type, - const void *data, size_t len ); -extern int storef_named_setting ( const char *name, - struct setting_type *default_type, - const char *value ); -extern int fetchf_named_setting ( const char *name, char *name_buf, - size_t name_len, char *value_buf, - size_t value_len ); -extern int fetchf_named_setting_copy ( const char *name, char **data ); + const struct setting *setting, const char *value ); +extern int fetchn_setting ( struct settings *settings, + const struct setting *setting, + struct settings **origin, struct setting *fetched, + unsigned long *value ); +extern int storen_setting ( struct settings *settings, + const struct setting *setting, + unsigned long value ); extern char * expand_settings ( const char *string ); -extern struct setting_type setting_type_string __setting_type; -extern struct setting_type setting_type_uristring __setting_type; -extern struct setting_type setting_type_ipv4 __setting_type; -extern struct setting_type setting_type_int8 __setting_type; -extern struct setting_type setting_type_int16 __setting_type; -extern struct setting_type setting_type_int32 __setting_type; -extern struct setting_type setting_type_uint8 __setting_type; -extern struct setting_type setting_type_uint16 __setting_type; -extern struct setting_type setting_type_uint32 __setting_type; -extern struct setting_type setting_type_hex __setting_type; -extern struct setting_type setting_type_hexhyp __setting_type; -extern struct setting_type setting_type_uuid __setting_type; - -extern struct setting ip_setting __setting ( SETTING_IPv4 ); -extern struct setting netmask_setting __setting ( SETTING_IPv4 ); -extern struct setting gateway_setting __setting ( SETTING_IPv4 ); -extern struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ); -extern struct setting hostname_setting __setting ( SETTING_HOST ); -extern struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ); -extern struct setting filename_setting __setting ( SETTING_BOOT ); -extern struct setting root_path_setting __setting ( SETTING_SANBOOT ); -extern struct setting username_setting __setting ( SETTING_AUTH ); -extern struct setting password_setting __setting ( SETTING_AUTH ); -extern struct setting priority_setting __setting ( SETTING_MISC ); -extern struct setting uuid_setting __setting ( SETTING_HOST ); -extern struct setting next_server_setting __setting ( SETTING_BOOT ); -extern struct setting mac_setting __setting ( SETTING_NETDEV ); -extern struct setting busid_setting __setting ( SETTING_NETDEV ); +extern const struct setting_type setting_type_string __setting_type; +extern const struct setting_type setting_type_uristring __setting_type; +extern const struct setting_type setting_type_ipv4 __setting_type; +extern const struct setting_type setting_type_ipv6 __setting_type; +extern const struct setting_type setting_type_int8 __setting_type; +extern const struct setting_type setting_type_int16 __setting_type; +extern const struct setting_type setting_type_int32 __setting_type; +extern const struct setting_type setting_type_uint8 __setting_type; +extern const struct setting_type setting_type_uint16 __setting_type; +extern const struct setting_type setting_type_uint32 __setting_type; +extern const struct setting_type setting_type_hex __setting_type; +extern const struct setting_type setting_type_hexhyp __setting_type; +extern const struct setting_type setting_type_hexraw __setting_type; +extern const struct setting_type setting_type_uuid __setting_type; +extern const struct setting_type setting_type_busdevfn __setting_type; +extern const struct setting_type setting_type_dnssl __setting_type; + +extern const struct setting +ip_setting __setting ( SETTING_IP, ip ); +extern const struct setting +netmask_setting __setting ( SETTING_IP, netmask ); +extern const struct setting +gateway_setting __setting ( SETTING_IP, gateway ); +extern const struct setting +dns_setting __setting ( SETTING_IP_EXTRA, dns ); +extern const struct setting +hostname_setting __setting ( SETTING_HOST, hostname ); +extern const struct setting +domain_setting __setting ( SETTING_IP_EXTRA, domain ); +extern const struct setting +filename_setting __setting ( SETTING_BOOT, filename ); +extern const struct setting +root_path_setting __setting ( SETTING_SANBOOT, root-path ); +extern const struct setting +username_setting __setting ( SETTING_AUTH, username ); +extern const struct setting +password_setting __setting ( SETTING_AUTH, password ); +extern const struct setting +priority_setting __setting ( SETTING_MISC, priority ); +extern const struct setting +uuid_setting __setting ( SETTING_HOST, uuid ); +extern const struct setting +next_server_setting __setting ( SETTING_BOOT, next-server ); +extern const struct setting +mac_setting __setting ( SETTING_NETDEV, mac ); +extern const struct setting +busid_setting __setting ( SETTING_NETDEV, busid ); +extern const struct setting +user_class_setting __setting ( SETTING_HOST_EXTRA, user-class ); /** * Initialise a settings block @@ -329,17 +458,17 @@ extern struct setting busid_setting __setting ( SETTING_NETDEV ); * @v settings Settings block * @v op Settings block operations * @v refcnt Containing object reference counter, or NULL - * @v tag_magic Tag magic + * @v default_scope Default scope */ static inline void settings_init ( struct settings *settings, struct settings_operations *op, struct refcnt *refcnt, - unsigned int tag_magic ) { + const struct settings_scope *default_scope ){ INIT_LIST_HEAD ( &settings->siblings ); INIT_LIST_HEAD ( &settings->children ); settings->op = op; settings->refcnt = refcnt; - settings->tag_magic = tag_magic; + settings->default_scope = default_scope; } /** @@ -351,7 +480,7 @@ static inline void settings_init ( struct settings *settings, static inline void generic_settings_init ( struct generic_settings *generics, struct refcnt *refcnt ) { settings_init ( &generics->settings, &generic_settings_operations, - refcnt, 0 ); + refcnt, NULL ); INIT_LIST_HEAD ( &generics->list ); } @@ -363,30 +492,21 @@ static inline void generic_settings_init ( struct generic_settings *generics, * @ret rc Return status code */ static inline int delete_setting ( struct settings *settings, - struct setting *setting ) { + const struct setting *setting ) { return store_setting ( settings, setting, NULL, 0 ); } /** - * Delete named setting - * - * @v name Name of setting - * @ret rc Return status code - */ -static inline int delete_named_setting ( const char *name ) { - return store_named_setting ( name, NULL, NULL, 0 ); -} - -/** - * Check existence of setting + * Check existence of predefined setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch * @ret exists Setting exists */ static inline int setting_exists ( struct settings *settings, - struct setting *setting ) { - return ( fetch_setting_len ( settings, setting ) >= 0 ); + const struct setting *setting ) { + return ( fetch_setting ( settings, setting, NULL, NULL, + NULL, 0 ) >= 0 ); } #endif /* _IPXE_SETTINGS_H */ diff --git a/roms/ipxe/src/include/ipxe/smbios.h b/roms/ipxe/src/include/ipxe/smbios.h index fcf149ea7..1a34ac04c 100644 --- a/roms/ipxe/src/include/ipxe/smbios.h +++ b/roms/ipxe/src/include/ipxe/smbios.h @@ -148,15 +148,29 @@ struct smbios { size_t len; /** Number of SMBIOS structures */ unsigned int count; + /** SMBIOS version */ + uint16_t version; }; +/** + * Calculate SMBIOS version + * + * @v major Major version + * @v minor Minor version + * @ret version SMBIOS version + */ +#define SMBIOS_VERSION( major, minor ) ( ( (major) << 8 ) | (minor) ) + extern int find_smbios ( struct smbios *smbios ); -extern int find_smbios_structure ( unsigned int type, +extern int find_smbios_entry ( userptr_t start, size_t len, + struct smbios_entry *entry ); +extern int find_smbios_structure ( unsigned int type, unsigned int instance, struct smbios_structure *structure ); extern int read_smbios_structure ( struct smbios_structure *structure, void *data, size_t len ); extern int read_smbios_string ( struct smbios_structure *structure, unsigned int index, void *data, size_t len ); +extern int smbios_version ( void ); #endif /* _IPXE_SMBIOS_H */ diff --git a/roms/ipxe/src/include/ipxe/socket.h b/roms/ipxe/src/include/ipxe/socket.h index 320dae4f1..7cb3912f4 100644 --- a/roms/ipxe/src/include/ipxe/socket.h +++ b/roms/ipxe/src/include/ipxe/socket.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> +#include <ipxe/tables.h> /** * @defgroup commtypes Communication semantics @@ -27,6 +28,11 @@ extern int udp_sock_dgram; #define UDP_SOCK_DGRAM 0x2 #define SOCK_DGRAM udp_sock_dgram +/** Echo testing streams */ +extern int ping_sock_echo; +#define PING_SOCK_ECHO 0x3 +#define SOCK_ECHO ping_sock_echo + /** @} */ /** @@ -42,6 +48,8 @@ socket_semantics_name ( int semantics ) { return "SOCK_STREAM"; } else if ( semantics == SOCK_DGRAM ) { return "SOCK_DGRAM"; + } else if ( semantics == SOCK_ECHO ) { + return "SOCK_ECHO"; } else { return "SOCK_UNKNOWN"; } @@ -68,6 +76,7 @@ socket_family_name ( int family ) { switch ( family ) { case AF_INET: return "AF_INET"; case AF_INET6: return "AF_INET6"; + case AF_FC: return "AF_FC"; default: return "AF_UNKNOWN"; } } @@ -97,6 +106,41 @@ struct sockaddr { * family. */ char pad[ SA_LEN - sizeof ( sa_family_t ) ]; -} __attribute__ (( may_alias )); +} __attribute__ (( packed, may_alias )); + +/** + * Socket address converter + * + */ +struct sockaddr_converter { + /** Socket address family + * + * This is an AF_XXX constant. + */ + sa_family_t family; + /** Transcribe socket address + * + * @v sa Socket address + * @ret string Socket address string + */ + const char * ( * ntoa ) ( struct sockaddr *sa ); + /** Parse socket address + * + * @v string Socket address stringh + * @v sa Socket address to fill in + * @ret rc Return status code + */ + int ( * aton ) ( const char *string, struct sockaddr *sa ); +}; + +/** Socket address converter table */ +#define SOCKADDR_CONVERTERS \ + __table ( struct sockaddr_converter, "sockaddr_converters" ) + +/** Declare a socket address converter */ +#define __sockaddr_converter __table_entry ( SOCKADDR_CONVERTERS, 01 ) + +extern const char * sock_ntoa ( struct sockaddr *sa ); +extern int sock_aton ( const char *string, struct sockaddr *sa ); #endif /* _IPXE_SOCKET_H */ diff --git a/roms/ipxe/src/include/ipxe/tcp.h b/roms/ipxe/src/include/ipxe/tcp.h index 6b6691175..9baa6391c 100644 --- a/roms/ipxe/src/include/ipxe/tcp.h +++ b/roms/ipxe/src/include/ipxe/tcp.h @@ -316,20 +316,19 @@ struct tcp_options { /** * Path MTU * - * We really ought to implement Path MTU discovery. Until we do, - * anything with a path MTU greater than this may fail. + * IPv6 requires all data link layers to support a datagram size of + * 1280 bytes. We choose to use this as our maximum transmitted + * datagram size, on the assumption that any practical link layer we + * encounter will allow this size. This is a very conservative + * assumption in practice, but the impact of making such a + * conservative assumption is insignificant since the amount of data + * that we transmit (rather than receive) is negligible. + * + * We allow space within this 1280 bytes for an IPv6 header, a TCP + * header, and a (padded) TCP timestamp option. */ -#define TCP_PATH_MTU 1460 - -/** - * Advertised TCP MSS - * - * We currently hardcode this to a reasonable value and hope that the - * sender uses path MTU discovery. The alternative is breaking the - * abstraction layer so that we can find out the MTU from the IP layer - * (which would have to find out from the net device layer). - */ -#define TCP_MSS 1460 +#define TCP_PATH_MTU \ + ( 1280 - 40 /* IPv6 */ - 20 /* TCP */ - 12 /* TCP timestamp */ ) /** TCP maximum segment lifetime * diff --git a/roms/ipxe/src/include/ipxe/tcpip.h b/roms/ipxe/src/include/ipxe/tcpip.h index 34d7f88f4..200630d6b 100644 --- a/roms/ipxe/src/include/ipxe/tcpip.h +++ b/roms/ipxe/src/include/ipxe/tcpip.h @@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct io_buffer; struct net_device; +struct ip_statistics; /** Empty checksum value * @@ -24,6 +25,16 @@ struct net_device; */ #define TCPIP_EMPTY_CSUM 0xffff +/** TCP/IP address flags */ +enum tcpip_st_flags { + /** Bind to a privileged port (less than 1024) + * + * This value is chosen as 1024 to optimise the calculations + * in tcpip_bind(). + */ + TCPIP_BIND_PRIVILEGED = 0x0400, +}; + /** * TCP/IP socket address * @@ -33,6 +44,8 @@ struct net_device; struct sockaddr_tcpip { /** Socket address family (part of struct @c sockaddr) */ sa_family_t st_family; + /** Flags */ + uint16_t st_flags; /** TCP/IP port */ uint16_t st_port; /** Padding @@ -42,8 +55,10 @@ struct sockaddr_tcpip { * family. */ char pad[ sizeof ( struct sockaddr ) - - ( sizeof ( sa_family_t ) + sizeof ( uint16_t ) ) ]; -} __attribute__ (( may_alias )); + ( sizeof ( sa_family_t ) /* st_family */ + + sizeof ( uint16_t ) /* st_flags */ + + sizeof ( uint16_t ) /* st_port */ ) ]; +} __attribute__ (( packed, may_alias )); /** * A transport-layer protocol of the TCP/IP stack (eg. UDP, TCP, etc) @@ -55,6 +70,7 @@ struct tcpip_protocol { * Process received packet * * @v iobuf I/O buffer + * @v netdev Network device * @v st_src Partially-filled source address * @v st_dest Partially-filled destination address * @v pshdr_csum Pseudo-header checksum @@ -62,7 +78,8 @@ struct tcpip_protocol { * * This method takes ownership of the I/O buffer. */ - int ( * rx ) ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, + int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev, + struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ); /** * Transport-layer protocol number @@ -80,6 +97,8 @@ struct tcpip_net_protocol { const char *name; /** Network address family */ sa_family_t sa_family; + /** Fixed header length */ + size_t header_len; /** * Transmit packet * @@ -99,6 +118,13 @@ struct tcpip_net_protocol { struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ); + /** + * Determine transmitting network device + * + * @v st_dest Destination address + * @ret netdev Network device, or NULL + */ + struct net_device * ( * netdev ) ( struct sockaddr_tcpip *dest ); }; /** TCP/IP transport-layer protocol table */ @@ -114,17 +140,22 @@ struct tcpip_net_protocol { /** Declare a TCP/IP network-layer protocol */ #define __tcpip_net_protocol __table_entry ( TCPIP_NET_PROTOCOLS, 01 ) -extern int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto, - struct sockaddr_tcpip *st_src, - struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ); +extern int tcpip_rx ( struct io_buffer *iobuf, struct net_device *netdev, + uint8_t tcpip_proto, struct sockaddr_tcpip *st_src, + struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum, + struct ip_statistics *stats ); extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ); +extern struct net_device * tcpip_netdev ( struct sockaddr_tcpip *st_dest ); +extern size_t tcpip_mtu ( struct sockaddr_tcpip *st_dest ); extern uint16_t generic_tcpip_continue_chksum ( uint16_t partial, const void *data, size_t len ); extern uint16_t tcpip_chksum ( const void *data, size_t len ); +extern int tcpip_bind ( struct sockaddr_tcpip *st_local, + int ( * available ) ( int port ) ); /* Use generic_tcpip_continue_chksum() if no architecture-specific * version is available diff --git a/roms/ipxe/src/include/ipxe/test.h b/roms/ipxe/src/include/ipxe/test.h index 8c361d284..028ee29fb 100644 --- a/roms/ipxe/src/include/ipxe/test.h +++ b/roms/ipxe/src/include/ipxe/test.h @@ -31,15 +31,19 @@ struct self_test { /** Declare a self-test */ #define __self_test __table_entry ( SELF_TESTS, 01 ) -extern void test_ok ( int success, const char *file, unsigned int line ); +extern void test_ok ( int success, const char *file, unsigned int line, + const char *test ); /** * Report test result * * @v success Test succeeded + * @v file File name + * @v line Line number */ -#define ok( success ) do { \ - test_ok ( (success), __FILE__, __LINE__ ); \ - } while ( 0 ) +#define okx( success, file, line ) \ + test_ok ( success, file, line, #success ) +#define ok( success ) \ + okx ( success, __FILE__, __LINE__ ) #endif /* _IPXE_TEST_H */ diff --git a/roms/ipxe/src/include/ipxe/tftp.h b/roms/ipxe/src/include/ipxe/tftp.h index 38be0d4da..aecafa2ae 100644 --- a/roms/ipxe/src/include/ipxe/tftp.h +++ b/roms/ipxe/src/include/ipxe/tftp.h @@ -80,6 +80,4 @@ union tftp_any { struct tftp_oack oack; }; -extern void tftp_set_request_blksize ( unsigned int blksize ); - #endif /* _IPXE_TFTP_H */ diff --git a/roms/ipxe/src/include/ipxe/tls.h b/roms/ipxe/src/include/ipxe/tls.h index f8a754096..586da26ec 100644 --- a/roms/ipxe/src/include/ipxe/tls.h +++ b/roms/ipxe/src/include/ipxe/tls.h @@ -241,8 +241,8 @@ struct tls_session { struct digest_algorithm *handshake_digest; /** Digest algorithm context used for handshake verification */ uint8_t *handshake_ctx; - /** Public-key algorithm used for Certificate Verify (if sent) */ - struct pubkey_algorithm *verify_pubkey; + /** Client certificate (if used) */ + struct x509_certificate *cert; /** Server certificate chain */ struct x509_chain *chain; diff --git a/roms/ipxe/src/include/ipxe/uaccess.h b/roms/ipxe/src/include/ipxe/uaccess.h index 95e943675..055bb2ca7 100644 --- a/roms/ipxe/src/include/ipxe/uaccess.h +++ b/roms/ipxe/src/include/ipxe/uaccess.h @@ -127,6 +127,23 @@ trivial_memmove_user ( userptr_t dest, off_t dest_off, } /** + * Compare data between user buffers + * + * @v first First buffer + * @v first_off First buffer offset + * @v second Second buffer + * @v second_off Second buffer offset + * @v len Length + * @ret diff Difference + */ +static inline __always_inline int +trivial_memcmp_user ( userptr_t first, off_t first_off, + userptr_t second, off_t second_off, size_t len ) { + return memcmp ( ( ( void * ) first + first_off ), + ( ( void * ) second + second_off ), len ); +} + +/** * Fill user buffer with a constant byte * * @v buffer User buffer @@ -334,6 +351,19 @@ void memmove_user ( userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len ); /** + * Compare data between user buffers + * + * @v first First buffer + * @v first_off First buffer offset + * @v second Second buffer + * @v second_off Second buffer offset + * @v len Length + * @ret diff Difference + */ +int memcmp_user ( userptr_t first, off_t first_off, + userptr_t second, off_t second_off, size_t len ); + +/** * Fill user buffer with a constant byte * * @v userptr User buffer diff --git a/roms/ipxe/src/include/ipxe/uri.h b/roms/ipxe/src/include/ipxe/uri.h index b7b8b4417..7613d578d 100644 --- a/roms/ipxe/src/include/ipxe/uri.h +++ b/roms/ipxe/src/include/ipxe/uri.h @@ -12,6 +12,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> #include <stdlib.h> #include <ipxe/refcnt.h> +#include <ipxe/in.h> + +struct parameters; /** A Uniform Resource Identifier * @@ -65,39 +68,42 @@ struct uri { const char *query; /** Fragment */ const char *fragment; + /** Form parameters */ + struct parameters *params; } __attribute__ (( packed )); -/** A field in a URI +/** + * Access URI field * - * The order of the indices in this enumeration must match the order - * of the fields in the URI structure. + * @v uri URI + * @v field URI field index + * @ret field URI field (as an lvalue) */ -enum { - URI_SCHEME = 0, URI_SCHEME_BIT = ( 1 << URI_SCHEME ), - URI_OPAQUE = 1, URI_OPAQUE_BIT = ( 1 << URI_OPAQUE ), - URI_USER = 2, URI_USER_BIT = ( 1 << URI_USER ), - URI_PASSWORD = 3, URI_PASSWORD_BIT = ( 1 << URI_PASSWORD ), - URI_HOST = 4, URI_HOST_BIT = ( 1 << URI_HOST ), - URI_PORT = 5, URI_PORT_BIT = ( 1 << URI_PORT ), - URI_PATH = 6, URI_PATH_BIT = ( 1 << URI_PATH ), - URI_QUERY = 7, URI_QUERY_BIT = ( 1 << URI_QUERY ), - URI_FRAGMENT = 8, URI_FRAGMENT_BIT = ( 1 << URI_FRAGMENT ), - - URI_FIRST_FIELD = URI_SCHEME, - URI_LAST_FIELD = URI_FRAGMENT, -}; - -/** Extract field from URI */ -#define uri_get_field( uri, field ) (&uri->scheme)[field] +#define uri_field( uri, field ) (&uri->scheme)[field] -/** All URI fields */ -#define URI_ALL ( URI_SCHEME_BIT | URI_OPAQUE_BIT | URI_USER_BIT | \ - URI_PASSWORD_BIT | URI_HOST_BIT | URI_PORT_BIT | \ - URI_PATH_BIT | URI_QUERY_BIT | URI_FRAGMENT_BIT ) - -/** URI fields that should be decoded on storage */ -#define URI_ENCODED ( URI_USER_BIT | URI_PASSWORD_BIT | URI_HOST_BIT | \ - URI_PATH_BIT | URI_QUERY_BIT | URI_FRAGMENT_BIT ) +/** + * Calculate index of a URI field + * + * @v name URI field name + * @ret field URI field index + */ +#define URI_FIELD( name ) \ + ( ( offsetof ( struct uri, name ) - \ + offsetof ( struct uri, scheme ) ) / sizeof ( void * ) ) + +/** URI fields */ +enum uri_fields { + URI_SCHEME = URI_FIELD ( scheme ), + URI_OPAQUE = URI_FIELD ( opaque ), + URI_USER = URI_FIELD ( user ), + URI_PASSWORD = URI_FIELD ( password ), + URI_HOST = URI_FIELD ( host ), + URI_PORT = URI_FIELD ( port ), + URI_PATH = URI_FIELD ( path ), + URI_QUERY = URI_FIELD ( query ), + URI_FRAGMENT = URI_FIELD ( fragment ), + URI_FIELDS +}; /** * URI is an absolute URI @@ -109,17 +115,27 @@ enum { * Note that this is a separate concept from a URI with an absolute * path. */ -static inline int uri_is_absolute ( struct uri *uri ) { +static inline int uri_is_absolute ( const struct uri *uri ) { return ( uri->scheme != NULL ); } /** + * URI has an opaque part + * + * @v uri URI + * @ret has_opaque URI has an opaque part + */ +static inline int uri_has_opaque ( const struct uri *uri ) { + return ( uri->opaque && ( uri->opaque[0] != '\0' ) ); +} + +/** * URI has a path * * @v uri URI * @ret has_path URI has a path */ -static inline int uri_has_path ( struct uri *uri ) { +static inline int uri_has_path ( const struct uri *uri ) { return ( uri->path && ( uri->path[0] != '\0' ) ); } @@ -133,7 +149,7 @@ static inline int uri_has_path ( struct uri *uri ) { * concept from an absolute URI. Note also that a URI may not have a * path at all. */ -static inline int uri_has_absolute_path ( struct uri *uri ) { +static inline int uri_has_absolute_path ( const struct uri *uri ) { return ( uri->path && ( uri->path[0] == '/' ) ); } @@ -147,7 +163,7 @@ static inline int uri_has_absolute_path ( struct uri *uri ) { * this is a separate concept from a relative URI. Note also that a * URI may not have a path at all. */ -static inline int uri_has_relative_path ( struct uri *uri ) { +static inline int uri_has_relative_path ( const struct uri *uri ) { return ( uri->path && ( uri->path[0] != '/' ) ); } @@ -175,18 +191,20 @@ uri_put ( struct uri *uri ) { extern struct uri *cwuri; +extern size_t uri_encode ( const char *string, unsigned int field, + char *buf, ssize_t len ); extern struct uri * parse_uri ( const char *uri_string ); -extern unsigned int uri_port ( struct uri *uri, unsigned int default_port ); -extern int unparse_uri ( char *buf, size_t size, struct uri *uri, - unsigned int fields ); -extern struct uri * uri_dup ( struct uri *uri ); +extern size_t format_uri ( const struct uri *uri, char *buf, size_t len ); +extern char * format_uri_alloc ( const struct uri *uri ); +extern unsigned int uri_port ( const struct uri *uri, + unsigned int default_port ); +extern struct uri * uri_dup ( const struct uri *uri ); extern char * resolve_path ( const char *base_path, const char *relative_path ); -extern struct uri * resolve_uri ( struct uri *base_uri, +extern struct uri * resolve_uri ( const struct uri *base_uri, struct uri *relative_uri ); +extern struct uri * tftp_uri ( struct in_addr next_server, + const char *filename ); extern void churi ( struct uri *uri ); -extern size_t uri_encode ( const char *raw_string, char *buf, ssize_t len, - int field ); -extern size_t uri_decode ( const char *encoded_string, char *buf, ssize_t len ); #endif /* _IPXE_URI_H */ diff --git a/roms/ipxe/src/include/ipxe/uuid.h b/roms/ipxe/src/include/ipxe/uuid.h index 5de56b94e..ad515d0cb 100644 --- a/roms/ipxe/src/include/ipxe/uuid.h +++ b/roms/ipxe/src/include/ipxe/uuid.h @@ -9,6 +9,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> +#include <byteswap.h> /** A universally unique ID */ union uuid { @@ -28,6 +29,24 @@ union uuid { uint8_t raw[16]; }; +/** + * Change UUID endianness + * + * @v uuid UUID + * + * RFC4122 defines UUIDs as being encoded in network byte order, but + * leaves some wriggle room for "explicit application or presentation + * protocol specification to the contrary". PXE, EFI and SMBIOS + * (versions 2.6 and above) treat the first three fields as being + * little-endian. + */ +static inline void uuid_mangle ( union uuid *uuid ) { + + __bswap_32s ( &uuid->canonical.a ); + __bswap_16s ( &uuid->canonical.b ); + __bswap_16s ( &uuid->canonical.c ); +} + extern char * uuid_ntoa ( const union uuid *uuid ); #endif /* _IPXE_UUID_H */ diff --git a/roms/ipxe/src/include/ipxe/vlan.h b/roms/ipxe/src/include/ipxe/vlan.h index d9f4484e6..083c21916 100644 --- a/roms/ipxe/src/include/ipxe/vlan.h +++ b/roms/ipxe/src/include/ipxe/vlan.h @@ -61,6 +61,7 @@ struct vlan_header { extern struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ); +extern unsigned int vlan_tag ( struct net_device *netdev ); extern int vlan_can_be_trunk ( struct net_device *trunk ); extern int vlan_create ( struct net_device *trunk, unsigned int tag, unsigned int priority ); diff --git a/roms/ipxe/src/include/ipxe/x509.h b/roms/ipxe/src/include/ipxe/x509.h index a47942a75..055a4460e 100644 --- a/roms/ipxe/src/include/ipxe/x509.h +++ b/roms/ipxe/src/include/ipxe/x509.h @@ -42,14 +42,6 @@ struct x509_validity { struct x509_time not_after; }; -/** Margin of error allowed in X.509 response times - * - * We allow a generous margin of error: 12 hours to allow for the - * local time zone being non-GMT, plus 30 minutes to allow for general - * clock drift. - */ -#define X509_ERROR_MARGIN_TIME ( ( 12 * 60 + 30 ) * 60 ) - /** An X.509 certificate public key */ struct x509_public_key { /** Raw public key information */ @@ -65,7 +57,7 @@ struct x509_subject { /** Raw subject */ struct asn1_cursor raw; /** Common name */ - char *name; + struct asn1_cursor common_name; /** Public key information */ struct x509_public_key public_key; }; @@ -133,7 +125,7 @@ enum x509_extended_key_usage_bits { /** X.509 certificate OCSP responder */ struct x509_ocsp_responder { /** URI */ - char *uri; + struct asn1_cursor uri; /** OCSP status is good */ int good; }; @@ -144,6 +136,18 @@ struct x509_authority_info_access { struct x509_ocsp_responder ocsp; }; +/** X.509 certificate subject alternative name */ +struct x509_subject_alt_name { + /** Names */ + struct asn1_cursor names; +}; + +/** X.509 certificate general name types */ +enum x509_general_name_types { + X509_GENERAL_NAME_DNS = ASN1_IMPLICIT_TAG ( 2 ), + X509_GENERAL_NAME_URI = ASN1_IMPLICIT_TAG ( 6 ), +}; + /** An X.509 certificate extensions set */ struct x509_extensions { /** Basic constraints */ @@ -154,14 +158,33 @@ struct x509_extensions { struct x509_extended_key_usage ext_usage; /** Authority information access */ struct x509_authority_info_access auth_info; + /** Subject alternative name */ + struct x509_subject_alt_name alt_name; +}; + +/** A link in an X.509 certificate chain */ +struct x509_link { + /** List of links */ + struct list_head list; + /** Certificate */ + struct x509_certificate *cert; +}; + +/** An X.509 certificate chain */ +struct x509_chain { + /** Reference count */ + struct refcnt refcnt; + /** List of links */ + struct list_head links; }; /** An X.509 certificate */ struct x509_certificate { /** Reference count */ struct refcnt refcnt; - /** List of certificates in cache */ - struct list_head list; + + /** Link in certificate store */ + struct x509_link store; /** Certificate has been validated */ int valid; @@ -212,22 +235,6 @@ x509_put ( struct x509_certificate *cert ) { ref_put ( &cert->refcnt ); } -/** A link in an X.509 certificate chain */ -struct x509_link { - /** List of links */ - struct list_head list; - /** Certificate */ - struct x509_certificate *cert; -}; - -/** An X.509 certificate chain */ -struct x509_chain { - /** Reference count */ - struct refcnt refcnt; - /** List of links */ - struct list_head links; -}; - /** * Get reference to X.509 certificate chain * @@ -330,11 +337,15 @@ struct x509_root { const void *fingerprints; }; +extern const char * x509_name ( struct x509_certificate *cert ); +extern int x509_parse ( struct x509_certificate *cert, + const struct asn1_cursor *raw ); extern int x509_certificate ( const void *data, size_t len, struct x509_certificate **cert ); extern int x509_validate ( struct x509_certificate *cert, struct x509_certificate *issuer, time_t time, struct x509_root *root ); +extern int x509_check_name ( struct x509_certificate *cert, const char *name ); extern struct x509_chain * x509_alloc_chain ( void ); extern int x509_append ( struct x509_chain *chain, @@ -344,6 +355,7 @@ extern int x509_append_raw ( struct x509_chain *chain, const void *data, extern int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ); extern int x509_validate_chain ( struct x509_chain *chain, time_t time, + struct x509_chain *store, struct x509_root *root ); /* Functions exposed only for unit testing */ diff --git a/roms/ipxe/src/include/linux_api.h b/roms/ipxe/src/include/linux_api.h index 94dc991f0..28a3cda3b 100644 --- a/roms/ipxe/src/include/linux_api.h +++ b/roms/ipxe/src/include/linux_api.h @@ -47,11 +47,13 @@ typedef __kernel_loff_t loff_t; typedef unsigned long nfds_t; typedef uint32_t useconds_t; #define MAP_FAILED ( ( void * ) -1 ) +#define SEEK_SET 0 extern long linux_syscall ( int number, ... ); extern int linux_open ( const char *pathname, int flags ); extern int linux_close ( int fd ); +extern off_t linux_lseek ( int fd, off_t offset, int whence ); extern __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ); extern __kernel_ssize_t linux_write ( int fd, const void *buf, __kernel_size_t count ); diff --git a/roms/ipxe/src/include/little_bswap.h b/roms/ipxe/src/include/little_bswap.h index a5dc9c875..92dd26ba1 100644 --- a/roms/ipxe/src/include/little_bswap.h +++ b/roms/ipxe/src/include/little_bswap.h @@ -3,6 +3,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#define htonll(x) __bswap_64(x) +#define ntohll(x) __bswap_64(x) #define ntohl(x) __bswap_32(x) #define htonl(x) __bswap_32(x) #define ntohs(x) __bswap_16(x) diff --git a/roms/ipxe/src/include/stddef.h b/roms/ipxe/src/include/stddef.h index 83a0f0ed6..bf792771f 100644 --- a/roms/ipxe/src/include/stddef.h +++ b/roms/ipxe/src/include/stddef.h @@ -23,7 +23,10 @@ FILE_LICENCE ( GPL2_ONLY ); /* __WCHAR_TYPE__ is defined by gcc and will change if -fshort-wchar is used */ #ifndef __WCHAR_TYPE__ -#define __WCHAR_TYPE__ long int +#define __WCHAR_TYPE__ uint16_t +#endif +#ifndef __WINT_TYPE__ +#define __WINT_TYPE__ int #endif typedef __WCHAR_TYPE__ wchar_t; typedef __WINT_TYPE__ wint_t; diff --git a/roms/ipxe/src/include/stdlib.h b/roms/ipxe/src/include/stdlib.h index 3d30858ff..2951522b8 100644 --- a/roms/ipxe/src/include/stdlib.h +++ b/roms/ipxe/src/include/stdlib.h @@ -34,19 +34,7 @@ static inline int strtoul_base ( const char **pp, int base ) return base; } -static inline unsigned int strtoul_charval ( unsigned int charval ) -{ - if ( charval >= 'a' ) { - charval = ( charval - 'a' + 10 ); - } else if ( charval >= 'A' ) { - charval = ( charval - 'A' + 10 ); - } else if ( charval <= '9' ) { - charval = ( charval - '0' ); - } - - return charval; -} - +extern unsigned int strtoul_charval ( unsigned int charval ); extern unsigned long strtoul ( const char *p, char **endp, int base ); extern unsigned long long strtoull ( const char *p, char **endp, int base ); @@ -105,6 +93,10 @@ static inline void srand ( unsigned int seed ) { **************************************************************************** */ +static inline __attribute__ (( always_inline )) int abs ( int value ) { + return __builtin_abs ( value ); +} + extern int system ( const char *command ); extern __asmcall int main ( void ); diff --git a/roms/ipxe/src/include/strings.h b/roms/ipxe/src/include/strings.h index c7063d682..6912a1e45 100644 --- a/roms/ipxe/src/include/strings.h +++ b/roms/ipxe/src/include/strings.h @@ -5,17 +5,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <limits.h> #include <string.h> +#include <bits/strings.h> static inline __attribute__ (( always_inline )) int -__constant_flsl ( unsigned long x ) { +__constant_flsll ( unsigned long long x ) { int r = 0; -#if ULONG_MAX > 0xffffffff - if ( x & 0xffffffff00000000UL ) { + if ( x & 0xffffffff00000000ULL ) { x >>= 32; r += 32; } -#endif if ( x & 0xffff0000UL ) { x >>= 16; r += 16; @@ -42,8 +41,16 @@ __constant_flsl ( unsigned long x ) { return r; } -/* We don't actually have these functions yet */ -extern int __flsl ( long x ); +static inline __attribute__ (( always_inline )) int +__constant_flsl ( unsigned long x ) { + return __constant_flsll ( x ); +} + +int __flsll ( long long x ); +int __flsl ( long x ); + +#define flsll( x ) \ + ( __builtin_constant_p ( x ) ? __constant_flsll ( x ) : __flsll ( x ) ) #define flsl( x ) \ ( __builtin_constant_p ( x ) ? __constant_flsl ( x ) : __flsl ( x ) ) diff --git a/roms/ipxe/src/include/sys/time.h b/roms/ipxe/src/include/sys/time.h index 6c9b7421b..2647d3588 100644 --- a/roms/ipxe/src/include/sys/time.h +++ b/roms/ipxe/src/include/sys/time.h @@ -6,6 +6,8 @@ * Date and time */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> /** Seconds since the Epoch diff --git a/roms/ipxe/src/include/time.h b/roms/ipxe/src/include/time.h index bc73af4cd..452a544bb 100644 --- a/roms/ipxe/src/include/time.h +++ b/roms/ipxe/src/include/time.h @@ -6,6 +6,8 @@ * Date and time */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include <sys/time.h> #include <ipxe/time.h> diff --git a/roms/ipxe/src/include/usr/autoboot.h b/roms/ipxe/src/include/usr/autoboot.h index 25b9f073d..f562b2b12 100644 --- a/roms/ipxe/src/include/usr/autoboot.h +++ b/roms/ipxe/src/include/usr/autoboot.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/in.h> +#include <ipxe/device.h> struct net_device; struct uri; struct settings; @@ -25,12 +26,14 @@ enum uriboot_flags { URIBOOT_NO_SAN_BOOT | \ URIBOOT_NO_SAN_UNHOOK ) +extern struct device_description autoboot_device; + extern int uriboot ( struct uri *filename, struct uri *root_path, int drive, unsigned int flags ); extern struct uri * fetch_next_server_and_filename ( struct settings *settings ); extern int netboot ( struct net_device *netdev ); -extern int autoboot ( void ); +extern void ipxe ( struct net_device *netdev ); extern int pxe_menu_boot ( struct net_device *netdev ); diff --git a/roms/ipxe/src/include/usr/dhcpmgmt.h b/roms/ipxe/src/include/usr/dhcpmgmt.h index 2394dac42..af1eceb17 100644 --- a/roms/ipxe/src/include/usr/dhcpmgmt.h +++ b/roms/ipxe/src/include/usr/dhcpmgmt.h @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct net_device; -extern int dhcp ( struct net_device *netdev ); extern int pxebs ( struct net_device *netdev, unsigned int pxe_type ); #endif /* _USR_DHCPMGMT_H */ diff --git a/roms/ipxe/src/include/usr/ifmgmt.h b/roms/ipxe/src/include/usr/ifmgmt.h index f762c7ba9..db77f1f1b 100644 --- a/roms/ipxe/src/include/usr/ifmgmt.h +++ b/roms/ipxe/src/include/usr/ifmgmt.h @@ -10,10 +10,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct net_device; +struct net_device_configurator; extern int ifopen ( struct net_device *netdev ); +extern int ifconf ( struct net_device *netdev, + struct net_device_configurator *configurator ); extern void ifclose ( struct net_device *netdev ); extern void ifstat ( struct net_device *netdev ); -extern int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ); +extern int iflinkwait ( struct net_device *netdev, unsigned long timeout ); #endif /* _USR_IFMGMT_H */ diff --git a/roms/ipxe/src/include/usr/imgmgmt.h b/roms/ipxe/src/include/usr/imgmgmt.h index 8db5c9780..5e25c562b 100644 --- a/roms/ipxe/src/include/usr/imgmgmt.h +++ b/roms/ipxe/src/include/usr/imgmgmt.h @@ -11,9 +11,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/image.h> -extern int imgdownload ( struct uri *uri, struct image **image ); -extern int imgdownload_string ( const char *uri_string, struct image **image ); -extern int imgacquire ( const char *name, struct image **image ); +extern int imgdownload ( struct uri *uri, unsigned long timeout, + struct image **image ); +extern int imgdownload_string ( const char *uri_string, unsigned long timeout, + struct image **image ); +extern int imgacquire ( const char *name, unsigned long timeout, + struct image **image ); extern void imgstat ( struct image *image ); #endif /* _USR_IMGMGMT_H */ diff --git a/roms/ipxe/src/include/usr/ipstat.h b/roms/ipxe/src/include/usr/ipstat.h new file mode 100644 index 000000000..5ff8b40c3 --- /dev/null +++ b/roms/ipxe/src/include/usr/ipstat.h @@ -0,0 +1,14 @@ +#ifndef _USR_IPSTAT_H +#define _USR_IPSTAT_H + +/** @file + * + * IP statistics + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern void ipstat ( void ); + +#endif /* _USR_IPSTAT_H */ diff --git a/roms/ipxe/src/include/usr/neighmgmt.h b/roms/ipxe/src/include/usr/neighmgmt.h new file mode 100644 index 000000000..3c2b704af --- /dev/null +++ b/roms/ipxe/src/include/usr/neighmgmt.h @@ -0,0 +1,14 @@ +#ifndef _USR_NEIGHMGMT_H +#define _USR_NEIGHMGMT_H + +/** @file + * + * Neighbour management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern void nstat ( void ); + +#endif /* _USR_NEIGHMGMT_H */ diff --git a/roms/ipxe/src/include/usr/pingmgmt.h b/roms/ipxe/src/include/usr/pingmgmt.h new file mode 100644 index 000000000..45ad5d394 --- /dev/null +++ b/roms/ipxe/src/include/usr/pingmgmt.h @@ -0,0 +1,16 @@ +#ifndef _USR_PINGMGMT_H +#define _USR_PINGMGMT_H + +/** @file + * + * ICMP ping management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> + +extern int ping ( const char *hostname, unsigned long timeout, size_t len ); + +#endif /* _USR_PINGMGMT_H */ diff --git a/roms/ipxe/src/include/usr/profstat.h b/roms/ipxe/src/include/usr/profstat.h new file mode 100644 index 000000000..06ea251a0 --- /dev/null +++ b/roms/ipxe/src/include/usr/profstat.h @@ -0,0 +1,14 @@ +#ifndef _USR_PROFSTAT_H +#define _USR_PROFSTAT_H + +/** @file + * + * Profiling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern void profstat ( void ); + +#endif /* _USR_PROFSTAT_H */ diff --git a/roms/ipxe/src/include/usr/prompt.h b/roms/ipxe/src/include/usr/prompt.h index fc1946c7a..57e43d2dc 100644 --- a/roms/ipxe/src/include/usr/prompt.h +++ b/roms/ipxe/src/include/usr/prompt.h @@ -9,6 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); -extern int prompt ( const char *text, unsigned int wait_ms, int key ); +extern int prompt ( const char *text, unsigned long timeout, int key ); #endif /* _USR_PROMPT_H */ diff --git a/roms/ipxe/src/include/usr/route.h b/roms/ipxe/src/include/usr/route.h index 855fa7ba8..b914f4b84 100644 --- a/roms/ipxe/src/include/usr/route.h +++ b/roms/ipxe/src/include/usr/route.h @@ -3,12 +3,33 @@ /** @file * - * Routing table management + * Routing management * */ FILE_LICENCE ( GPL2_OR_LATER ); +#include <ipxe/tables.h> + +/** A routing family */ +struct routing_family { + /** + * Print routes for a network device + * + * @v netdev Network device + */ + void ( * print ) ( struct net_device *netdev ); +}; + +/** Routing family table */ +#define ROUTING_FAMILIES __table ( struct routing_family, "routing_families" ) + +/** Declare a routing family */ +#define __routing_family( order ) __table_entry ( ROUTING_FAMILIES, order ) + +#define ROUTING_IPV4 01 +#define ROUTING_IPV6 02 + extern void route ( void ); #endif /* _USR_ROUTE_H */ diff --git a/roms/ipxe/src/include/usr/sync.h b/roms/ipxe/src/include/usr/sync.h new file mode 100644 index 000000000..0047d4ed9 --- /dev/null +++ b/roms/ipxe/src/include/usr/sync.h @@ -0,0 +1,14 @@ +#ifndef _USR_SYNC_H +#define _USR_SYNC_H + +/** @file + * + * Wait for pending operations to complete + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern int sync ( unsigned long timeout ); + +#endif /* _USR_SYNC_H */ diff --git a/roms/ipxe/src/interface/efi/efi_bofm.c b/roms/ipxe/src/interface/efi/efi_bofm.c index c313d2e97..4982b22cc 100644 --- a/roms/ipxe/src/interface/efi/efi_bofm.c +++ b/roms/ipxe/src/interface/efi/efi_bofm.c @@ -181,7 +181,7 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, /* Create corresponding PCI device, if any */ efipci = efipci_create ( efidrv, device ); if ( ! efipci ) { - efirc = EFI_UNSUPPORTED; + rc = -ENOTSUP; goto err_not_pci; } @@ -189,16 +189,15 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, if ( ( rc = bofm_find_driver ( &efipci->pci ) ) != 0 ) { DBGCP ( efidrv, "EFIBOFM " PCI_FMT " has no driver\n", PCI_ARGS ( &efipci->pci ) ); - efirc = EFI_UNSUPPORTED; goto err_no_driver; } /* Locate BOFM protocol */ if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL, &bofm1.interface ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM " "protocol\n", PCI_ARGS ( &efipci->pci ) ); - efirc = EFI_UNSUPPORTED; goto err_not_bofm; } @@ -207,9 +206,10 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, 0x04 /* Can change MAC */, 0x00 /* No iSCSI */, 0x02 /* Version */ ))!=0){ + rc = -EEFI ( efirc ); DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not register " "support: %s\n", PCI_ARGS ( &efipci->pci ), - efi_strerror ( efirc ) ); + strerror ( rc ) ); goto err_cannot_register; } @@ -226,7 +226,7 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, err_no_driver: efipci_destroy ( efidrv, efipci ); err_not_pci: - return efirc; + return EFIRC ( rc ); } /** @@ -254,25 +254,27 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, struct efi_pci_device *efipci; IBM_BOFM_TABLE *bofmtab; IBM_BOFM_TABLE *bofmtab2; - EFI_STATUS efirc; int bofmrc; + EFI_STATUS efirc; + int rc; DBGCP ( efidrv, "EFIBOFM DRIVER_START %p (%p)\n", device, child ); /* Create corresponding PCI device */ efipci = efipci_create ( efidrv, device ); if ( ! efipci ) { - efirc = EFI_OUT_OF_RESOURCES; + rc = -ENOMEM; goto err_create; } /* Enable PCI device */ - if ( ( efirc = efipci_enable ( efipci ) ) != 0 ) + if ( ( rc = efipci_enable ( efipci ) ) != 0 ) goto err_enable; /* Locate BOFM protocol */ if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL, &bofm1.interface ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM " "protocol\n", PCI_ARGS ( &efipci->pci ) ); goto err_locate_bofm; @@ -324,17 +326,19 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, if ( bofmtab2 ) { if ( ( efirc = bofm2.bofm2->SetStatus ( bofm2.bofm2, device, FALSE, bofmrc ) ) != 0){ + rc = -EEFI ( efirc ); DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set " "BOFM2 status: %s\n", PCI_ARGS ( &efipci->pci ), - efi_strerror ( efirc ) ); + strerror ( rc ) ); goto err_set_status; } } else { if ( ( efirc = bofm1.bofm1->SetStatus ( bofm1.bofm1, device, FALSE, bofmrc ) ) != 0){ + rc = -EEFI ( efirc ); DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set " "BOFM status: %s\n", PCI_ARGS ( &efipci->pci ), - efi_strerror ( efirc ) ); + strerror ( rc ) ); goto err_set_status; } } @@ -350,7 +354,7 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, err_enable: efipci_destroy ( efidrv, efipci ); err_create: - return efirc; + return EFIRC ( rc ); } /** @@ -383,21 +387,33 @@ static struct efi_driver efi_bofm_driver = * Install EFI BOFM driver * */ -static void efi_bofm_driver_init ( void ) { +static void efi_bofm_driver_startup ( void ) { struct efi_driver *efidrv = &efi_bofm_driver; - EFI_STATUS efirc; + int rc; /* Install driver */ - if ( ( efirc = efi_driver_install ( efidrv ) ) != 0 ) { + if ( ( rc = efi_driver_install ( efidrv ) ) != 0 ) { DBGC ( efidrv, "EFIBOFM could not install driver: %s\n", - efi_strerror ( efirc ) ); + strerror ( rc ) ); return; } DBGC ( efidrv, "EFIBOFM driver installed\n" ); } +/** + * Shut down EFI BOFM driver + * + * @v booting System is shutting down for OS boot + */ +static void efi_bofm_driver_shutdown ( int booting __unused ) { + struct efi_driver *efidrv = &efi_bofm_driver; + + efi_driver_uninstall ( efidrv ); +} + /** EFI BOFM startup function */ struct startup_fn startup_bofm __startup_fn ( STARTUP_EARLY ) = { - .startup = efi_bofm_driver_init, + .startup = efi_bofm_driver_startup, + .shutdown = efi_bofm_driver_shutdown, }; diff --git a/roms/ipxe/src/interface/efi/efi_console.c b/roms/ipxe/src/interface/efi/efi_console.c index a30ca301b..af60d4f91 100644 --- a/roms/ipxe/src/interface/efi/efi_console.c +++ b/roms/ipxe/src/interface/efi/efi_console.c @@ -20,6 +20,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> +#include <string.h> +#include <errno.h> #include <assert.h> #include <ipxe/efi/efi.h> #include <ipxe/ansiesc.h> @@ -62,11 +64,13 @@ static unsigned int efi_attr = ATTR_DEFAULT; /** * Handle ANSI CUP (cursor position) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params[0] Row (1 is top) * @v params[1] Column (1 is left) */ -static void efi_handle_cup ( unsigned int count __unused, int params[] ) { +static void efi_handle_cup ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, int params[] ) { EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; int cx = ( params[1] - 1 ); int cy = ( params[0] - 1 ); @@ -82,11 +86,13 @@ static void efi_handle_cup ( unsigned int count __unused, int params[] ) { /** * Handle ANSI ED (erase in page) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params[0] Region to erase */ -static void efi_handle_ed ( unsigned int count __unused, - int params[] __unused ) { +static void efi_handle_ed ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, + int params[] __unused ) { EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; /* We assume that we always clear the whole screen */ @@ -98,10 +104,12 @@ static void efi_handle_ed ( unsigned int count __unused, /** * Handle ANSI SGR (set graphics rendition) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params List of graphic rendition aspects */ -static void efi_handle_sgr ( unsigned int count, int params[] ) { +static void efi_handle_sgr ( struct ansiesc_context *ctx __unused, + unsigned int count, int params[] ) { EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; static const uint8_t efi_attr_fcols[10] = { ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN, @@ -227,6 +235,7 @@ static int efi_getchar ( void ) { const char *ansi_seq; EFI_INPUT_KEY key; EFI_STATUS efirc; + int rc; /* If we are mid-sequence, pass out the next byte */ if ( *ansi_input ) @@ -234,8 +243,8 @@ static int efi_getchar ( void ) { /* Read key from real EFI console */ if ( ( efirc = conin->ReadKeyStroke ( conin, &key ) ) != 0 ) { - DBG ( "EFI could not read keystroke: %s\n", - efi_strerror ( efirc ) ); + rc = -EEFI ( efirc ); + DBG ( "EFI could not read keystroke: %s\n", strerror ( rc ) ); return 0; } DBG2 ( "EFI read key stroke with unicode %04x scancode %04x\n", diff --git a/roms/ipxe/src/interface/efi/efi_debug.c b/roms/ipxe/src/interface/efi/efi_debug.c new file mode 100644 index 000000000..4ed666077 --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_debug.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * EFI debugging utilities + * + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ipxe/uuid.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> +#include <ipxe/efi/Protocol/DevicePath.h> +#include <ipxe/efi/Protocol/DevicePathToText.h> + +/** Device path to text protocol */ +static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *efidpt; +EFI_REQUIRE_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt ); + +/** + * Convert GUID to a printable string + * + * @v guid GUID + * @ret string Printable string + */ +const char * efi_guid_ntoa ( EFI_GUID *guid ) { + union { + union uuid uuid; + EFI_GUID guid; + } u; + + /* Convert GUID to standard endianness */ + memcpy ( &u.guid, guid, sizeof ( u.guid ) ); + uuid_mangle ( &u.uuid ); + return uuid_ntoa ( &u.uuid ); +} + +/** + * Print list of protocol handlers attached to a handle + * + * @v handle EFI handle + */ +void dbg_efi_protocols ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_GUID **protocols; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Retrieve list of protocols */ + if ( ( efirc = bs->ProtocolsPerHandle ( handle, &protocols, + &count ) ) != 0 ) { + rc = -EEFI ( efirc ); + printf ( "EFI could not retrieve protocols for %p: %s\n", + handle, strerror ( rc ) ); + return; + } + + /* Dump list of protocols */ + for ( i = 0 ; i < count ; i++ ) + printf ( "%s\n", efi_guid_ntoa ( protocols[i] ) ); + + /* Free list */ + bs->FreePool ( protocols ); +} + +/** + * Print device path + * + * @v path Device path + */ +void dbg_efi_devpath ( EFI_DEVICE_PATH_PROTOCOL *path ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DEVICE_PATH_PROTOCOL *end; + CHAR16 *text; + size_t len; + + /* Convert path to a textual representation */ + text = efidpt->ConvertDevicePathToText ( path, TRUE, FALSE ); + if ( ! text ) { + printf ( "<cannot convert>:\n" ); + end = efi_devpath_end ( path ); + len = ( ( ( void * ) end ) - ( ( void * ) path ) + + sizeof ( *end ) ); + dbg_hex_dump_da ( 0, path, len ); + return; + } + + /* Print path */ + printf ( "%ls", text ); + + /* Free path */ + bs->FreePool ( text ); +} diff --git a/roms/ipxe/src/interface/efi/efi_download.c b/roms/ipxe/src/interface/efi/efi_download.c index 250946e28..80279f7f9 100644 --- a/roms/ipxe/src/interface/efi/efi_download.c +++ b/roms/ipxe/src/interface/efi/efi_download.c @@ -20,12 +20,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <string.h> +#include <errno.h> #include <ipxe/open.h> #include <ipxe/process.h> #include <ipxe/iobuf.h> #include <ipxe/xfer.h> #include <ipxe/efi/efi.h> -#include <ipxe/efi/ipxe_download.h> +#include <ipxe/efi/efi_download.h> /** iPXE download protocol GUID */ static EFI_GUID ipxe_download_protocol_guid @@ -59,7 +60,7 @@ struct efi_download_file { */ static void efi_download_close ( struct efi_download_file *file, int rc ) { - file->finish_callback ( file->context, RC_TO_EFIRC ( rc ) ); + file->finish_callback ( file->context, EFIRC ( rc ) ); intf_shutdown ( &file->xfer, rc ); } @@ -77,6 +78,7 @@ static int efi_download_deliver_iob ( struct efi_download_file *file, struct xfer_metadata *meta ) { EFI_STATUS efirc; size_t len = iob_len ( iobuf ); + int rc; /* Calculate new buffer position */ if ( meta->flags & XFER_FL_ABS_OFFSET ) @@ -84,14 +86,21 @@ static int efi_download_deliver_iob ( struct efi_download_file *file, file->pos += meta->offset; /* Call out to the data handler */ - efirc = file->data_callback ( file->context, iobuf->data, - len, file->pos ); + if ( ( efirc = file->data_callback ( file->context, iobuf->data, + len, file->pos ) ) != 0 ) { + rc = -EEFI ( efirc ); + goto err_callback; + } /* Update current buffer position */ file->pos += len; + /* Success */ + rc = 0; + + err_callback: free_iob ( iobuf ); - return EFIRC_TO_RC ( efirc ); + return rc; } /** Data transfer interface operations */ @@ -135,7 +144,7 @@ efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused, rc = xfer_open ( &file->xfer, LOCATION_URI_STRING, Url ); if ( rc ) { free ( file ); - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } file->pos = 0; @@ -162,7 +171,7 @@ efi_download_abort ( IPXE_DOWNLOAD_PROTOCOL *This __unused, EFI_STATUS Status ) { struct efi_download_file *file = File; - efi_download_close ( file, EFIRC_TO_RC ( Status ) ); + efi_download_close ( file, -EEFI ( Status ) ); return EFI_SUCCESS; } @@ -187,47 +196,41 @@ static IPXE_DOWNLOAD_PROTOCOL ipxe_download_protocol_interface = { }; /** - * Create a new device handle with a iPXE download protocol attached to it. + * Install iPXE download protocol * - * @v device_handle Newly created device handle (output) + * @v handle EFI handle * @ret rc Return status code */ -int efi_download_install ( EFI_HANDLE *device_handle ) { +int efi_download_install ( EFI_HANDLE *handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_STATUS efirc; - EFI_HANDLE handle = NULL; - if (efi_loaded_image->DeviceHandle) { /* TODO: ensure handle is the NIC (maybe efi_image has a better way to indicate the handle doing SNP?) */ - handle = efi_loaded_image->DeviceHandle; - } + int rc; - DBG ( "Installing ipxe protocol interface (%p)... ", - &ipxe_download_protocol_interface ); efirc = bs->InstallMultipleProtocolInterfaces ( - &handle, + handle, &ipxe_download_protocol_guid, &ipxe_download_protocol_interface, NULL ); if ( efirc ) { - DBG ( "failed (%s)\n", efi_strerror ( efirc ) ); - return EFIRC_TO_RC ( efirc ); + rc = -EEFI ( efirc ); + DBG ( "Could not install download protocol: %s\n", + strerror ( rc ) ); + return rc; } - DBG ( "success (%p)\n", handle ); - *device_handle = handle; return 0; } /** - * Remove the iPXE download protocol from the given handle, and if nothing - * else is attached, destroy the handle. + * Uninstall iPXE download protocol * - * @v device_handle EFI device handle to remove from + * @v handle EFI handle */ -void efi_download_uninstall ( EFI_HANDLE device_handle ) { +void efi_download_uninstall ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; bs->UninstallMultipleProtocolInterfaces ( - device_handle, - ipxe_download_protocol_guid, - ipxe_download_protocol_interface ); + handle, + &ipxe_download_protocol_guid, + &ipxe_download_protocol_interface, NULL ); } diff --git a/roms/ipxe/src/interface/efi/efi_driver.c b/roms/ipxe/src/interface/efi/efi_driver.c index deb3cf2cd..1bc28e7c3 100644 --- a/roms/ipxe/src/interface/efi/efi_driver.c +++ b/roms/ipxe/src/interface/efi/efi_driver.c @@ -21,6 +21,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> #include <stdio.h> +#include <string.h> +#include <errno.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/DriverBinding.h> #include <ipxe/efi/Protocol/ComponentName2.h> @@ -117,16 +119,81 @@ efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused, } /** + * Try to connect EFI driver + * + * @v efidrv EFI driver + * @v handle Controller handle + */ +static void efi_driver_connect ( struct efi_driver *efidrv, EFI_HANDLE handle ){ + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE drivers[2] = { efidrv->driver.DriverBindingHandle, NULL }; + + bs->ConnectController ( handle, drivers, NULL, FALSE ); +} + +/** + * Try to disconnect EFI driver + * + * @v efidrv EFI driver + * @v handle Controller handle + */ +static void efi_driver_disconnect ( struct efi_driver *efidrv, + EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + bs->DisconnectController ( handle, efidrv->driver.DriverBindingHandle, + NULL ); +} + +/** + * Connect/disconnect EFI driver from all handles + * + * @v efidrv EFI driver + * @v method Connect/disconnect method + * @ret rc Return status code + */ +static int efi_driver_handles ( struct efi_driver *efidrv, + void ( * method ) ( struct efi_driver *efidrv, + EFI_HANDLE handle ) ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE *handles; + UINTN num_handles; + EFI_STATUS efirc; + UINTN i; + int rc; + + /* Enumerate all handles */ + if ( ( efirc = bs->LocateHandleBuffer ( AllHandles, NULL, NULL, + &num_handles, + &handles ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( efidrv, "EFIDRV %s could not list handles: %s\n", + efidrv->name, strerror ( rc ) ); + return rc; + } + + /* Connect/disconnect driver from all handles */ + for ( i = 0 ; i < num_handles ; i++ ) + method ( efidrv, handles[i] ); + + /* Free list of handles */ + bs->FreePool ( handles ); + + return 0; +} + +/** * Install EFI driver * * @v efidrv EFI driver - * @ret efirc EFI status code + * @ret rc Return status code */ -EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ) { +int efi_driver_install ( struct efi_driver *efidrv ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_DRIVER_BINDING_PROTOCOL *driver = &efidrv->driver; EFI_COMPONENT_NAME2_PROTOCOL *wtf = &efidrv->wtf; EFI_STATUS efirc; + int rc; /* Configure driver binding protocol */ driver->ImageHandle = efi_image_handle; @@ -140,7 +207,9 @@ EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ) { efi_snprintf ( efidrv->wname, ( sizeof ( efidrv->wname ) / sizeof ( efidrv->wname[0] ) ), - PRODUCT_SHORT_NAME " - %s", efidrv->name ); + PRODUCT_SHORT_NAME "%s%s", + ( efidrv->name ? " - " : "" ), + ( efidrv->name ? efidrv->name : "" ) ); /* Install driver */ if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( @@ -148,11 +217,37 @@ EFI_STATUS efi_driver_install ( struct efi_driver *efidrv ) { &efi_driver_binding_protocol_guid, driver, &efi_component_name2_protocol_guid, wtf, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( efidrv, "EFIDRV %s could not install protocol: %s\n", - efidrv->name, efi_strerror ( efirc ) ); - return efirc; + efidrv->name, strerror ( rc ) ); + return rc; } + /* Connect devices */ + DBGC ( efidrv, "EFIDRV %s connecting devices\n", efidrv->name ); + efi_driver_handles ( efidrv, efi_driver_connect ); + DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name ); return 0; } + +/** + * Uninstall EFI driver + * + * @v efidrv EFI driver + */ +void efi_driver_uninstall ( struct efi_driver *efidrv ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Disconnect the driver from its devices */ + DBGC ( efidrv, "EFIDRV %s disconnecting devices\n", efidrv->name ); + efi_driver_handles ( efidrv, efi_driver_disconnect ); + + /* Uninstall the driver */ + bs->UninstallMultipleProtocolInterfaces ( + efidrv->driver.DriverBindingHandle, + &efi_driver_binding_protocol_guid, &efidrv->driver, + &efi_component_name2_protocol_guid, &efidrv->wtf, + NULL ); + DBGC ( efidrv, "EFIDRV %s uninstalled\n", efidrv->name ); +} diff --git a/roms/ipxe/src/interface/efi/efi_file.c b/roms/ipxe/src/interface/efi/efi_file.c new file mode 100644 index 000000000..4c482d2e5 --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_file.c @@ -0,0 +1,596 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * EFI file protocols + * + */ + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <wchar.h> +#include <ipxe/image.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/Protocol/SimpleFileSystem.h> +#include <ipxe/efi/Protocol/BlockIo.h> +#include <ipxe/efi/Guid/FileInfo.h> +#include <ipxe/efi/Guid/FileSystemInfo.h> +#include <ipxe/efi/efi_strings.h> +#include <ipxe/efi/efi_file.h> + +/** EFI simple file system protocol GUID */ +static EFI_GUID efi_simple_file_system_protocol_guid + = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; + +/** EFI file information GUID */ +static EFI_GUID efi_file_info_id = EFI_FILE_INFO_ID; + +/** EFI file system information GUID */ +static EFI_GUID efi_file_system_info_id = EFI_FILE_SYSTEM_INFO_ID; + +/** EFI block I/O protocol GUID */ +static EFI_GUID efi_block_io_protocol_guid + = EFI_BLOCK_IO_PROTOCOL_GUID; + +/** EFI media ID */ +#define EFI_MEDIA_ID_MAGIC 0x69505845 + +/** An image exposed as an EFI file */ +struct efi_file { + /** EFI file protocol */ + EFI_FILE_PROTOCOL file; + /** Image */ + struct image *image; + /** Current file position */ + size_t pos; +}; + +static struct efi_file efi_file_root; + +/** + * Get EFI file name (for debugging) + * + * @v file EFI file + * @ret name Name + */ +static const char * efi_file_name ( struct efi_file *file ) { + + return ( file->image ? file->image->name : "<root>" ); +} + +/** + * Open file + * + * @v this EFI file + * @ret new New EFI file + * @v wname Filename + * @v mode File mode + * @v attributes File attributes (for newly-created files) + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, + CHAR16 *wname, UINT64 mode __unused, + UINT64 attributes __unused ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + char name[ wcslen ( wname ) + 1 /* NUL */ ]; + struct efi_file *new_file; + struct image *image; + + /* Initial '\' indicates opening from the root directory */ + while ( *wname == L'\\' ) { + file = &efi_file_root; + wname++; + } + + /* Allow root directory itself to be opened */ + if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) { + *new = &efi_file_root.file; + return 0; + } + + /* Fail unless opening from the root */ + if ( file->image ) { + DBGC ( file, "EFIFILE %s is not a directory\n", + efi_file_name ( file ) ); + return EFI_NOT_FOUND; + } + + /* Identify image */ + snprintf ( name, sizeof ( name ), "%ls", wname ); + image = find_image ( name ); + if ( ! image ) { + DBGC ( file, "EFIFILE \"%s\" does not exist\n", name ); + return EFI_NOT_FOUND; + } + + /* Fail unless opening read-only */ + if ( mode != EFI_FILE_MODE_READ ) { + DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n", + image->name, mode ); + return EFI_WRITE_PROTECTED; + } + + /* Allocate and initialise file */ + new_file = zalloc ( sizeof ( *new_file ) ); + memcpy ( &new_file->file, &efi_file_root.file, + sizeof ( new_file->file ) ); + new_file->image = image_get ( image ); + *new = &new_file->file; + DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) ); + + return 0; +} + +/** + * Close file + * + * @v this EFI file + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + /* Do nothing if this is the root */ + if ( ! file->image ) + return 0; + + /* Close file */ + DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) ); + image_put ( file->image ); + free ( file ); + + return 0; +} + +/** + * Close and delete file + * + * @v this EFI file + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) ); + + /* Close file */ + efi_file_close ( this ); + + /* Warn of failure to delete */ + return EFI_WARN_DELETE_FAILURE; +} + +/** + * Return variable-length data structure + * + * @v base Base data structure (starting with UINT64) + * @v base_len Length of base data structure + * @v name Name to append to base data structure + * @v len Length of data buffer + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len, + const char *name, UINTN *len, VOID *data ) { + size_t name_len; + + /* Calculate structure length */ + name_len = strlen ( name ); + *base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ); + if ( *len < *base ) { + *len = *base; + return EFI_BUFFER_TOO_SMALL; + } + + /* Copy data to buffer */ + *len = *base; + memcpy ( data, base, base_len ); + efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ), + "%s", name ); + + return 0; +} + +/** + * Return file information structure + * + * @v image Image, or NULL for the root directory + * @v len Length of data buffer + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS efi_file_info ( struct image *image, UINTN *len, + VOID *data ) { + EFI_FILE_INFO info; + const char *name; + + /* Populate file information */ + memset ( &info, 0, sizeof ( info ) ); + if ( image ) { + info.FileSize = image->len; + info.PhysicalSize = image->len; + info.Attribute = EFI_FILE_READ_ONLY; + name = image->name; + } else { + info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY ); + name = ""; + } + + return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name, + len, data ); +} + +/** + * Read directory entry + * + * @v file EFI file + * @v len Length to read + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len, + VOID *data ) { + EFI_STATUS efirc; + struct image *image; + unsigned int index; + + /* Construct directory entry at current position */ + index = file->pos; + for_each_image ( image ) { + if ( index-- == 0 ) { + efirc = efi_file_info ( image, len, data ); + if ( efirc == 0 ) + file->pos++; + return efirc; + } + } + + /* No more entries */ + *len = 0; + return 0; +} + +/** + * Read from file + * + * @v this EFI file + * @v len Length to read + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this, + UINTN *len, VOID *data ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + size_t remaining; + + /* If this is the root directory, then construct a directory entry */ + if ( ! file->image ) + return efi_file_read_dir ( file, len, data ); + + /* Read from the file */ + remaining = ( file->image->len - file->pos ); + if ( *len > remaining ) + *len = remaining; + DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n", + efi_file_name ( file ), file->pos, + ( ( size_t ) ( file->pos + *len ) ) ); + copy_from_user ( data, file->image->data, file->pos, *len ); + file->pos += *len; + return 0; +} + +/** + * Write to file + * + * @v this EFI file + * @v len Length to write + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this, + UINTN *len, VOID *data __unused ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n", + efi_file_name ( file ), file->pos, + ( ( size_t ) ( file->pos + *len ) ) ); + return EFI_WRITE_PROTECTED; +} + +/** + * Set file position + * + * @v this EFI file + * @v position New file position + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this, + UINT64 position ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + /* If this is the root directory, reset to the start */ + if ( ! file->image ) { + DBGC ( file, "EFIFILE root directory rewound\n" ); + file->pos = 0; + return 0; + } + + /* Check for the magic end-of-file value */ + if ( position == 0xffffffffffffffffULL ) + position = file->image->len; + + /* Fail if we attempt to seek past the end of the file (since + * we do not support writes). + */ + if ( position > file->image->len ) { + DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n", + efi_file_name ( file ), position, file->image->len ); + return EFI_UNSUPPORTED; + } + + /* Set position */ + file->pos = position; + DBGC ( file, "EFIFILE %s position set to %#08zx\n", + efi_file_name ( file ), file->pos ); + + return 0; +} + +/** + * Get file position + * + * @v this EFI file + * @ret position New file position + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this, + UINT64 *position ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + *position = file->pos; + return 0; +} + +/** + * Get file information + * + * @v this EFI file + * @v type Type of information + * @v len Buffer size + * @v data Buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this, + EFI_GUID *type, + UINTN *len, VOID *data ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + EFI_FILE_SYSTEM_INFO fsinfo; + struct image *image; + + /* Determine information to return */ + if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) { + + /* Get file information */ + DBGC ( file, "EFIFILE %s get file information\n", + efi_file_name ( file ) ); + return efi_file_info ( file->image, len, data ); + + } else if ( memcmp ( type, &efi_file_system_info_id, + sizeof ( *type ) ) == 0 ) { + + /* Get file system information */ + DBGC ( file, "EFIFILE %s get file system information\n", + efi_file_name ( file ) ); + memset ( &fsinfo, 0, sizeof ( fsinfo ) ); + fsinfo.ReadOnly = 1; + for_each_image ( image ) + fsinfo.VolumeSize += image->len; + return efi_file_varlen ( &fsinfo.Size, + SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE", + len, data ); + } else { + + DBGC ( file, "EFIFILE %s cannot get information of type %s\n", + efi_file_name ( file ), efi_guid_ntoa ( type ) ); + return EFI_UNSUPPORTED; + } +} + +/** + * Set file information + * + * @v this EFI file + * @v type Type of information + * @v len Buffer size + * @v data Buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type, + UINTN len __unused, VOID *data __unused ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + DBGC ( file, "EFIFILE %s cannot set information of type %s\n", + efi_file_name ( file ), efi_guid_ntoa ( type ) ); + return EFI_WRITE_PROTECTED; +} + +/** + * Flush file modified data + * + * @v this EFI file + * @v type Type of information + * @v len Buffer size + * @v data Buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) { + struct efi_file *file = container_of ( this, struct efi_file, file ); + + DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) ); + return 0; +} + +/** Root directory */ +static struct efi_file efi_file_root = { + .file = { + .Revision = EFI_FILE_PROTOCOL_REVISION, + .Open = efi_file_open, + .Close = efi_file_close, + .Delete = efi_file_delete, + .Read = efi_file_read, + .Write = efi_file_write, + .GetPosition = efi_file_get_position, + .SetPosition = efi_file_set_position, + .GetInfo = efi_file_get_info, + .SetInfo = efi_file_set_info, + .Flush = efi_file_flush, + }, + .image = NULL, +}; + +/** + * Open root directory + * + * @v filesystem EFI simple file system + * @ret file EFI file handle + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused, + EFI_FILE_PROTOCOL **file ) { + + *file = &efi_file_root.file; + return 0; +} + +/** EFI simple file system protocol */ +static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = { + .Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, + .OpenVolume = efi_file_open_volume, +}; + +/** Dummy block I/O reset */ +static EFI_STATUS EFIAPI +efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused, + BOOLEAN extended __unused ) { + return 0; +} + +/** Dummy block I/O read */ +static EFI_STATUS EFIAPI +efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, + UINT32 MediaId __unused, EFI_LBA lba __unused, + UINTN len __unused, VOID *data __unused ) { + return EFI_DEVICE_ERROR; +} + +/** Dummy block I/O write */ +static EFI_STATUS EFIAPI +efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused, + UINT32 MediaId __unused, EFI_LBA lba __unused, + UINTN len __unused, VOID *data __unused ) { + return EFI_DEVICE_ERROR; +} + +/** Dummy block I/O flush */ +static EFI_STATUS EFIAPI +efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) { + return 0; +} + +/** Dummy block I/O media */ +static EFI_BLOCK_IO_MEDIA efi_block_io_media = { + .MediaId = EFI_MEDIA_ID_MAGIC, + .MediaPresent = 1, + .ReadOnly = 1, + .BlockSize = 1, +}; + +/** Dummy EFI block I/O protocol */ +static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = { + .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION, + .Media = &efi_block_io_media, + .Reset = efi_block_io_reset, + .ReadBlocks = efi_block_io_read_blocks, + .WriteBlocks = efi_block_io_write_blocks, + .FlushBlocks = efi_block_io_flush_blocks, +}; + +/** + * Install EFI simple file system protocol + * + * @v handle EFI handle + * @ret rc Return status code + */ +int efi_file_install ( EFI_HANDLE *handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + int rc; + + /* Install the simple file system protocol and the block I/O + * protocol. We don't have a block device, but large parts of + * the EDK2 codebase make the assumption that file systems are + * normally attached to block devices, and so we create a + * dummy block device on the same handle just to keep things + * looking normal. + */ + if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( + handle, + &efi_block_io_protocol_guid, + &efi_block_io_protocol, + &efi_simple_file_system_protocol_guid, + &efi_simple_file_system_protocol, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( handle, "Could not install simple file system protocol: " + "%s\n", strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Uninstall EFI simple file system protocol + * + * @v handle EFI handle + */ +void efi_file_uninstall ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* We must install the file system protocol first, since + * otherwise the EDK2 code will attempt to helpfully uninstall + * it when the block I/O protocol is uninstalled, leading to a + * system lock-up. + */ + bs->UninstallMultipleProtocolInterfaces ( + handle, + &efi_simple_file_system_protocol_guid, + &efi_simple_file_system_protocol, + &efi_block_io_protocol_guid, + &efi_block_io_protocol, NULL ); +} diff --git a/roms/ipxe/src/interface/efi/efi_init.c b/roms/ipxe/src/interface/efi/efi_init.c index aaf894718..b4ed5c147 100644 --- a/roms/ipxe/src/interface/efi/efi_init.c +++ b/roms/ipxe/src/interface/efi/efi_init.c @@ -20,8 +20,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <string.h> +#include <errno.h> #include <ipxe/efi/efi.h> +#include <ipxe/efi/efi_driver.h> #include <ipxe/efi/Protocol/LoadedImage.h> +#include <ipxe/efi/Protocol/DevicePath.h> #include <ipxe/uuid.h> #include <ipxe/init.h> @@ -31,6 +34,9 @@ EFI_HANDLE efi_image_handle; /** Loaded image protocol for this image */ EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image; +/** Loaded image protocol device path for this image */ +EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; + /** System table passed to entry point */ EFI_SYSTEM_TABLE *efi_systab; @@ -38,9 +44,71 @@ EFI_SYSTEM_TABLE *efi_systab; static EFI_GUID efi_loaded_image_protocol_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; +/** EFI loaded image device path protocol GUID */ +static EFI_GUID efi_loaded_image_device_path_protocol_guid + = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; + /** Event used to signal shutdown */ static EFI_EVENT efi_shutdown_event; +/* Forward declarations */ +static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle ); + +/** + * Check to see if driver supports a device + * + * @v driver EFI driver + * @v device EFI device + * @v child Path to child device, if any + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_image_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, + EFI_HANDLE device __unused, + EFI_DEVICE_PATH_PROTOCOL *child __unused ) { + + return EFI_UNSUPPORTED; +} + +/** + * Attach driver to device + * + * @v driver EFI driver + * @v device EFI device + * @v child Path to child device, if any + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_image_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, + EFI_HANDLE device __unused, + EFI_DEVICE_PATH_PROTOCOL *child __unused ) { + + return EFI_UNSUPPORTED; +} + +/** + * Detach driver from device + * + * @v driver EFI driver + * @v device EFI device + * @v pci PCI device + * @v num_children Number of child devices + * @v children List of child devices + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_image_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, + EFI_HANDLE device __unused, UINTN num_children __unused, + EFI_HANDLE *children __unused ) { + + return EFI_UNSUPPORTED; +} + +/** EFI loaded image driver */ +static struct efi_driver efi_image_driver = + EFI_DRIVER_INIT ( NULL, efi_image_supported, efi_image_start, + efi_image_stop ); + /** * Shut down in preparation for booting an OS. * @@ -83,8 +151,10 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_BOOT_SERVICES *bs; struct efi_protocol *prot; struct efi_config_table *tab; - EFI_STATUS efirc; void *loaded_image; + void *loaded_image_path; + EFI_STATUS efirc; + int rc; /* Store image handle and system table pointer for future use */ efi_image_handle = image_handle; @@ -105,29 +175,18 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, return EFI_NOT_AVAILABLE_YET; } DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab ); - bs = systab->BootServices; - efirc = bs->OpenProtocol ( image_handle, - &efi_loaded_image_protocol_guid, - &loaded_image, image_handle, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ); - if ( efirc ) { - DBGC ( systab, "Could not get loaded image protocol" ); - return efirc; - } - - efi_loaded_image = loaded_image; - DBG ( "Image base address = %p\n", efi_loaded_image->ImageBase ); /* Look up used protocols */ for_each_table_entry ( prot, EFI_PROTOCOLS ) { - if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL, + if ( ( efirc = bs->LocateProtocol ( &prot->guid, NULL, prot->protocol ) ) == 0 ) { DBGC ( systab, "EFI protocol %s is at %p\n", - uuid_ntoa ( &prot->u.uuid ), *(prot->protocol)); + efi_guid_ntoa ( &prot->guid ), + *(prot->protocol) ); } else { DBGC ( systab, "EFI does not provide protocol %s\n", - uuid_ntoa ( &prot->u.uuid ) ); + efi_guid_ntoa ( &prot->guid ) ); /* All protocols are required */ return efirc; } @@ -135,17 +194,46 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, /* Look up used configuration tables */ for_each_table_entry ( tab, EFI_CONFIG_TABLES ) { - if ( ( *(tab->table) = efi_find_table ( &tab->u.guid ) ) ) { + if ( ( *(tab->table) = efi_find_table ( &tab->guid ) ) ) { DBGC ( systab, "EFI configuration table %s is at %p\n", - uuid_ntoa ( &tab->u.uuid ), *(tab->table) ); + efi_guid_ntoa ( &tab->guid ), *(tab->table) ); } else { DBGC ( systab, "EFI does not provide configuration " - "table %s\n", uuid_ntoa ( &tab->u.uuid ) ); + "table %s\n", efi_guid_ntoa ( &tab->guid ) ); if ( tab->required ) return EFI_NOT_AVAILABLE_YET; } } + /* Get loaded image protocol */ + if ( ( efirc = bs->OpenProtocol ( image_handle, + &efi_loaded_image_protocol_guid, + &loaded_image, image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( systab, "EFI could not get loaded image protocol: %s", + strerror ( rc ) ); + return efirc; + } + efi_loaded_image = loaded_image; + DBGC ( systab, "EFI image base address %p\n", + efi_loaded_image->ImageBase ); + + /* Get loaded image device path protocol */ + if ( ( efirc = bs->OpenProtocol ( image_handle, + &efi_loaded_image_device_path_protocol_guid, + &loaded_image_path, image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( systab, "EFI could not get loaded image device path " + "protocol: %s", strerror ( rc ) ); + return efirc; + } + efi_loaded_image_path = loaded_image_path; + DBGC ( systab, "EFI image device path " ); + DBGC_EFI_DEVPATH ( systab, efi_loaded_image_path ); + DBGC ( systab, "\n" ); + /* EFI is perfectly capable of gracefully shutting down any * loaded devices if it decides to fall back to a legacy boot. * For no particularly comprehensible reason, it doesn't @@ -154,10 +242,49 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, efi_shutdown_hook, NULL, &efi_shutdown_event ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( systab, "EFI could not create ExitBootServices event: " - "%s\n", efi_strerror ( efirc ) ); + "%s\n", strerror ( rc ) ); return efirc; } + /* Install an EFI driver on the image handle, to allow the + * driver to be subsequently unloaded. + */ + efi_image_driver.driver.DriverBindingHandle = image_handle; + if ( ( rc = efi_driver_install ( &efi_image_driver ) ) != 0 ) { + DBGC ( systab, "EFI could not install loaded image driver: " + "%s\n", strerror ( rc ) ); + return EFIRC ( rc ); + } + + /* Install image unload method */ + efi_loaded_image->Unload = efi_unload; + + return 0; +} + +/** + * Shut down EFI environment + * + * @v image_handle Image handle + */ +static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_SYSTEM_TABLE *systab = efi_systab; + + DBGC ( systab, "EFI image unloading\n" ); + + /* Shut down */ + shutdown_exit(); + + /* Uninstall exit boot services event */ + bs->CloseEvent ( efi_shutdown_event ); + + /* Uninstall loaded image driver */ + efi_driver_uninstall ( &efi_image_driver ); + + DBGC ( systab, "EFI image unloaded\n" ); + return 0; } diff --git a/roms/ipxe/src/interface/efi/efi_io.c b/roms/ipxe/src/interface/efi/efi_io.c deleted file mode 100644 index a620d6e43..000000000 --- a/roms/ipxe/src/interface/efi/efi_io.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <assert.h> -#include <ipxe/io.h> -#include <ipxe/efi/efi.h> -#include <ipxe/efi/Protocol/CpuIo.h> -#include <ipxe/efi/efi_io.h> - -/** @file - * - * iPXE I/O API for EFI - * - */ - -/** CPU I/O protocol */ -static EFI_CPU_IO_PROTOCOL *cpu_io; -EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io ); - -/** Maximum address that can be used for port I/O */ -#define MAX_PORT_ADDRESS 0xffff - -/** - * Determine whether or not address is a port I/O address - * - * @v io_addr I/O address - * @v is_port I/O address is a port I/O address - */ -#define IS_PORT_ADDRESS(io_addr) \ - ( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS ) - -/** - * Determine EFI CPU I/O width code - * - * @v size Size of value - * @ret width EFI width code - * - * Someone at Intel clearly gets paid by the number of lines of code - * they write. No-one should ever be able to make I/O this - * convoluted. The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite - * idiocy. - */ -static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) { - switch ( size ) { - case 1 : return EfiCpuIoWidthFifoUint8; - case 2 : return EfiCpuIoWidthFifoUint16; - case 4 : return EfiCpuIoWidthFifoUint32; - case 8 : return EfiCpuIoWidthFifoUint64; - default : - assert ( 0 ); - /* I wonder what this will actually do... */ - return EfiCpuIoWidthMaximum; - } -} - -/** - * Read from device - * - * @v io_addr I/O address - * @v size Size of value - * @ret data Value read - */ -unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) { - EFI_CPU_IO_PROTOCOL_IO_MEM read; - unsigned long long data = 0; - EFI_STATUS efirc; - - read = ( IS_PORT_ADDRESS ( io_addr ) ? - cpu_io->Io.Read : cpu_io->Mem.Read ); - - if ( ( efirc = read ( cpu_io, efi_width ( size ), - ( intptr_t ) io_addr, 1, - ( void * ) &data ) ) != 0 ) { - DBG ( "EFI I/O read at %p failed: %s\n", - io_addr, efi_strerror ( efirc ) ); - return -1ULL; - } - - return data; -} - -/** - * Write to device - * - * @v data Value to write - * @v io_addr I/O address - * @v size Size of value - */ -void efi_iowrite ( unsigned long long data, volatile void *io_addr, - size_t size ) { - EFI_CPU_IO_PROTOCOL_IO_MEM write; - EFI_STATUS efirc; - - write = ( IS_PORT_ADDRESS ( io_addr ) ? - cpu_io->Io.Write : cpu_io->Mem.Write ); - - if ( ( efirc = write ( cpu_io, efi_width ( size ), - ( intptr_t ) io_addr, 1, - ( void * ) &data ) ) != 0 ) { - DBG ( "EFI I/O write at %p failed: %s\n", - io_addr, efi_strerror ( efirc ) ); - } -} - -/** - * String read from device - * - * @v io_addr I/O address - * @v data Data buffer - * @v size Size of values - * @v count Number of values to read - */ -void efi_ioreads ( volatile void *io_addr, void *data, - size_t size, unsigned int count ) { - EFI_CPU_IO_PROTOCOL_IO_MEM read; - EFI_STATUS efirc; - - read = ( IS_PORT_ADDRESS ( io_addr ) ? - cpu_io->Io.Read : cpu_io->Mem.Read ); - - if ( ( efirc = read ( cpu_io, efi_width ( size ), - ( intptr_t ) io_addr, count, - ( void * ) data ) ) != 0 ) { - DBG ( "EFI I/O string read at %p failed: %s\n", - io_addr, efi_strerror ( efirc ) ); - } -} - -/** - * String write to device - * - * @v io_addr I/O address - * @v data Data buffer - * @v size Size of values - * @v count Number of values to write - */ -void efi_iowrites ( volatile void *io_addr, const void *data, - size_t size, unsigned int count ) { - EFI_CPU_IO_PROTOCOL_IO_MEM write; - EFI_STATUS efirc; - - write = ( IS_PORT_ADDRESS ( io_addr ) ? - cpu_io->Io.Write : cpu_io->Mem.Write ); - - if ( ( efirc = write ( cpu_io, efi_width ( size ), - ( intptr_t ) io_addr, count, - ( void * ) data ) ) != 0 ) { - DBG ( "EFI I/O write at %p failed: %s\n", - io_addr, efi_strerror ( efirc ) ); - } -} - -/** - * Wait for I/O-mapped operation to complete - * - */ -static void efi_iodelay ( void ) { - /* Write to non-existent port. Probably x86-only. */ - outb ( 0, 0x80 ); -} - -/** - * Get memory map - * - * Can't be done on EFI so return an empty map - * - * @v memmap Memory map to fill in - */ -static void efi_get_memmap ( struct memory_map *memmap ) { - memmap->count = 0; -} - -PROVIDE_IOAPI_INLINE ( efi, phys_to_bus ); -PROVIDE_IOAPI_INLINE ( efi, bus_to_phys ); -PROVIDE_IOAPI_INLINE ( efi, ioremap ); -PROVIDE_IOAPI_INLINE ( efi, iounmap ); -PROVIDE_IOAPI_INLINE ( efi, io_to_bus ); -PROVIDE_IOAPI_INLINE ( efi, readb ); -PROVIDE_IOAPI_INLINE ( efi, readw ); -PROVIDE_IOAPI_INLINE ( efi, readl ); -PROVIDE_IOAPI_INLINE ( efi, readq ); -PROVIDE_IOAPI_INLINE ( efi, writeb ); -PROVIDE_IOAPI_INLINE ( efi, writew ); -PROVIDE_IOAPI_INLINE ( efi, writel ); -PROVIDE_IOAPI_INLINE ( efi, writeq ); -PROVIDE_IOAPI_INLINE ( efi, inb ); -PROVIDE_IOAPI_INLINE ( efi, inw ); -PROVIDE_IOAPI_INLINE ( efi, inl ); -PROVIDE_IOAPI_INLINE ( efi, outb ); -PROVIDE_IOAPI_INLINE ( efi, outw ); -PROVIDE_IOAPI_INLINE ( efi, outl ); -PROVIDE_IOAPI_INLINE ( efi, insb ); -PROVIDE_IOAPI_INLINE ( efi, insw ); -PROVIDE_IOAPI_INLINE ( efi, insl ); -PROVIDE_IOAPI_INLINE ( efi, outsb ); -PROVIDE_IOAPI_INLINE ( efi, outsw ); -PROVIDE_IOAPI_INLINE ( efi, outsl ); -PROVIDE_IOAPI ( efi, iodelay, efi_iodelay ); -PROVIDE_IOAPI_INLINE ( efi, mb ); -PROVIDE_IOAPI ( efi, get_memmap, efi_get_memmap ); diff --git a/roms/ipxe/src/interface/efi/efi_pci.c b/roms/ipxe/src/interface/efi/efi_pci.c index 0288cf326..dc7304a35 100644 --- a/roms/ipxe/src/interface/efi/efi_pci.c +++ b/roms/ipxe/src/interface/efi/efi_pci.c @@ -57,13 +57,15 @@ static unsigned long efipci_address ( struct pci_device *pci, int efipci_read ( struct pci_device *pci, unsigned long location, void *value ) { EFI_STATUS efirc; + int rc; if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ), efipci_address ( pci, location ), 1, value ) ) != 0 ) { + rc = -EEFI ( efirc ); DBG ( "EFIPCI config read from " PCI_FMT " offset %02lx " "failed: %s\n", PCI_ARGS ( pci ), - EFIPCI_OFFSET ( location ), efi_strerror ( efirc ) ); + EFIPCI_OFFSET ( location ), strerror ( rc ) ); return -EIO; } @@ -73,13 +75,15 @@ int efipci_read ( struct pci_device *pci, unsigned long location, int efipci_write ( struct pci_device *pci, unsigned long location, unsigned long value ) { EFI_STATUS efirc; + int rc; if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ), efipci_address ( pci, location ), 1, &value ) ) != 0 ) { + rc = -EEFI ( efirc ); DBG ( "EFIPCI config write to " PCI_FMT " offset %02lx " "failed: %s\n", PCI_ARGS ( pci ), - EFIPCI_OFFSET ( location ), efi_strerror ( efirc ) ); + EFIPCI_OFFSET ( location ), strerror ( rc ) ); return -EIO; } @@ -149,6 +153,7 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, efidrv->driver.DriverBindingHandle, device, EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ + rc = -EEFI ( efirc ); DBGCP ( efipci, "EFIPCI device %p is not a PCI device\n", device ); goto err_open_protocol; @@ -160,8 +165,9 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, &pci_segment, &pci_bus, &pci_dev, &pci_fn ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( efipci, "EFIPCI device %p could not get PCI " - "location: %s\n", device, efi_strerror ( efirc ) ); + "location: %s\n", device, strerror ( rc ) ); goto err_get_location; } DBGC2 ( efipci, "EFIPCI device %p is PCI %04lx:%02lx:%02lx.%lx\n", @@ -185,6 +191,7 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, efidrv->driver.DriverBindingHandle, device, EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){ + rc = -EEFI ( efirc ); DBGC ( efipci, "EFIPCI " PCI_FMT " has no device path\n", PCI_ARGS ( &efipci->pci ) ); goto err_no_device_path; @@ -213,9 +220,9 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv, * Enable EFI PCI device * * @v efipci EFI PCI device - * @ret efirc EFI status code + * @ret rc Return status code */ -EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ) { +int efipci_enable ( struct efi_pci_device *efipci ) { EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io; /* Try to enable I/O cycles, memory cycles, and bus mastering. @@ -273,8 +280,7 @@ struct efi_pci_device * efipci_find ( struct device *dev ) { * @v device EFI child device * @ret efirc EFI status code */ -EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci, - EFI_HANDLE device ) { +int efipci_child_add ( struct efi_pci_device *efipci, EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_driver *efidrv = efipci->efidrv; union { @@ -282,6 +288,7 @@ EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci, void *interface; } pci_io; EFI_STATUS efirc; + int rc; /* Re-open the PCI_IO_PROTOCOL */ if ( ( efirc = bs->OpenProtocol ( efipci->device, @@ -291,9 +298,10 @@ EFI_STATUS efipci_child_add ( struct efi_pci_device *efipci, device, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n", - PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) ); - return efirc; + PCI_ARGS ( &efipci->pci ), strerror ( rc ) ); + return rc; } return 0; @@ -355,7 +363,6 @@ efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, struct efi_driver *efidrv = container_of ( driver, struct efi_driver, driver ); struct efi_pci_device *efipci; - EFI_STATUS efirc; int rc; DBGCP ( efidrv, "EFIPCI DRIVER_SUPPORTED %p (%p)\n", device, child ); @@ -364,7 +371,7 @@ efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, efipci = efipci_create ( efidrv, device ); if ( ! efipci ) { /* Non-PCI devices are simply unsupported */ - efirc = EFI_UNSUPPORTED; + rc = -ENOTSUP; goto err_not_pci; } @@ -372,7 +379,6 @@ efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { DBGCP ( efipci, "EFIPCI " PCI_FMT " has no driver\n", PCI_ARGS ( &efipci->pci ) ); - efirc = EFI_UNSUPPORTED; goto err_no_driver; } @@ -387,7 +393,7 @@ efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, err_no_driver: efipci_destroy ( efidrv, efipci ); err_not_pci: - return efirc; + return EFIRC ( rc ); } /** @@ -404,7 +410,6 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, struct efi_driver *efidrv = container_of ( driver, struct efi_driver, driver ); struct efi_pci_device *efipci; - EFI_STATUS efirc; int rc; DBGC ( efidrv, "EFIPCI DRIVER_START %p (%p)\n", device, child ); @@ -412,7 +417,7 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, /* Create corresponding PCI device */ efipci = efipci_create ( efidrv, device ); if ( ! efipci ) { - efirc = EFI_OUT_OF_RESOURCES; + rc = -ENOMEM; goto err_create; } @@ -420,12 +425,11 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { DBGC ( efipci, "EFIPCI " PCI_FMT " has no driver\n", PCI_ARGS ( &efipci->pci ) ); - efirc = RC_TO_EFIRC ( rc ); goto err_find_driver; } /* Enable PCI device */ - if ( ( efirc = efipci_enable ( efipci ) ) != 0 ) + if ( ( rc = efipci_enable ( efipci ) ) != 0 ) goto err_enable; /* Probe driver */ @@ -433,7 +437,6 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, DBGC ( efipci, "EFIPCI " PCI_FMT " could not probe driver " "\"%s\": %s\n", PCI_ARGS ( &efipci->pci ), efipci->pci.id->name, strerror ( rc ) ); - efirc = RC_TO_EFIRC ( rc ); goto err_probe; } @@ -445,7 +448,7 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device, err_find_driver: efipci_destroy ( efidrv, efipci ); err_create: - return efirc; + return EFIRC ( rc ); } /** @@ -494,12 +497,12 @@ static struct efi_driver efipci_driver = */ static void efipci_driver_startup ( void ) { struct efi_driver *efidrv = &efipci_driver; - EFI_STATUS efirc; + int rc; /* Install driver */ - if ( ( efirc = efi_driver_install ( efidrv ) ) != 0 ) { + if ( ( rc = efi_driver_install ( efidrv ) ) != 0 ) { DBGC ( efidrv, "EFIPCI could not install driver: %s\n", - efi_strerror ( efirc ) ); + strerror ( rc ) ); return; } @@ -516,6 +519,9 @@ static void efipci_driver_shutdown ( int booting __unused ) { struct efi_pci_device *efipci; struct efi_pci_device *tmp; + /* Uninstall driver */ + efi_driver_uninstall ( efidrv ); + /* Shut down any remaining devices */ list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) { DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; " diff --git a/roms/ipxe/src/interface/efi/efi_reboot.c b/roms/ipxe/src/interface/efi/efi_reboot.c new file mode 100644 index 000000000..96638c48e --- /dev/null +++ b/roms/ipxe/src/interface/efi/efi_reboot.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * EFI reboot mechanism + * + */ + +#include <errno.h> +#include <ipxe/efi/efi.h> +#include <ipxe/reboot.h> + +/** + * Reboot system + * + * @v warm Perform a warm reboot + */ +static void efi_reboot ( int warm ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + + /* Use runtime services to reset system */ + rs->ResetSystem ( ( warm ? EfiResetWarm : EfiResetCold ), 0, 0, NULL ); +} + +/** + * Power off system + * + * @ret rc Return status code + */ +static int efi_poweroff ( void ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + + /* Use runtime services to power off system */ + rs->ResetSystem ( EfiResetShutdown, 0, 0, NULL ); + + /* Should never happen */ + return -ECANCELED; +} + +PROVIDE_REBOOT ( efi, reboot, efi_reboot ); +PROVIDE_REBOOT ( efi, poweroff, efi_poweroff ); diff --git a/roms/ipxe/src/interface/efi/efi_smbios.c b/roms/ipxe/src/interface/efi/efi_smbios.c index 506b04e77..304f95a56 100644 --- a/roms/ipxe/src/interface/efi/efi_smbios.c +++ b/roms/ipxe/src/interface/efi/efi_smbios.c @@ -55,6 +55,8 @@ static int efi_find_smbios ( struct smbios *smbios ) { smbios->address = phys_to_user ( smbios_entry->smbios_address ); smbios->len = smbios_entry->smbios_len; smbios->count = smbios_entry->smbios_count; + smbios->version = + SMBIOS_VERSION ( smbios_entry->major, smbios_entry->minor ); DBG ( "Found SMBIOS v%d.%d entry point at %p (%x+%zx)\n", smbios_entry->major, smbios_entry->minor, smbios_entry, smbios_entry->smbios_address, smbios->len ); diff --git a/roms/ipxe/src/interface/efi/efi_snp.c b/roms/ipxe/src/interface/efi/efi_snp.c index 200275966..9c541552b 100644 --- a/roms/ipxe/src/interface/efi/efi_snp.c +++ b/roms/ipxe/src/interface/efi/efi_snp.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/efi/efi_strings.h> #include <ipxe/efi/efi_snp.h> #include <config/general.h> +#include <usr/autoboot.h> /** EFI simple network protocol GUID */ static EFI_GUID efi_simple_network_protocol_guid @@ -57,14 +58,47 @@ static EFI_GUID efi_nii31_protocol_guid = { { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } }; -/** EFI component name protocol */ +/** EFI component name protocol GUID */ static EFI_GUID efi_component_name2_protocol_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID; +/** EFI load file protocol GUID */ +static EFI_GUID efi_load_file_protocol_guid + = EFI_LOAD_FILE_PROTOCOL_GUID; + /** List of SNP devices */ static LIST_HEAD ( efi_snp_devices ); /** + * Set EFI SNP mode state + * + * @v snp SNP interface + */ +static void efi_snp_set_state ( struct efi_snp_device *snpdev ) { + struct net_device *netdev = snpdev->netdev; + EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode; + + /* Calculate state */ + if ( ! snpdev->started ) { + /* Start() method not called; report as Stopped */ + mode->State = EfiSimpleNetworkStopped; + } else if ( ! netdev_is_open ( netdev ) ) { + /* Network device not opened; report as Started */ + mode->State = EfiSimpleNetworkStarted; + } else if ( ! netdev_rx_frozen ( netdev ) ) { + /* Network device opened but claimed for use by iPXE; report + * as Started to inhibit receive polling. + */ + mode->State = EfiSimpleNetworkStarted; + } else { + /* Network device opened and available for use via SNP; report + * as Initialized. + */ + mode->State = EfiSimpleNetworkInitialized; + } +} + +/** * Set EFI SNP mode based on iPXE net device parameters * * @v snp SNP interface @@ -129,7 +163,12 @@ efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev ); - snpdev->mode.State = EfiSimpleNetworkStarted; + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + + snpdev->started = 1; + efi_snp_set_state ( snpdev ); return 0; } @@ -146,7 +185,12 @@ efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev ); - snpdev->mode.State = EfiSimpleNetworkStopped; + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + + snpdev->started = 0; + efi_snp_set_state ( snpdev ); return 0; } @@ -169,13 +213,17 @@ efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, snpdev, ( ( unsigned long ) extra_rx_bufsize ), ( ( unsigned long ) extra_tx_bufsize ) ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n", snpdev, snpdev->netdev->name, strerror ( rc ) ); - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } + efi_snp_set_state ( snpdev ); - snpdev->mode.State = EfiSimpleNetworkInitialized; return 0; } @@ -195,16 +243,20 @@ efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n", snpdev, ( ext_verify ? "with" : "without" ) ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + netdev_close ( snpdev->netdev ); - snpdev->mode.State = EfiSimpleNetworkStarted; + efi_snp_set_state ( snpdev ); if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n", snpdev, snpdev->netdev->name, strerror ( rc ) ); - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } + efi_snp_set_state ( snpdev ); - snpdev->mode.State = EfiSimpleNetworkInitialized; return 0; } @@ -221,8 +273,13 @@ efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + netdev_close ( snpdev->netdev ); - snpdev->mode.State = EfiSimpleNetworkStarted; + efi_snp_set_state ( snpdev ); + return 0; } @@ -253,6 +310,10 @@ efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable, snpdev->netdev->ll_protocol->ll_addr_len ); } + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Lie through our teeth, otherwise MNP refuses to accept us */ return 0; } @@ -275,6 +336,10 @@ efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev, ( reset ? "reset" : ll_protocol->ntoa ( new ) ) ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Set the MAC address */ if ( reset ) new = &snpdev->mode.PermanentAddress; @@ -308,6 +373,10 @@ efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev, ( reset ? " reset" : "" ) ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Gather statistics */ memset ( &stats_buf, 0, sizeof ( stats_buf ) ); stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good; @@ -356,12 +425,16 @@ efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6, inet_ntoa ( *( ( struct in_addr * ) ip ) ) ); DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Try to hash the address */ if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ), ip, mac ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n", snpdev, ip_str, strerror ( rc ) ); - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } return 0; @@ -389,6 +462,10 @@ efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read, if ( ! read ) DBGC2_HDA ( snpdev, offset, data, len ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + return EFI_UNSUPPORTED; } @@ -408,6 +485,10 @@ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Poll the network device */ efi_snp_poll ( snpdev ); @@ -485,7 +566,6 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, struct io_buffer *iobuf; size_t payload_len; int rc; - EFI_STATUS efirc; DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, ( ( unsigned long ) len ) ); @@ -504,31 +584,35 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } DBGC2 ( snpdev, "\n" ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Sanity checks */ if ( ll_header_len ) { if ( ll_header_len != ll_protocol->ll_header_len ) { DBGC ( snpdev, "SNPDEV %p TX invalid header length " "%ld\n", snpdev, ( ( unsigned long ) ll_header_len ) ); - efirc = EFI_INVALID_PARAMETER; + rc = -EINVAL; goto err_sanity; } if ( len < ll_header_len ) { DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n", snpdev, ( ( unsigned long ) len ) ); - efirc = EFI_BUFFER_TOO_SMALL; + rc = -EINVAL; goto err_sanity; } if ( ! ll_dest ) { DBGC ( snpdev, "SNPDEV %p TX missing destination " "address\n", snpdev ); - efirc = EFI_INVALID_PARAMETER; + rc = -EINVAL; goto err_sanity; } if ( ! net_proto ) { DBGC ( snpdev, "SNPDEV %p TX missing network " "protocol\n", snpdev ); - efirc = EFI_INVALID_PARAMETER; + rc = -EINVAL; goto err_sanity; } if ( ! ll_src ) @@ -542,7 +626,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, if ( ! iobuf ) { DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte " "buffer\n", snpdev, ( ( unsigned long ) len ) ); - efirc = EFI_DEVICE_ERROR; + rc = -ENOMEM; goto err_alloc_iob; } iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN - @@ -557,7 +641,6 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, htons ( *net_proto ) )) != 0 ){ DBGC ( snpdev, "SNPDEV %p TX could not construct " "header: %s\n", snpdev, strerror ( rc ) ); - efirc = RC_TO_EFIRC ( rc ); goto err_ll_push; } } @@ -566,7 +649,6 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){ DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n", snpdev, strerror ( rc ) ); - efirc = RC_TO_EFIRC ( rc ); goto err_tx; } @@ -581,7 +663,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, free_iob ( iobuf ); err_alloc_iob: err_sanity: - return efirc; + return EFIRC ( rc ); } /** @@ -610,11 +692,14 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, uint16_t iob_net_proto; unsigned int iob_flags; int rc; - EFI_STATUS efirc; DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, ( ( unsigned long ) *len ) ); + /* Fail if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return EFI_NOT_READY; + /* Poll the network device */ efi_snp_poll ( snpdev ); @@ -622,7 +707,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, iobuf = netdev_rx_dequeue ( snpdev->netdev ); if ( ! iobuf ) { DBGC2 ( snpdev, "\n" ); - efirc = EFI_NOT_READY; + rc = -EAGAIN; goto out_no_packet; } DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) ); @@ -637,7 +722,6 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, &iob_flags ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n", snpdev, strerror ( rc ) ); - efirc = RC_TO_EFIRC ( rc ); goto out_bad_ll_header; } @@ -651,12 +735,12 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, if ( net_proto ) *net_proto = ntohs ( iob_net_proto ); - efirc = 0; + rc = 0; out_bad_ll_header: free_iob ( iobuf ); -out_no_packet: - return efirc; + out_no_packet: + return EFIRC ( rc ); } /** @@ -676,6 +760,10 @@ static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event, if ( ! netdev_is_open ( snpdev->netdev ) ) return; + /* Do nothing if net device is currently claimed for use by iPXE */ + if ( ! netdev_rx_frozen ( snpdev->netdev ) ) + return; + /* Poll the network device */ efi_snp_poll ( snpdev ); @@ -756,6 +844,55 @@ efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2, /****************************************************************************** * + * Load file protocol + * + ****************************************************************************** + */ + +/** + * Load file + * + * @v loadfile Load file protocol + * @v path File path + * @v booting Loading as part of a boot attempt + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file, + EFI_DEVICE_PATH_PROTOCOL *path __unused, + BOOLEAN booting, UINTN *len __unused, + VOID *data __unused ) { + struct efi_snp_device *snpdev = + container_of ( load_file, struct efi_snp_device, load_file ); + struct net_device *netdev = snpdev->netdev; + + /* Fail unless this is a boot attempt */ + if ( ! booting ) { + DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n", + snpdev ); + return EFI_UNSUPPORTED; + } + + /* Claim network devices for use by iPXE */ + efi_snp_claim(); + + /* Boot from network device */ + ipxe ( netdev ); + + /* Release network devices for use via SNP */ + efi_snp_release(); + + /* Assume boot process was aborted */ + return EFI_ABORTED; +} + +/** Load file protocol */ +static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = { + .LoadFile = efi_snp_load_file, +}; + +/****************************************************************************** + * * iPXE network driver * ****************************************************************************** @@ -831,9 +968,9 @@ static int efi_snp_probe ( struct net_device *netdev ) { if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, efi_snp_wait_for_packet, snpdev, &snpdev->snp.WaitForPacket ) ) != 0 ){ + rc = -EEFI ( efirc ); DBGC ( snpdev, "SNPDEV %p could not create event: %s\n", - snpdev, efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + snpdev, strerror ( rc ) ); goto err_create_event; } @@ -861,6 +998,10 @@ static int efi_snp_probe ( struct net_device *netdev ) { snpdev->name2.GetControllerName = efi_snp_get_controller_name; snpdev->name2.SupportedLanguages = "en"; + /* Populate the load file protocol structure */ + memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol, + sizeof ( snpdev->load_file ) ); + /* Populate the device name */ efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) / sizeof ( snpdev->name[0] ) ), @@ -890,19 +1031,19 @@ static int efi_snp_probe ( struct net_device *netdev ) { &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, + &efi_load_file_protocol_guid, &snpdev->load_file, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snpdev, "SNPDEV %p could not install protocols: " - "%s\n", snpdev, efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + "%s\n", snpdev, strerror ( rc ) ); goto err_install_protocol_interface; } /* Add as child of PCI device */ - if ( ( efirc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) { + if ( ( rc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ), - efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + strerror ( rc ) ); goto err_efipci_child_add; } @@ -931,6 +1072,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, + &efi_load_file_protocol_guid, &snpdev->load_file, NULL ); err_install_protocol_interface: bs->CloseEvent ( snpdev->snp.WaitForPacket ); @@ -963,6 +1105,9 @@ static void efi_snp_notify ( struct net_device *netdev ) { ( netdev_link_ok ( netdev ) ? TRUE : FALSE ); DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev, ( snpdev->mode.MediaPresent ? "up" : "down" ) ); + + /* Update mode state */ + efi_snp_set_state ( snpdev ); } /** @@ -992,6 +1137,7 @@ static void efi_snp_remove ( struct net_device *netdev ) { &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, + &efi_load_file_protocol_guid, &snpdev->load_file, NULL ); bs->CloseEvent ( snpdev->snp.WaitForPacket ); netdev_put ( snpdev->netdev ); @@ -1005,3 +1151,40 @@ struct net_driver efi_snp_driver __net_driver = { .notify = efi_snp_notify, .remove = efi_snp_remove, }; + +/** + * Get most recently opened SNP device + * + * @ret snpdev Most recently opened SNP device, or NULL + */ +struct efi_snp_device * last_opened_snpdev ( void ) { + struct net_device *netdev; + + netdev = last_opened_netdev(); + if ( ! netdev ) + return NULL; + + return efi_snp_demux ( netdev ); +} + +/** + * Claim network devices for use by iPXE + * + */ +void efi_snp_claim ( void ) { + struct net_device *netdev; + + for_each_netdev ( netdev ) + netdev_rx_unfreeze ( netdev ); +} + +/** + * Release network devices for use via SNP + * + */ +void efi_snp_release ( void ) { + struct net_device *netdev; + + for_each_netdev ( netdev ) + netdev_rx_freeze ( netdev ); +} diff --git a/roms/ipxe/src/interface/efi/efi_snp_hii.c b/roms/ipxe/src/interface/efi/efi_snp_hii.c index 3a1193a38..c272527c0 100644 --- a/roms/ipxe/src/interface/efi/efi_snp_hii.c +++ b/roms/ipxe/src/interface/efi/efi_snp_hii.c @@ -126,6 +126,7 @@ static void efi_snp_hii_questions ( struct efi_snp_device *snpdev, struct efi_ifr_builder *ifr, unsigned int varstore_id ) { struct setting *setting; + struct setting *previous = NULL; unsigned int name_id; unsigned int prompt_id; unsigned int help_id; @@ -135,6 +136,9 @@ static void efi_snp_hii_questions ( struct efi_snp_device *snpdev, for_each_table_entry ( setting, SETTINGS ) { if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) ) continue; + if ( previous && ( setting_cmp ( setting, previous ) == 0 ) ) + continue; + previous = setting; name_id = efi_ifr_string ( ifr, "%s", setting->name ); prompt_id = efi_ifr_string ( ifr, "%s", setting->description ); help_id = efi_ifr_string ( ifr, "http://ipxe.org/cfg/%s", @@ -276,7 +280,9 @@ static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev, const char *key, const char *value, wchar_t **results, int *have_setting ) { struct settings *settings = efi_snp_hii_settings ( snpdev ); + struct settings *origin; struct setting *setting; + struct setting fetched; int len; char *buf; char *encoded; @@ -311,7 +317,8 @@ static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev, if ( setting_exists ( settings, setting ) ) { /* Calculate formatted length */ - len = fetchf_setting ( settings, setting, NULL, 0 ); + len = fetchf_setting ( settings, setting, &origin, &fetched, + NULL, 0 ); if ( len < 0 ) { rc = len; DBGC ( snpdev, "SNPDEV %p could not fetch %s: %s\n", @@ -328,7 +335,8 @@ static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev, encoded = ( buf + len + 1 /* NUL */ ); /* Format value */ - fetchf_setting ( settings, setting, buf, ( len + 1 /* NUL */ )); + fetchf_setting ( origin, &fetched, NULL, NULL, buf, + ( len + 1 /* NUL */ ) ); for ( i = 0 ; i < len ; i++ ) { sprintf ( ( encoded + ( 4 * i ) ), "%04x", *( ( uint8_t * ) buf + i ) ); @@ -544,7 +552,7 @@ efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress, results, &have_setting, efi_snp_hii_fetch ) ) != 0 ) { - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } } @@ -558,7 +566,7 @@ efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, if ( ( rc = efi_snp_hii_fetch ( snpdev, setting->name, NULL, results, NULL ) ) != 0 ) { - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } } } @@ -592,7 +600,7 @@ efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress, NULL, NULL, efi_snp_hii_store ) ) != 0 ) { - return RC_TO_EFIRC ( rc ); + return EFIRC ( rc ); } } @@ -657,9 +665,9 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list, snpdev->handle, &snpdev->hii_handle ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n", - snpdev, efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + snpdev, strerror ( rc ) ); goto err_new_package_list; } @@ -668,9 +676,9 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { &snpdev->handle, &efi_hii_config_access_protocol_guid, &snpdev->hii, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); DBGC ( snpdev, "SNPDEV %p could not install HII protocol: %s\n", - snpdev, efi_strerror ( efirc ) ); - rc = EFIRC_TO_RC ( efirc ); + snpdev, strerror ( rc ) ); goto err_install_protocol; } diff --git a/roms/ipxe/src/interface/efi/efi_timer.c b/roms/ipxe/src/interface/efi/efi_timer.c index b110cae29..7a1ff7869 100644 --- a/roms/ipxe/src/interface/efi/efi_timer.c +++ b/roms/ipxe/src/interface/efi/efi_timer.c @@ -19,6 +19,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include <string.h> +#include <errno.h> #include <limits.h> #include <assert.h> #include <unistd.h> @@ -54,10 +56,12 @@ EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch ); static void efi_udelay ( unsigned long usecs ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_STATUS efirc; + int rc; if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) { + rc = -EEFI ( efirc ); DBG ( "EFI could not delay for %ldus: %s\n", - usecs, efi_strerror ( efirc ) ); + usecs, strerror ( rc ) ); /* Probably screwed */ } } @@ -70,12 +74,13 @@ static void efi_udelay ( unsigned long usecs ) { static unsigned long efi_currticks ( void ) { UINT64 time; EFI_STATUS efirc; + int rc; /* Read CPU timer 0 (TSC) */ if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time, NULL ) ) != 0 ) { - DBG ( "EFI could not read CPU timer: %s\n", - efi_strerror ( efirc ) ); + rc = -EEFI ( efirc ); + DBG ( "EFI could not read CPU timer: %s\n", strerror ( rc ) ); /* Probably screwed */ return -1UL; } diff --git a/roms/ipxe/src/interface/efi/efi_umalloc.c b/roms/ipxe/src/interface/efi/efi_umalloc.c index b49949327..356efaa6f 100644 --- a/roms/ipxe/src/interface/efi/efi_umalloc.c +++ b/roms/ipxe/src/interface/efi/efi_umalloc.c @@ -19,6 +19,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include <string.h> +#include <errno.h> #include <assert.h> #include <ipxe/umalloc.h> #include <ipxe/efi/efi.h> @@ -49,6 +51,7 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { userptr_t new_ptr = UNOWHERE; size_t old_size; EFI_STATUS efirc; + int rc; /* Allocate new memory if necessary. If allocation fails, * return without touching the old block. @@ -59,8 +62,9 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { EfiBootServicesData, new_pages, &phys_addr ) ) != 0 ) { + rc = -EEFI ( efirc ); DBG ( "EFI could not allocate %d pages: %s\n", - new_pages, efi_strerror ( efirc ) ); + new_pages, strerror ( rc ) ); return UNULL; } assert ( phys_addr != 0 ); @@ -84,8 +88,9 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 ); phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE ); if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){ + rc = -EEFI ( efirc ); DBG ( "EFI could not free %d pages at %llx: %s\n", - old_pages, phys_addr, efi_strerror ( efirc ) ); + old_pages, phys_addr, strerror ( rc ) ); /* Not fatal; we have leaked memory but successfully * allocated (if asked to do so). */ diff --git a/roms/ipxe/src/interface/linux/linux_pci.c b/roms/ipxe/src/interface/linux/linux_pci.c new file mode 100644 index 000000000..cbd825c18 --- /dev/null +++ b/roms/ipxe/src/interface/linux/linux_pci.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <errno.h> +#include <byteswap.h> +#include <linux_api.h> +#include <ipxe/linux.h> +#include <ipxe/pci.h> + +/** @file + * + * iPXE PCI API for Linux + * + */ + +/** + * Open PCI configuration space + * + * @v pci PCI device + * @v flags Access mode flags + * @v where Address within configuration space + * @ret fd File handle, or negative error + */ +static int linux_pci_open ( struct pci_device *pci, int flags, + unsigned long where ) { + char filename[ 22 /* "/proc/bus/pci/xx/xx.x" + NUL */ ]; + int fd; + int rc; + + /* Construct filename */ + snprintf ( filename, sizeof ( filename ), "/proc/bus/pci/%02x/%02x.%x", + PCI_BUS ( pci->busdevfn ), PCI_SLOT ( pci->busdevfn ), + PCI_FUNC ( pci->busdevfn ) ); + + /* Open file */ + fd = linux_open ( filename, flags ); + if ( fd < 0 ) { + DBGC ( pci, "PCI could not open %s: %s\n", filename, + linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_open; + } + + /* Seek to location */ + if ( linux_lseek ( fd, where, SEEK_SET ) < 0 ) { + DBGC ( pci, "PCI could not seek to %s offset %#02lx: %s\n", + filename, where, linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_seek; + } + + return fd; + + err_seek: + linux_close ( fd ); + err_open: + return rc; +} + +/** + * Read from PCI configuration space + * + * @v pci PCI device + * @v where Address within configuration space + * @v value Data buffer + * @v len Length to read + * @ret rc Return status code + */ +int linux_pci_read ( struct pci_device *pci, unsigned long where, + unsigned long *value, size_t len ) { + uint32_t tmp = 0; + int fd; + int check_len; + int rc; + + /* Return "missing device" in case of error */ + *value = -1UL; + + /* Open configuration space */ + fd = linux_pci_open ( pci, O_RDONLY, where ); + if ( fd < 0 ) { + rc = fd; + goto err_open; + } + + /* Read value */ + check_len = linux_read ( fd, &tmp, len ); + if ( check_len < 0 ) { + DBGC ( pci, "PCI could not read from " PCI_FMT " %#02lx+%#zx: " + "%s\n", PCI_ARGS ( pci ), where, len, + linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_read; + } + if ( ( size_t ) check_len != len ) { + DBGC ( pci, "PCI read only %#x bytes from " PCI_FMT + " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ), + where, len ); + rc = -EIO; + goto err_read; + } + + /* Return value */ + *value = le32_to_cpu ( tmp ); + + /* Success */ + rc = 0; + + err_read: + linux_close ( fd ); + err_open: + return rc; +} + +/** + * Write to PCI configuration space + * + * @v pci PCI device + * @v where Address within configuration space + * @v value Value to write + * @v len Length of value + * @ret rc Return status code + */ +int linux_pci_write ( struct pci_device *pci, unsigned long where, + unsigned long value, size_t len ) { + uint32_t tmp; + int fd; + int check_len; + int rc; + + /* Open configuration space */ + fd = linux_pci_open ( pci, O_WRONLY, where ); + if ( fd < 0 ) { + rc = fd; + goto err_open; + } + + /* Prepare value for writing */ + tmp = cpu_to_le32 ( value ); + assert ( len <= sizeof ( tmp ) ); + + /* Write value */ + check_len = linux_write ( fd, &tmp, len ); + if ( check_len < 0 ) { + DBGC ( pci, "PCI could not write to " PCI_FMT " %#02lx+%#zx: " + "%s\n", PCI_ARGS ( pci ), where, len, + linux_strerror ( linux_errno ) ); + rc = -ELINUX ( linux_errno ); + goto err_write; + } + if ( ( size_t ) check_len != len ) { + DBGC ( pci, "PCI wrote only %#x bytes to " PCI_FMT + " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ), + where, len ); + rc = -EIO; + goto err_write; + } + + /* Success */ + rc = 0; + + err_write: + linux_close ( fd ); + err_open: + return rc; +} diff --git a/roms/ipxe/src/interface/linux/linux_smbios.c b/roms/ipxe/src/interface/linux/linux_smbios.c index f99120bf6..6e5174d23 100644 --- a/roms/ipxe/src/interface/linux/linux_smbios.c +++ b/roms/ipxe/src/interface/linux/linux_smbios.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Piotr JaroszyÅ„ski <p.jaroszynski@gmail.com> + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,25 +13,103 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ -FILE_LICENCE(GPL2_OR_LATER); +FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> +#include <linux_api.h> +#include <ipxe/linux.h> #include <ipxe/smbios.h> +/** SMBIOS filename */ +static const char smbios_filename[] = "/dev/mem"; + +/** SMBIOS entry point scan region start address */ +#define SMBIOS_ENTRY_START 0xf0000 + +/** SMBIOS entry point scan region length */ +#define SMBIOS_ENTRY_LEN 0x10000 + +/** SMBIOS mapping alignment */ +#define SMBIOS_ALIGN 0x1000 + /** * Find SMBIOS * - * Not implemented currently. - * * @v smbios SMBIOS entry point descriptor structure to fill in * @ret rc Return status code */ -static int linux_find_smbios(struct smbios *smbios __unused) -{ - return -ENODEV; +static int linux_find_smbios ( struct smbios *smbios ) { + struct smbios_entry entry; + void *entry_mem; + void *smbios_mem; + size_t smbios_offset; + size_t smbios_indent; + size_t smbios_len; + int fd; + int rc; + + /* Open SMBIOS file */ + fd = linux_open ( smbios_filename, O_RDONLY ); + if ( fd < 0 ) { + rc = -ELINUX ( linux_errno ); + DBGC ( smbios, "SMBIOS could not open %s: %s\n", + smbios_filename, linux_strerror ( linux_errno ) ); + goto err_open; + } + + /* Map the region potentially containing the SMBIOS entry point */ + entry_mem = linux_mmap ( NULL, SMBIOS_ENTRY_LEN, PROT_READ, MAP_SHARED, + fd, SMBIOS_ENTRY_START ); + if ( entry_mem == MAP_FAILED ) { + rc = -ELINUX ( linux_errno ); + DBGC ( smbios, "SMBIOS could not mmap %s (%#x+%#x): %s\n", + smbios_filename, SMBIOS_ENTRY_START, SMBIOS_ENTRY_LEN, + linux_strerror ( linux_errno ) ); + goto err_mmap_entry; + } + + /* Scan for the SMBIOS entry point */ + if ( ( rc = find_smbios_entry ( virt_to_user ( entry_mem ), + SMBIOS_ENTRY_LEN, &entry ) ) != 0 ) + goto err_find_entry; + + /* Map the region containing the SMBIOS structures */ + smbios_indent = ( entry.smbios_address & ( SMBIOS_ALIGN - 1 ) ); + smbios_offset = ( entry.smbios_address - smbios_indent ); + smbios_len = ( entry.smbios_len + smbios_indent ); + smbios_mem = linux_mmap ( NULL, smbios_len, PROT_READ, MAP_SHARED, + fd, smbios_offset ); + if ( smbios_mem == MAP_FAILED ) { + rc = -ELINUX ( linux_errno ); + DBGC ( smbios, "SMBIOS could not mmap %s (%#zx+%#zx): %s\n", + smbios_filename, smbios_offset, smbios_len, + linux_strerror ( linux_errno ) ); + goto err_mmap_smbios; + } + + /* Fill in entry point descriptor structure */ + smbios->address = virt_to_user ( smbios_mem + smbios_indent ); + smbios->len = entry.smbios_len; + smbios->count = entry.smbios_count; + smbios->version = SMBIOS_VERSION ( entry.major, entry.minor ); + + /* Unmap the entry point region (no longer required) */ + linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN ); + + return 0; + + linux_munmap ( smbios_mem, smbios_len ); + err_mmap_smbios: + err_find_entry: + linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN ); + err_mmap_entry: + linux_close ( fd ); + err_open: + return rc; } -PROVIDE_SMBIOS(linux, find_smbios, linux_find_smbios); +PROVIDE_SMBIOS ( linux, find_smbios, linux_find_smbios ); diff --git a/roms/ipxe/src/interface/linux/linux_time.c b/roms/ipxe/src/interface/linux/linux_time.c index 6d722aad0..e3cbafec6 100644 --- a/roms/ipxe/src/interface/linux/linux_time.c +++ b/roms/ipxe/src/interface/linux/linux_time.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #include <stdint.h> +#include <stddef.h> #include <errno.h> #include <linux_api.h> #include <ipxe/time.h> diff --git a/roms/ipxe/src/interface/linux/linux_timer.c b/roms/ipxe/src/interface/linux/linux_timer.c index 6b4643a65..7a994517b 100644 --- a/roms/ipxe/src/interface/linux/linux_timer.c +++ b/roms/ipxe/src/interface/linux/linux_timer.c @@ -18,6 +18,7 @@ FILE_LICENCE(GPL2_OR_LATER); +#include <stddef.h> #include <ipxe/timer.h> #include <linux_api.h> @@ -54,6 +55,12 @@ static unsigned long linux_ticks_per_sec(void) * linux doesn't provide an easy access to jiffies so implement it by measuring * the time since the first call to this function. * + * Since this function is used to seed the (non-cryptographic) random + * number generator, we round the start time down to the nearest whole + * second. This minimises the chances of generating identical RNG + * sequences (and hence identical TCP port numbers, etc) on + * consecutive invocations of iPXE. + * * @ret ticks Current time, in ticks */ static unsigned long linux_currticks(void) @@ -70,7 +77,7 @@ static unsigned long linux_currticks(void) linux_gettimeofday(&now, NULL); unsigned long ticks = (now.tv_sec - start.tv_sec) * linux_ticks_per_sec(); - ticks += (now.tv_usec - start.tv_usec) / (long)(1000000 / linux_ticks_per_sec()); + ticks += now.tv_usec / (long)(1000000 / linux_ticks_per_sec()); return ticks; } diff --git a/roms/ipxe/src/interface/smbios/smbios.c b/roms/ipxe/src/interface/smbios/smbios.c index 8ed24dd66..856943428 100644 --- a/roms/ipxe/src/interface/smbios/smbios.c +++ b/roms/ipxe/src/interface/smbios/smbios.c @@ -38,6 +38,54 @@ static struct smbios smbios = { }; /** + * Scan for SMBIOS entry point structure + * + * @v start Start address of region to scan + * @v len Length of region to scan + * @v entry SMBIOS entry point structure to fill in + * @ret rc Return status code + */ +int find_smbios_entry ( userptr_t start, size_t len, + struct smbios_entry *entry ) { + uint8_t buf[256]; /* 256 is maximum length possible */ + static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */ + size_t entry_len; + unsigned int i; + uint8_t sum; + + /* Try to find SMBIOS */ + for ( ; offset < len ; offset += 0x10 ) { + + /* Read start of header and verify signature */ + copy_from_user ( entry, start, offset, sizeof ( *entry ) ); + if ( entry->signature != SMBIOS_SIGNATURE ) + continue; + + /* Read whole header and verify checksum */ + entry_len = entry->len; + assert ( entry_len <= sizeof ( buf ) ); + copy_from_user ( buf, start, offset, entry_len ); + for ( i = 0, sum = 0 ; i < entry_len ; i++ ) { + sum += buf[i]; + } + if ( sum != 0 ) { + DBG ( "SMBIOS at %08lx has bad checksum %02x\n", + user_to_phys ( start, offset ), sum ); + continue; + } + + /* Fill result structure */ + DBG ( "Found SMBIOS v%d.%d entry point at %08lx\n", + entry->major, entry->minor, + user_to_phys ( start, offset ) ); + return 0; + } + + DBG ( "No SMBIOS found\n" ); + return -ENODEV; +} + +/** * Find SMBIOS strings terminator * * @v offset Offset to start of strings @@ -59,10 +107,11 @@ static size_t find_strings_terminator ( size_t offset ) { * Find specific structure type within SMBIOS * * @v type Structure type to search for + * @v instance Instance of this type of structure * @v structure SMBIOS structure descriptor to fill in * @ret rc Return status code */ -int find_smbios_structure ( unsigned int type, +int find_smbios_structure ( unsigned int type, unsigned int instance, struct smbios_structure *structure ) { unsigned int count = 0; size_t offset = 0; @@ -105,7 +154,8 @@ int find_smbios_structure ( unsigned int type, structure->header.len, structure->strings_len ); /* If this is the structure we want, return */ - if ( structure->header.type == type ) { + if ( ( structure->header.type == type ) && + ( instance-- == 0 ) ) { structure->offset = offset; return 0; } @@ -179,3 +229,20 @@ int read_smbios_string ( struct smbios_structure *structure, DBG ( "SMBIOS string index %d not found\n", index ); return -ENOENT; } + +/** + * Get SMBIOS version + * + * @ret version Version, or negative error + */ +int smbios_version ( void ) { + int rc; + + /* Find SMBIOS */ + if ( ( smbios.address == UNULL ) && + ( ( rc = find_smbios ( &smbios ) ) != 0 ) ) + return rc; + assert ( smbios.address != UNULL ); + + return smbios.version; +} diff --git a/roms/ipxe/src/interface/smbios/smbios_settings.c b/roms/ipxe/src/interface/smbios/smbios_settings.c index 893b958e1..5dcf00201 100644 --- a/roms/ipxe/src/interface/smbios/smbios_settings.c +++ b/roms/ipxe/src/interface/smbios/smbios_settings.c @@ -27,15 +27,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/uuid.h> #include <ipxe/smbios.h> -/** SMBIOS settings tag magic number */ -#define SMBIOS_TAG_MAGIC 0x5B /* "SmBios" */ - -/** - * Construct SMBIOS empty tag - * - * @ret tag SMBIOS setting tag - */ -#define SMBIOS_EMPTY_TAG ( SMBIOS_TAG_MAGIC << 24 ) +/** SMBIOS settings scope */ +static const struct settings_scope smbios_settings_scope; /** * Construct SMBIOS raw-data tag @@ -46,8 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret tag SMBIOS setting tag */ #define SMBIOS_RAW_TAG( _type, _structure, _field ) \ - ( ( SMBIOS_TAG_MAGIC << 24 ) | \ - ( (_type) << 16 ) | \ + ( ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) | \ ( sizeof ( ( ( _structure * ) 0 )->_field ) ) ) @@ -60,8 +52,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret tag SMBIOS setting tag */ #define SMBIOS_STRING_TAG( _type, _structure, _field ) \ - ( ( SMBIOS_TAG_MAGIC << 24 ) | \ - ( (_type) << 16 ) | \ + ( ( (_type) << 16 ) | \ ( offsetof ( _structure, _field ) << 8 ) ) /** @@ -72,12 +63,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret applies Setting applies within this settings block */ static int smbios_applies ( struct settings *settings __unused, - struct setting *setting ) { - unsigned int tag_magic; + const struct setting *setting ) { - /* Check tag magic */ - tag_magic = ( setting->tag >> 24 ); - return ( tag_magic == SMBIOS_TAG_MAGIC ); + return ( setting->scope == &smbios_settings_scope ); } /** @@ -93,50 +81,77 @@ static int smbios_fetch ( struct settings *settings __unused, struct setting *setting, void *data, size_t len ) { struct smbios_structure structure; - unsigned int tag_magic; + unsigned int tag_instance; unsigned int tag_type; unsigned int tag_offset; unsigned int tag_len; int rc; - /* Split tag into type, offset and length */ - tag_magic = ( setting->tag >> 24 ); + /* Split tag into instance, type, offset and length */ + tag_instance = ( ( setting->tag >> 24 ) & 0xff ); tag_type = ( ( setting->tag >> 16 ) & 0xff ); tag_offset = ( ( setting->tag >> 8 ) & 0xff ); tag_len = ( setting->tag & 0xff ); - assert ( tag_magic == SMBIOS_TAG_MAGIC ); /* Find SMBIOS structure */ - if ( ( rc = find_smbios_structure ( tag_type, &structure ) ) != 0 ) + if ( ( rc = find_smbios_structure ( tag_type, tag_instance, + &structure ) ) != 0 ) return rc; { uint8_t buf[structure.header.len]; + const void *raw; + union uuid uuid; + unsigned int index; /* Read SMBIOS structure */ if ( ( rc = read_smbios_structure ( &structure, buf, sizeof ( buf ) ) ) != 0 ) return rc; - if ( tag_len == 0 ) { - /* String */ - if ( ( rc = read_smbios_string ( &structure, - buf[tag_offset], + /* A <length> of zero indicates that the byte at + * <offset> contains a string index. An <offset> of + * zero indicates that the <length> contains a literal + * string index. + */ + if ( ( tag_len == 0 ) || ( tag_offset == 0 ) ) { + index = ( ( tag_offset == 0 ) ? + tag_len : buf[tag_offset] ); + if ( ( rc = read_smbios_string ( &structure, index, data, len ) ) < 0 ) { return rc; } if ( ! setting->type ) setting->type = &setting_type_string; return rc; - } else { - /* Raw data */ - if ( len > tag_len ) - len = tag_len; - memcpy ( data, &buf[tag_offset], len ); - if ( ! setting->type ) - setting->type = &setting_type_hex; - return tag_len; } + + /* Mangle UUIDs if necessary. iPXE treats UUIDs as + * being in network byte order (big-endian). SMBIOS + * specification version 2.6 states that UUIDs are + * stored with little-endian values in the first three + * fields; earlier versions did not specify an + * endianness. dmidecode assumes that the byte order + * is little-endian if and only if the SMBIOS version + * is 2.6 or higher; we match this behaviour. + */ + raw = &buf[tag_offset]; + if ( ( setting->type == &setting_type_uuid ) && + ( tag_len == sizeof ( uuid ) ) && + ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) { + DBG ( "SMBIOS detected mangled UUID\n" ); + memcpy ( &uuid, &buf[tag_offset], sizeof ( uuid ) ); + uuid_mangle ( &uuid ); + raw = &uuid; + } + + /* Return data */ + if ( len > tag_len ) + len = tag_len; + memcpy ( data, raw, len ); + if ( ! setting->type ) + setting->type = &setting_type_hex; + return tag_len; } } @@ -149,10 +164,10 @@ static struct settings_operations smbios_settings_operations = { /** SMBIOS settings */ static struct settings smbios_settings = { .refcnt = NULL, - .tag_magic = SMBIOS_EMPTY_TAG, .siblings = LIST_HEAD_INIT ( smbios_settings.siblings ), .children = LIST_HEAD_INIT ( smbios_settings.children ), .op = &smbios_settings_operations, + .default_scope = &smbios_settings_scope, }; /** Initialise SMBIOS settings */ @@ -173,46 +188,56 @@ struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = { }; /** UUID setting obtained via SMBIOS */ -struct setting uuid_setting __setting ( SETTING_HOST ) = { +const struct setting uuid_setting __setting ( SETTING_HOST, uuid ) = { .name = "uuid", .description = "UUID", .tag = SMBIOS_RAW_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, struct smbios_system_information, uuid ), .type = &setting_type_uuid, + .scope = &smbios_settings_scope, }; -/** Other SMBIOS named settings */ -struct setting smbios_named_settings[] __setting ( SETTING_HOST_EXTRA ) = { - { - .name = "manufacturer", - .description = "Manufacturer", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, - manufacturer ), - .type = &setting_type_string, - }, - { - .name = "product", - .description = "Product name", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, - product ), - .type = &setting_type_string, - }, - { - .name = "serial", - .description = "Serial number", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, - struct smbios_system_information, - serial ), - .type = &setting_type_string, - }, - { - .name = "asset", - .description = "Asset tag", - .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_ENCLOSURE_INFORMATION, - struct smbios_enclosure_information, - asset_tag ), - .type = &setting_type_string, - }, +/** Manufacturer name setting */ +const struct setting manufacturer_setting __setting ( SETTING_HOST_EXTRA, + manufacturer ) = { + .name = "manufacturer", + .description = "Manufacturer", + .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, + struct smbios_system_information, + manufacturer ), + .type = &setting_type_string, + .scope = &smbios_settings_scope, +}; + +/** Product name setting */ +const struct setting product_setting __setting ( SETTING_HOST_EXTRA, product )={ + .name = "product", + .description = "Product name", + .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, + struct smbios_system_information, + product ), + .type = &setting_type_string, + .scope = &smbios_settings_scope, +}; + +/** Serial number setting */ +const struct setting serial_setting __setting ( SETTING_HOST_EXTRA, serial ) = { + .name = "serial", + .description = "Serial number", + .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_SYSTEM_INFORMATION, + struct smbios_system_information, + serial ), + .type = &setting_type_string, + .scope = &smbios_settings_scope, +}; + +/** Asset tag setting */ +const struct setting asset_setting __setting ( SETTING_HOST_EXTRA, asset ) = { + .name = "asset", + .description = "Asset tag", + .tag = SMBIOS_STRING_TAG ( SMBIOS_TYPE_ENCLOSURE_INFORMATION, + struct smbios_enclosure_information, + asset_tag ), + .type = &setting_type_string, + .scope = &smbios_settings_scope, }; diff --git a/roms/ipxe/src/net/80211/net80211.c b/roms/ipxe/src/net/80211/net80211.c index 2181fc4ac..434944523 100644 --- a/roms/ipxe/src/net/80211/net80211.c +++ b/roms/ipxe/src/net/80211/net80211.c @@ -204,11 +204,11 @@ struct settings_applicator net80211_applicator __settings_applicator = { * If this is blank, we scan for all networks and use the one with the * greatest signal strength. */ -struct setting net80211_ssid_setting __setting ( SETTING_NETDEV_EXTRA ) = { +const struct setting net80211_ssid_setting __setting ( SETTING_NETDEV_EXTRA, + ssid ) = { .name = "ssid", .description = "Wireless SSID", .type = &setting_type_string, - .tag = NET80211_SETTING_TAG_SSID, }; /** Whether to use active scanning @@ -217,11 +217,11 @@ struct setting net80211_ssid_setting __setting ( SETTING_NETDEV_EXTRA ) = { * active scan (send probe packets). If this setting is nonzero, an * active scan on the 2.4GHz band will be used to associate. */ -struct setting net80211_active_setting __setting ( SETTING_NETDEV_EXTRA ) = { +const struct setting net80211_active_setting __setting ( SETTING_NETDEV_EXTRA, + active-scan ) = { .name = "active-scan", .description = "Actively scan for wireless networks", .type = &setting_type_int8, - .tag = NET80211_SETTING_TAG_ACTIVE_SCAN, }; /** The cryptographic key to use @@ -230,11 +230,11 @@ struct setting net80211_active_setting __setting ( SETTING_NETDEV_EXTRA ) = { * normal iPXE method for entering hex settings; an ASCII string of * hex characters will not behave as expected. */ -struct setting net80211_key_setting __setting ( SETTING_NETDEV_EXTRA ) = { +const struct setting net80211_key_setting __setting ( SETTING_NETDEV_EXTRA, + key ) = { .name = "key", .description = "Wireless encryption key", .type = &setting_type_string, - .tag = NET80211_SETTING_TAG_KEY, }; /** @} */ @@ -602,6 +602,7 @@ static struct ll_protocol net80211_ll_protocol __ll_protocol = { .ntoa = eth_ntoa, .mc_hash = eth_mc_hash, .eth_addr = eth_eth_addr, + .eui64 = eth_eui64, .ll_proto = htons ( ARPHRD_ETHER ), /* "encapsulated Ethernet" */ .hw_addr_len = ETH_ALEN, .ll_addr_len = ETH_ALEN, diff --git a/roms/ipxe/src/net/80211/sec80211.c b/roms/ipxe/src/net/80211/sec80211.c index d159edbdf..d1bc75e90 100644 --- a/roms/ipxe/src/net/80211/sec80211.c +++ b/roms/ipxe/src/net/80211/sec80211.c @@ -45,8 +45,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ENOTSUP_CCMP __einfo_error ( EINFO_ENOTSUP_CCMP ) #define EINFO_ENOTSUP_CCMP __einfo_uniqify ( EINFO_ENOTSUP, \ ( 0x10 | NET80211_CRYPT_CCMP ), "CCMP not supported" ) -#define ENOTSUP_CRYPT( crypt ) \ - EUNIQ ( ENOTSUP, ( 0x10 | (crypt) ), \ +#define ENOTSUP_CRYPT( crypt ) \ + EUNIQ ( EINFO_ENOTSUP, ( 0x10 | (crypt) ), \ ENOTSUP_WEP, ENOTSUP_TKIP, ENOTSUP_CCMP ) /** Mapping from net80211 crypto/secprot types to RSN OUI descriptors */ diff --git a/roms/ipxe/src/net/80211/wep.c b/roms/ipxe/src/net/80211/wep.c index 37b27f71a..e22ac8998 100644 --- a/roms/ipxe/src/net/80211/wep.c +++ b/roms/ipxe/src/net/80211/wep.c @@ -236,8 +236,8 @@ static int trivial_init ( struct net80211_device *dev ) dev->associating->crypto == NET80211_CRYPT_NONE ) return 0; /* no crypto? OK. */ - len = fetch_setting ( netdev_settings ( dev->netdev ), - &net80211_key_setting, key, WEP_MAX_KEY ); + len = fetch_raw_setting ( netdev_settings ( dev->netdev ), + &net80211_key_setting, key, WEP_MAX_KEY ); if ( len <= 0 ) { DBGC ( dev, "802.11 %p cannot do WEP without a key\n", dev ); @@ -278,8 +278,8 @@ static int trivial_change_key ( struct net80211_device *dev ) if ( ! dev->crypto || ( dev->crypto->init != wep_init ) ) change ^= 1; - len = fetch_setting ( netdev_settings ( dev->netdev ), - &net80211_key_setting, key, WEP_MAX_KEY ); + len = fetch_raw_setting ( netdev_settings ( dev->netdev ), + &net80211_key_setting, key, WEP_MAX_KEY ); if ( len <= 0 ) change ^= 1; diff --git a/roms/ipxe/src/net/arp.c b/roms/ipxe/src/net/arp.c index b94eb9064..261e681e1 100644 --- a/roms/ipxe/src/net/arp.c +++ b/roms/ipxe/src/net/arp.c @@ -28,11 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/if_arp.h> #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> -#include <ipxe/list.h> -#include <ipxe/retry.h> -#include <ipxe/timer.h> -#include <ipxe/malloc.h> -#include <ipxe/refcnt.h> +#include <ipxe/neighbour.h> #include <ipxe/arp.h> /** @file @@ -45,291 +41,30 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** ARP minimum timeout */ -#define ARP_MIN_TIMEOUT ( TICKS_PER_SEC / 8 ) - -/** ARP maximum timeout */ -#define ARP_MAX_TIMEOUT ( TICKS_PER_SEC * 3 ) - -/** An ARP cache entry */ -struct arp_entry { - /** Reference count */ - struct refcnt refcnt; - /** List of ARP cache entries */ - struct list_head list; - /** Network device */ - struct net_device *netdev; - /** Network-layer protocol */ - struct net_protocol *net_protocol; - /** Network-layer destination address */ - uint8_t net_dest[MAX_NET_ADDR_LEN]; - /** Network-layer source address */ - uint8_t net_source[MAX_NET_ADDR_LEN]; - /** Link-layer destination address */ - uint8_t ll_dest[MAX_LL_ADDR_LEN]; - /** Retransmission timer */ - struct retry_timer timer; - /** Pending I/O buffers */ - struct list_head tx_queue; -}; - -/** The ARP cache */ -static LIST_HEAD ( arp_entries ); - struct net_protocol arp_protocol __net_protocol; -static void arp_expired ( struct retry_timer *timer, int over ); - -/** - * Free ARP cache entry - * - * @v refcnt Reference count - */ -static void arp_free ( struct refcnt *refcnt ) { - struct arp_entry *arp = - container_of ( refcnt, struct arp_entry, refcnt ); - - /* Sanity check */ - assert ( list_empty ( &arp->tx_queue ) ); - - /* Drop reference to network device */ - netdev_put ( arp->netdev ); - - /* Free entry */ - free ( arp ); -} - -/** - * Create ARP cache entry - * - * @v netdev Network device - * @v net_protocol Network-layer protocol - * @v net_dest Destination network-layer address - * @v net_source Source network-layer address - * @ret arp ARP cache entry, or NULL if allocation failed - */ -static struct arp_entry * arp_create ( struct net_device *netdev, - struct net_protocol *net_protocol, - const void *net_dest, - const void *net_source ) { - struct arp_entry *arp; - - /* Allocate and initialise entry */ - arp = zalloc ( sizeof ( *arp ) ); - if ( ! arp ) - return NULL; - ref_init ( &arp->refcnt, arp_free ); - arp->netdev = netdev_get ( netdev ); - arp->net_protocol = net_protocol; - memcpy ( arp->net_dest, net_dest, - net_protocol->net_addr_len ); - memcpy ( arp->net_source, net_source, - net_protocol->net_addr_len ); - timer_init ( &arp->timer, arp_expired, &arp->refcnt ); - arp->timer.min_timeout = ARP_MIN_TIMEOUT; - arp->timer.max_timeout = ARP_MAX_TIMEOUT; - INIT_LIST_HEAD ( &arp->tx_queue ); - - /* Start timer running to trigger initial transmission */ - start_timer_nodelay ( &arp->timer ); - - /* Transfer ownership to cache */ - list_add ( &arp->list, &arp_entries ); - - DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name, - net_protocol->name, net_protocol->ntoa ( net_dest ) ); - return arp; -} - -/** - * Find entry in the ARP cache - * - * @v netdev Network device - * @v net_protocol Network-layer protocol - * @v net_dest Destination network-layer address - * @ret arp ARP cache entry, or NULL if not found - */ -static struct arp_entry * arp_find ( struct net_device *netdev, - struct net_protocol *net_protocol, - const void *net_dest ) { - struct arp_entry *arp; - - list_for_each_entry ( arp, &arp_entries, list ) { - if ( ( arp->netdev == netdev ) && - ( arp->net_protocol == net_protocol ) && - ( memcmp ( arp->net_dest, net_dest, - net_protocol->net_addr_len ) == 0 ) ) { - - /* Move to start of cache */ - list_del ( &arp->list ); - list_add ( &arp->list, &arp_entries ); - - return arp; - } - } - return NULL; -} - -/** - * Destroy ARP cache entry - * - * @v arp ARP cache entry - * @v rc Reason for destruction - */ -static void arp_destroy ( struct arp_entry *arp, int rc ) { - struct net_device *netdev = arp->netdev; - struct net_protocol *net_protocol = arp->net_protocol; - struct io_buffer *iobuf; - - /* Take ownership from cache */ - list_del ( &arp->list ); - - /* Stop timer */ - stop_timer ( &arp->timer ); - - /* Discard any outstanding I/O buffers */ - while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer, - list ) ) != NULL ) { - DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: " - "%s\n", arp, netdev->name, net_protocol->name, - net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) ); - list_del ( &iobuf->list ); - netdev_tx_err ( arp->netdev, iobuf, rc ); - } - - DBGC ( arp, "ARP %p %s %s %s destroyed: %s\n", arp, netdev->name, - net_protocol->name, net_protocol->ntoa ( arp->net_dest ), - strerror ( rc ) ); - - /* Drop remaining reference */ - ref_put ( &arp->refcnt ); -} - /** - * Test if ARP cache entry has a valid link-layer address + * Transmit ARP request * - * @v arp ARP cache entry - * @ret resolved ARP cache entry is resolved - */ -static inline int arp_resolved ( struct arp_entry *arp ) { - return ( ! timer_running ( &arp->timer ) ); -} - -/** - * Transmit packet, determining link-layer address via ARP - * - * @v iobuf I/O buffer * @v netdev Network device * @v net_protocol Network-layer protocol * @v net_dest Destination network-layer address * @v net_source Source network-layer address - * @v ll_source Source link-layer address * @ret rc Return status code */ -int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, - struct net_protocol *net_protocol, const void *net_dest, - const void *net_source, const void *ll_source ) { - struct arp_entry *arp; - - /* Find or create ARP cache entry */ - arp = arp_find ( netdev, net_protocol, net_dest ); - if ( ! arp ) { - arp = arp_create ( netdev, net_protocol, net_dest, - net_source ); - if ( ! arp ) - return -ENOMEM; - } - - /* If a link-layer address is available then transmit - * immediately, otherwise queue for later transmission. - */ - if ( arp_resolved ( arp ) ) { - return net_tx ( iobuf, netdev, net_protocol, arp->ll_dest, - ll_source ); - } else { - DBGC2 ( arp, "ARP %p %s %s %s deferring packet\n", - arp, netdev->name, net_protocol->name, - net_protocol->ntoa ( net_dest ) ); - list_add_tail ( &iobuf->list, &arp->tx_queue ); - return -EAGAIN; - } -} - -/** - * Update ARP cache entry - * - * @v arp ARP cache entry - * @v ll_dest Destination link-layer address - */ -static void arp_update ( struct arp_entry *arp, const void *ll_dest ) { - struct net_device *netdev = arp->netdev; - struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct net_protocol *net_protocol = arp->net_protocol; - struct io_buffer *iobuf; - int rc; - - DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name, - net_protocol->name, net_protocol->ntoa ( arp->net_dest ), - ll_protocol->ntoa ( ll_dest ) ); - - /* Fill in link-layer address */ - memcpy ( arp->ll_dest, ll_dest, ll_protocol->ll_addr_len ); - - /* Stop retransmission timer */ - stop_timer ( &arp->timer ); - - /* Transmit any packets in queue. Take out a temporary - * reference on the entry to prevent it from going out of - * scope during the call to net_tx(). - */ - ref_get ( &arp->refcnt ); - while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer, - list ) ) != NULL ) { - DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n", - arp, netdev->name, net_protocol->name, - net_protocol->ntoa ( arp->net_dest ) ); - list_del ( &iobuf->list ); - if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest, - netdev->ll_addr ) ) != 0 ) { - DBGC ( arp, "ARP %p could not transmit deferred " - "packet: %s\n", arp, strerror ( rc ) ); - /* Ignore error and continue */ - } - } - ref_put ( &arp->refcnt ); -} - -/** - * Handle ARP timer expiry - * - * @v timer Retry timer - * @v fail Failure indicator - */ -static void arp_expired ( struct retry_timer *timer, int fail ) { - struct arp_entry *arp = container_of ( timer, struct arp_entry, timer ); - struct net_device *netdev = arp->netdev; +static int arp_tx_request ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *net_source ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct net_protocol *net_protocol = arp->net_protocol; struct io_buffer *iobuf; struct arphdr *arphdr; int rc; - /* If we have failed, destroy the cache entry */ - if ( fail ) { - arp_destroy ( arp, -ETIMEDOUT ); - return; - } - - /* Restart the timer */ - start_timer ( &arp->timer ); - /* Allocate ARP packet */ iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) + ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) ); - if ( ! iobuf ) { - /* Leave timer running and try again later */ - return; - } + if ( ! iobuf ) + return -ENOMEM; iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); /* Build up ARP request */ @@ -342,21 +77,30 @@ static void arp_expired ( struct retry_timer *timer, int fail ) { memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ), netdev->ll_addr, ll_protocol->ll_addr_len ); memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), - arp->net_source, net_protocol->net_addr_len ); + net_source, net_protocol->net_addr_len ); memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ), 0, ll_protocol->ll_addr_len ); memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), - arp->net_dest, net_protocol->net_addr_len ); + net_dest, net_protocol->net_addr_len ); /* Transmit ARP request */ if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol, netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) { - DBGC ( arp, "ARP %p could not transmit request: %s\n", - arp, strerror ( rc ) ); - return; + DBGC ( netdev, "ARP %s %s %s could not transmit request: %s\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( net_dest ), strerror ( rc ) ); + return rc; } + + return 0; } +/** ARP neighbour discovery protocol */ +struct neighbour_discovery arp_discovery = { + .name = "ARP", + .tx_request = arp_tx_request, +}; + /** * Identify ARP protocol * @@ -368,9 +112,8 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) { struct arp_net_protocol *arp_net_protocol; for_each_table_entry ( arp_net_protocol, ARP_NET_PROTOCOLS ) { - if ( arp_net_protocol->net_protocol->net_proto == net_proto ) { + if ( arp_net_protocol->net_protocol->net_proto == net_proto ) return arp_net_protocol; - } } return NULL; } @@ -392,7 +135,6 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, struct arp_net_protocol *arp_net_protocol; struct net_protocol *net_protocol; struct ll_protocol *ll_protocol; - struct arp_entry *arp; int rc; /* Identify network-layer and link-layer protocols */ @@ -412,11 +154,9 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, goto done; } - /* See if we have an entry for this sender, and update it if so */ - arp = arp_find ( netdev, net_protocol, arp_sender_pa ( arphdr ) ); - if ( arp ) { - arp_update ( arp, arp_sender_ha ( arphdr ) ); - } + /* Update neighbour cache entry for this sender, if any */ + neighbour_update ( netdev, net_protocol, arp_sender_pa ( arphdr ), + arp_sender_ha ( arphdr ) ); /* If it's not a request, there's nothing more to do */ if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) { @@ -431,10 +171,10 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, } /* Change request to a reply */ - DBGC ( netdev, "ARP reply %s %s %s => %s %s\n", - netdev->name, net_protocol->name, - net_protocol->ntoa ( arp_target_pa ( arphdr ) ), - ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); + DBGC2 ( netdev, "ARP %s %s %s reply => %s %s\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( arp_target_pa ( arphdr ) ), + ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); arphdr->ar_op = htons ( ARPOP_REPLY ); memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), arphdr->ar_hln + arphdr->ar_pln ); @@ -444,8 +184,10 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol, arp_target_ha ( arphdr ), netdev->ll_addr ) ) != 0 ) { - DBGC ( netdev, "ARP could not transmit reply via %s: %s\n", - netdev->name, strerror ( rc ) ); + DBGC ( netdev, "ARP %s %s %s could not transmit reply: %s\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( arp_target_pa ( arphdr ) ), + strerror ( rc ) ); goto done; } @@ -469,72 +211,10 @@ static const char * arp_ntoa ( const void *net_addr __unused ) { return "<ARP>"; } -/** ARP protocol */ +/** ARP network protocol */ struct net_protocol arp_protocol __net_protocol = { .name = "ARP", .net_proto = htons ( ETH_P_ARP ), .rx = arp_rx, .ntoa = arp_ntoa, }; - -/** - * Update ARP cache on network device creation - * - * @v netdev Network device - */ -static int arp_probe ( struct net_device *netdev __unused ) { - /* Nothing to do */ - return 0; -} - -/** - * Update ARP cache on network device state change or removal - * - * @v netdev Network device - */ -static void arp_flush ( struct net_device *netdev ) { - struct arp_entry *arp; - struct arp_entry *tmp; - - /* Remove all ARP cache entries when a network device is closed */ - if ( ! netdev_is_open ( netdev ) ) { - list_for_each_entry_safe ( arp, tmp, &arp_entries, list ) - arp_destroy ( arp, -ENODEV ); - } -} - -/** ARP driver (for net device notifications) */ -struct net_driver arp_net_driver __net_driver = { - .name = "ARP", - .probe = arp_probe, - .notify = arp_flush, - .remove = arp_flush, -}; - -/** - * Discard some cached ARP entries - * - * @ret discarded Number of cached items discarded - */ -static unsigned int arp_discard ( void ) { - struct arp_entry *arp; - - /* Drop oldest cache entry, if any */ - arp = list_last_entry ( &arp_entries, struct arp_entry, list ); - if ( arp ) { - arp_destroy ( arp, -ENOBUFS ); - return 1; - } else { - return 0; - } -} - -/** ARP cache discarder - * - * ARP cache entries are deemed to have a high replacement cost, since - * flushing an active ARP cache entry midway through a TCP transfer - * will cause substantial disruption. - */ -struct cache_discarder arp_discarder __cache_discarder ( CACHE_EXPENSIVE ) = { - .discard = arp_discard, -}; diff --git a/roms/ipxe/src/net/cachedhcp.c b/roms/ipxe/src/net/cachedhcp.c deleted file mode 100644 index fc7dabc90..000000000 --- a/roms/ipxe/src/net/cachedhcp.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ipxe/dhcp.h> -#include <ipxe/dhcppkt.h> -#include <ipxe/netdevice.h> -#include <ipxe/iobuf.h> -#include <ipxe/uaccess.h> - -/** @file - * - * Cached DHCP packet handling - * - */ - -/** - * Store cached DHCPACK packet - * - * @v data User pointer to cached DHCP packet data - * @v len Length of cached DHCP packet data - * @ret rc Return status code - * - * This function should be called by the architecture-specific - * get_cached_dhcpack() handler. - */ -void store_cached_dhcpack ( userptr_t data, size_t len ) { - struct dhcp_packet *dhcppkt; - struct dhcphdr *dhcphdr; - struct settings *parent; - int rc; - - /* Create DHCP packet */ - dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len ); - if ( ! dhcppkt ) - return; - - /* Fill in data for DHCP packet */ - dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( * dhcppkt ) ); - copy_from_user ( dhcphdr, data, 0, len ); - dhcppkt_init ( dhcppkt, dhcphdr, len ); - DBG_HD ( dhcppkt->options.data, dhcppkt->options.used_len ); - - /* Register settings on the last opened network device. - * This will have the effect of registering cached settings - * with a network device when "dhcp netX" is performed for that - * device, which is usually what we want. - */ - parent = netdev_settings ( last_opened_netdev() ); - if ( ( rc = register_settings ( &dhcppkt->settings, parent, - DHCP_SETTINGS_NAME ) ) != 0 ) - DBG ( "DHCP could not register cached settings: %s\n", - strerror ( rc ) ); - - dhcppkt_put ( dhcppkt ); - - DBG ( "DHCP registered cached settings\n" ); -} diff --git a/roms/ipxe/src/net/dhcpopts.c b/roms/ipxe/src/net/dhcpopts.c index 6d29a7b5e..8cd19cf80 100644 --- a/roms/ipxe/src/net/dhcpopts.c +++ b/roms/ipxe/src/net/dhcpopts.c @@ -202,7 +202,6 @@ static int resize_dhcp_option ( struct dhcp_options *options, size_t new_encapsulator_len; void *source; void *dest; - void *end; int rc; /* Check for sufficient space */ @@ -245,8 +244,7 @@ static int resize_dhcp_option ( struct dhcp_options *options, option = dhcp_option ( options, offset ); source = ( ( ( void * ) option ) + old_len ); dest = ( ( ( void * ) option ) + new_len ); - end = ( options->data + options->alloc_len ); - memmove ( dest, source, ( end - dest ) ); + memmove ( dest, source, ( new_used_len - offset - new_len ) ); /* Shrink options block, if applicable */ if ( new_used_len < options->alloc_len ) { diff --git a/roms/ipxe/src/net/dhcppkt.c b/roms/ipxe/src/net/dhcppkt.c index 528f90037..a9a6d3a94 100644 --- a/roms/ipxe/src/net/dhcppkt.c +++ b/roms/ipxe/src/net/dhcppkt.c @@ -226,11 +226,12 @@ int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag, * @ret applies Setting applies within this settings block */ static int dhcppkt_settings_applies ( struct settings *settings, - struct setting *setting ) { + const struct setting *setting ) { struct dhcp_packet *dhcppkt = container_of ( settings, struct dhcp_packet, settings ); - return dhcppkt_applies ( dhcppkt, setting->tag ); + return ( ( setting->scope == NULL ) && + dhcppkt_applies ( dhcppkt, setting->tag ) ); } /** @@ -243,7 +244,7 @@ static int dhcppkt_settings_applies ( struct settings *settings, * @ret rc Return status code */ static int dhcppkt_settings_store ( struct settings *settings, - struct setting *setting, + const struct setting *setting, const void *data, size_t len ) { struct dhcp_packet *dhcppkt = container_of ( settings, struct dhcp_packet, settings ); @@ -299,6 +300,6 @@ void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data, dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options, ( len - offsetof ( struct dhcphdr, options ) ), dhcpopt_no_realloc ); - settings_init ( &dhcppkt->settings, - &dhcppkt_settings_operations, &dhcppkt->refcnt, 0 ); + settings_init ( &dhcppkt->settings, &dhcppkt_settings_operations, + &dhcppkt->refcnt, NULL ); } diff --git a/roms/ipxe/src/net/ethernet.c b/roms/ipxe/src/net/ethernet.c index 4fd2ab6e5..a2e565899 100644 --- a/roms/ipxe/src/net/ethernet.c +++ b/roms/ipxe/src/net/ethernet.c @@ -149,6 +149,11 @@ int eth_mc_hash ( unsigned int af, const void *net_addr, void *ll_addr ) { ll_addr_bytes[4] = net_addr_bytes[2]; ll_addr_bytes[5] = net_addr_bytes[3]; return 0; + case AF_INET6: + ll_addr_bytes[0] = 0x33; + ll_addr_bytes[1] = 0x33; + memcpy ( &ll_addr_bytes[2], &net_addr_bytes[12], 4 ); + return 0; default: return -ENOTSUP; } @@ -165,6 +170,21 @@ int eth_eth_addr ( const void *ll_addr, void *eth_addr ) { return 0; } +/** + * Generate EUI-64 address + * + * @v ll_addr Link-layer address + * @v eui64 EUI-64 address to fill in + * @ret rc Return status code + */ +int eth_eui64 ( const void *ll_addr, void *eui64 ) { + + memcpy ( ( eui64 + 0 ), ( ll_addr + 0 ), 3 ); + memcpy ( ( eui64 + 5 ), ( ll_addr + 3 ), 3 ); + *( ( uint16_t * ) ( eui64 + 3 ) ) = htons ( 0xfffe ); + return 0; +} + /** Ethernet protocol */ struct ll_protocol ethernet_protocol __ll_protocol = { .name = "Ethernet", @@ -178,6 +198,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = { .ntoa = eth_ntoa, .mc_hash = eth_mc_hash, .eth_addr = eth_eth_addr, + .eui64 = eth_eui64, }; /** diff --git a/roms/ipxe/src/net/fakedhcp.c b/roms/ipxe/src/net/fakedhcp.c index d67501ed3..3dec88b11 100644 --- a/roms/ipxe/src/net/fakedhcp.c +++ b/roms/ipxe/src/net/fakedhcp.c @@ -49,8 +49,8 @@ static int copy_encap_settings ( struct dhcp_packet *dest, struct setting setting = { .name = "" }; unsigned int subtag; unsigned int tag; + void *data; int len; - int check_len; int rc; for ( subtag = DHCP_MIN_OPTION; subtag <= DHCP_MAX_OPTION; subtag++ ) { @@ -66,17 +66,11 @@ static int copy_encap_settings ( struct dhcp_packet *dest, default: /* Copy setting, if present */ setting.tag = tag; - len = fetch_setting_len ( source, &setting ); - if ( len < 0 ) - break; - { - char buf[len]; - - check_len = fetch_setting ( source, &setting, - buf, sizeof (buf)); - assert ( check_len == len ); - if ( ( rc = dhcppkt_store ( dest, tag, buf, - sizeof(buf) )) !=0) + len = fetch_raw_setting_copy ( source, &setting, &data); + if ( len >= 0 ) { + rc = dhcppkt_store ( dest, tag, data, len ); + free ( data ); + if ( rc != 0 ) return rc; } break; diff --git a/roms/ipxe/src/net/fcoe.c b/roms/ipxe/src/net/fcoe.c index d11304258..e9e404ec3 100644 --- a/roms/ipxe/src/net/fcoe.c +++ b/roms/ipxe/src/net/fcoe.c @@ -1011,7 +1011,7 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) { /* Increment the timeout counter */ fcoe->timeouts++; - if ( vlan_can_be_trunk ( fcoe->netdev ) & + if ( vlan_can_be_trunk ( fcoe->netdev ) && ! ( fcoe->flags & FCOE_VLAN_TIMED_OUT ) ) { /* If we have already found a VLAN, send infrequent diff --git a/roms/ipxe/src/net/fragment.c b/roms/ipxe/src/net/fragment.c new file mode 100644 index 000000000..410915b3b --- /dev/null +++ b/roms/ipxe/src/net/fragment.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <ipxe/retry.h> +#include <ipxe/timer.h> +#include <ipxe/ipstat.h> +#include <ipxe/fragment.h> + +/** @file + * + * Fragment reassembly + * + */ + +/** + * Expire fragment reassembly buffer + * + * @v timer Retry timer + * @v fail Failure indicator + */ +static void fragment_expired ( struct retry_timer *timer, int fail __unused ) { + struct fragment *fragment = + container_of ( timer, struct fragment, timer ); + + DBGC ( fragment, "FRAG %p expired\n", fragment ); + free_iob ( fragment->iobuf ); + list_del ( &fragment->list ); + fragment->fragments->stats->reasm_fails++; + free ( fragment ); +} + +/** + * Find fragment reassembly buffer + * + * @v fragments Fragment reassembler + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret fragment Fragment reassembly buffer, or NULL if not found + */ +static struct fragment * fragment_find ( struct fragment_reassembler *fragments, + struct io_buffer *iobuf, + size_t hdrlen ) { + struct fragment *fragment; + + list_for_each_entry ( fragment, &fragments->list, list ) { + if ( fragments->is_fragment ( fragment, iobuf, hdrlen ) ) + return fragment; + } + return NULL; +} + +/** + * Reassemble packet + * + * @v fragments Fragment reassembler + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret iobuf Reassembled packet, or NULL + * + * This function takes ownership of the I/O buffer. Note that the + * length of the non-fragmentable portion may be modified. + */ +struct io_buffer * fragment_reassemble ( struct fragment_reassembler *fragments, + struct io_buffer *iobuf, + size_t *hdrlen ) { + struct fragment *fragment; + struct io_buffer *new_iobuf; + size_t new_len; + size_t offset; + size_t expected_offset; + int more_frags; + + /* Update statistics */ + fragments->stats->reasm_reqds++; + + /* Find matching fragment reassembly buffer, if any */ + fragment = fragment_find ( fragments, iobuf, *hdrlen ); + + /* Drop out-of-order fragments */ + offset = fragments->fragment_offset ( iobuf, *hdrlen ); + expected_offset = ( fragment ? ( iob_len ( fragment->iobuf ) - + fragment->hdrlen ) : 0 ); + if ( offset != expected_offset ) { + DBGC ( fragment, "FRAG %p dropping out-of-sequence fragment " + "[%zd,%zd), expected [%zd,...)\n", fragment, offset, + ( offset + iob_len ( iobuf ) - *hdrlen ), + expected_offset ); + goto drop; + } + + /* Create or extend fragment reassembly buffer as applicable */ + if ( ! fragment ) { + + /* Create new fragment reassembly buffer */ + fragment = zalloc ( sizeof ( *fragment ) ); + if ( ! fragment ) + goto drop; + list_add ( &fragment->list, &fragments->list ); + fragment->iobuf = iobuf; + fragment->hdrlen = *hdrlen; + timer_init ( &fragment->timer, fragment_expired, NULL ); + fragment->fragments = fragments; + DBGC ( fragment, "FRAG %p [0,%zd)\n", fragment, + ( iob_len ( iobuf ) - *hdrlen ) ); + + } else { + + /* Check if this is the final fragment */ + more_frags = fragments->more_fragments ( iobuf, *hdrlen ); + DBGC ( fragment, "FRAG %p [%zd,%zd)%s\n", fragment, + offset, ( offset + iob_len ( iobuf ) - *hdrlen ), + ( more_frags ? "" : " complete" ) ); + + /* Extend fragment reassembly buffer. Preserve I/O + * buffer headroom to allow for code which modifies + * and resends the buffer (e.g. ICMP echo responses). + */ + iob_pull ( iobuf, *hdrlen ); + new_len = ( iob_headroom ( fragment->iobuf ) + + iob_len ( fragment->iobuf ) + iob_len ( iobuf ) ); + new_iobuf = alloc_iob ( new_len ); + if ( ! new_iobuf ) { + DBGC ( fragment, "FRAG %p could not extend reassembly " + "buffer to %zd bytes\n", fragment, new_len ); + goto drop; + } + iob_reserve ( new_iobuf, iob_headroom ( fragment->iobuf ) ); + memcpy ( iob_put ( new_iobuf, iob_len ( fragment->iobuf ) ), + fragment->iobuf->data, iob_len ( fragment->iobuf ) ); + memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ), + iobuf->data, iob_len ( iobuf ) ); + free_iob ( fragment->iobuf ); + fragment->iobuf = new_iobuf; + free_iob ( iobuf ); + + /* Stop fragment reassembly timer */ + stop_timer ( &fragment->timer ); + + /* If this is the final fragment, return it */ + if ( ! more_frags ) { + iobuf = fragment->iobuf; + *hdrlen = fragment->hdrlen; + list_del ( &fragment->list ); + free ( fragment ); + fragments->stats->reasm_oks++; + return iobuf; + } + } + + /* (Re)start fragment reassembly timer */ + start_timer_fixed ( &fragment->timer, FRAGMENT_TIMEOUT ); + + return NULL; + + drop: + fragments->stats->reasm_fails++; + free_iob ( iobuf ); + return NULL; +} diff --git a/roms/ipxe/src/net/icmp.c b/roms/ipxe/src/net/icmp.c index 830d82924..1bbf8bd30 100644 --- a/roms/ipxe/src/net/icmp.c +++ b/roms/ipxe/src/net/icmp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>. + * Copyright (C) 2013 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 @@ -20,10 +20,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <string.h> +#include <byteswap.h> #include <errno.h> #include <ipxe/iobuf.h> #include <ipxe/in.h> #include <ipxe/tcpip.h> +#include <ipxe/ping.h> +#include <ipxe/crc32.h> #include <ipxe/icmp.h> /** @file @@ -32,73 +35,192 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -struct tcpip_protocol icmp_protocol __tcpip_protocol; +/** + * Identify ICMP echo protocol + * + * @v st_family Address family + * @ret echo_protocol ICMP echo protocol, or NULL + */ +static struct icmp_echo_protocol * icmp_echo_protocol ( sa_family_t family ) { + struct icmp_echo_protocol *echo_protocol; + + for_each_table_entry ( echo_protocol, ICMP_ECHO_PROTOCOLS ) { + if ( echo_protocol->family == family ) + return echo_protocol; + } + return NULL; +} /** - * Process a received packet + * + * Determine debugging colour for ICMP debug messages + * + * @v st_peer Peer address + * @ret col Debugging colour (for DBGC()) + */ +static uint32_t icmpcol ( struct sockaddr_tcpip *st_peer ) { + + return crc32_le ( 0, st_peer, sizeof ( *st_peer ) ); +} + +/** + * Transmit ICMP echo packet * * @v iobuf I/O buffer - * @v st_src Partially-filled source address - * @v st_dest Partially-filled destination address - * @v pshdr_csum Pseudo-header checksum + * @v st_dest Destination socket address + * @v echo_protocol ICMP echo protocol * @ret rc Return status code */ -static int icmp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, - struct sockaddr_tcpip *st_dest, - uint16_t pshdr_csum __unused ) { - struct icmp_header *icmp = iobuf->data; - size_t len = iob_len ( iobuf ); - unsigned int csum; +static int icmp_tx_echo ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_dest, + struct icmp_echo_protocol *echo_protocol ) { + struct icmp_echo *echo = iobuf->data; int rc; - /* Sanity check */ - if ( len < sizeof ( *icmp ) ) { - DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n", - len, sizeof ( *icmp ) ); - rc = -EINVAL; - goto done; - } + /* Set ICMP type and (re)calculate checksum */ + echo->icmp.chksum = 0; + echo->icmp.chksum = tcpip_chksum ( echo, iob_len ( iobuf ) ); - /* Verify checksum */ - csum = tcpip_chksum ( icmp, len ); - if ( csum != 0 ) { - DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n", - csum ); - DBG_HD ( icmp, len ); - rc = -EINVAL; - goto done; + /* Transmit packet */ + if ( ( rc = tcpip_tx ( iobuf, echo_protocol->tcpip_protocol, NULL, + st_dest, NULL, + ( echo_protocol->net_checksum ? + &echo->icmp.chksum : NULL ) ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Transmit ICMP echo request + * + * @v iobuf I/O buffer + * @v st_dest Destination socket address + * @ret rc Return status code + */ +int icmp_tx_echo_request ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_dest ) { + struct icmp_echo *echo = iobuf->data; + struct icmp_echo_protocol *echo_protocol; + int rc; + + /* Identify ICMP echo protocol */ + echo_protocol = icmp_echo_protocol ( st_dest->st_family ); + if ( ! echo_protocol ) { + DBGC ( icmpcol ( st_dest ), "ICMP TX echo request unknown " + "address family %d\n", st_dest->st_family ); + free_iob ( iobuf ); + return -ENOTSUP; } - /* We respond only to pings */ - if ( icmp->type != ICMP_ECHO_REQUEST ) { - DBG ( "ICMP ignoring type %d\n", icmp->type ); - rc = 0; - goto done; + /* Set type */ + echo->icmp.type = echo_protocol->request; + + /* Transmit request */ + DBGC ( icmpcol ( st_dest ), "ICMP TX echo request id %04x seq %04x\n", + ntohs ( echo->ident ), ntohs ( echo->sequence ) ); + if ( ( rc = icmp_tx_echo ( iobuf, st_dest, echo_protocol ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Transmit ICMP echo reply + * + * @v iobuf I/O buffer + * @v st_dest Destination socket address + * @ret rc Return status code + */ +static int icmp_tx_echo_reply ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_dest, + struct icmp_echo_protocol *echo_protocol ) { + struct icmp_echo *echo = iobuf->data; + int rc; + + /* Set type */ + echo->icmp.type = echo_protocol->reply; + + /* Transmit reply */ + DBGC ( icmpcol ( st_dest ), "ICMP TX echo reply id %04x seq %04x\n", + ntohs ( echo->ident ), ntohs ( echo->sequence ) ); + if ( ( rc = icmp_tx_echo ( iobuf, st_dest, echo_protocol ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Process a received ICMP echo request + * + * @v iobuf I/O buffer + * @v st_src Source socket address + * @v echo_protocol ICMP echo protocol + * @ret rc Return status code + */ +int icmp_rx_echo_request ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_src, + struct icmp_echo_protocol *echo_protocol ) { + struct icmp_echo *echo = iobuf->data; + int rc; + + /* Sanity check */ + if ( iob_len ( iobuf ) < sizeof ( *echo ) ) { + DBGC ( icmpcol ( st_src ), "ICMP RX echo request too short at " + "%zd bytes (min %zd bytes)\n", + iob_len ( iobuf ), sizeof ( *echo ) ); + free_iob ( iobuf ); + return -EINVAL; } + DBGC ( icmpcol ( st_src ), "ICMP RX echo request id %04x seq %04x\n", + ntohs ( echo->ident ), ntohs ( echo->sequence ) ); - DBG ( "ICMP responding to ping\n" ); + /* Transmit echo reply */ + if ( ( rc = icmp_tx_echo_reply ( iobuf, st_src, echo_protocol ) ) != 0 ) + return rc; - /* Change type to response and recalculate checksum */ - icmp->type = ICMP_ECHO_RESPONSE; - icmp->chksum = 0; - icmp->chksum = tcpip_chksum ( icmp, len ); + return 0; +} - /* Transmit the response */ - if ( ( rc = tcpip_tx ( iob_disown ( iobuf ), &icmp_protocol, st_dest, - st_src, NULL, NULL ) ) != 0 ) { - DBG ( "ICMP could not transmit ping response: %s\n", - strerror ( rc ) ); - goto done; +/** + * Process a received ICMP echo request + * + * @v iobuf I/O buffer + * @v st_src Source socket address + * @ret rc Return status code + */ +int icmp_rx_echo_reply ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_src ) { + struct icmp_echo *echo = iobuf->data; + int rc; + + /* Sanity check */ + if ( iob_len ( iobuf ) < sizeof ( *echo ) ) { + DBGC ( icmpcol ( st_src ), "ICMP RX echo reply too short at " + "%zd bytes (min %zd bytes)\n", + iob_len ( iobuf ), sizeof ( *echo ) ); + free_iob ( iobuf ); + return -EINVAL; } + DBGC ( icmpcol ( st_src ), "ICMP RX echo reply id %04x seq %04x\n", + ntohs ( echo->ident ), ntohs ( echo->sequence ) ); - done: - free_iob ( iobuf ); - return rc; + /* Deliver to ping protocol */ + if ( ( rc = ping_rx ( iobuf, st_src ) ) != 0 ) + return rc; + + return 0; } -/** ICMP TCP/IP protocol */ -struct tcpip_protocol icmp_protocol __tcpip_protocol = { - .name = "ICMP", - .rx = icmp_rx, - .tcpip_proto = IP_ICMP, -}; +/** + * Receive ping reply (when no ping protocol is present) + * + * @v iobuf I/O buffer + * @v st_src Source socket address + * @ret rc Return status code + */ +__weak int ping_rx ( struct io_buffer *iobuf, + struct sockaddr_tcpip *st_src __unused ) { + free_iob ( iobuf ); + return 0; +} diff --git a/roms/ipxe/src/net/icmpv4.c b/roms/ipxe/src/net/icmpv4.c new file mode 100644 index 000000000..996ba1490 --- /dev/null +++ b/roms/ipxe/src/net/icmpv4.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <string.h> +#include <errno.h> +#include <ipxe/iobuf.h> +#include <ipxe/in.h> +#include <ipxe/tcpip.h> +#include <ipxe/icmp.h> + +/** @file + * + * ICMPv4 protocol + * + */ + +struct icmp_echo_protocol icmpv4_echo_protocol __icmp_echo_protocol; + +/** + * Process a received packet + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v st_src Partially-filled source address + * @v st_dest Partially-filled destination address + * @v pshdr_csum Pseudo-header checksum + * @ret rc Return status code + */ +static int icmpv4_rx ( struct io_buffer *iobuf, + struct net_device *netdev __unused, + struct sockaddr_tcpip *st_src, + struct sockaddr_tcpip *st_dest __unused, + uint16_t pshdr_csum __unused ) { + struct icmp_header *icmp = iobuf->data; + size_t len = iob_len ( iobuf ); + unsigned int csum; + unsigned int type; + int rc; + + /* Sanity check */ + if ( len < sizeof ( *icmp ) ) { + DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n", + len, sizeof ( *icmp ) ); + rc = -EINVAL; + goto discard; + } + + /* Verify checksum */ + csum = tcpip_chksum ( icmp, len ); + if ( csum != 0 ) { + DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n", + csum ); + DBG_HD ( icmp, len ); + rc = -EINVAL; + goto discard; + } + + /* Handle ICMP packet */ + type = icmp->type; + switch ( type ) { + case ICMP_ECHO_REQUEST: + return icmp_rx_echo_request ( iobuf, st_src, + &icmpv4_echo_protocol ); + case ICMP_ECHO_REPLY: + return icmp_rx_echo_reply ( iobuf, st_src ); + default: + DBG ( "ICMP ignoring type %d\n", type ); + rc = 0; + break; + } + + discard: + free_iob ( iobuf ); + return rc; +} + +/** ICMPv4 TCP/IP protocol */ +struct tcpip_protocol icmpv4_protocol __tcpip_protocol = { + .name = "ICMPv4", + .rx = icmpv4_rx, + .tcpip_proto = IP_ICMP, +}; + +/** ICMPv4 echo protocol */ +struct icmp_echo_protocol icmpv4_echo_protocol __icmp_echo_protocol = { + .family = AF_INET, + .request = ICMP_ECHO_REQUEST, + .reply = ICMP_ECHO_REPLY, + .tcpip_protocol = &icmpv4_protocol, + .net_checksum = 0, +}; diff --git a/roms/ipxe/src/net/icmpv6.c b/roms/ipxe/src/net/icmpv6.c index 1a5aad3ba..479800e7d 100644 --- a/roms/ipxe/src/net/icmpv6.c +++ b/roms/ipxe/src/net/icmpv6.c @@ -1,126 +1,179 @@ -#include <stdint.h> +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + #include <string.h> -#include <byteswap.h> #include <errno.h> +#include <byteswap.h> #include <ipxe/in.h> -#include <ipxe/ip6.h> -#include <ipxe/if_ether.h> #include <ipxe/iobuf.h> -#include <ipxe/ndp.h> -#include <ipxe/icmp6.h> #include <ipxe/tcpip.h> -#include <ipxe/netdevice.h> +#include <ipxe/ping.h> +#include <ipxe/icmpv6.h> + +/** @file + * + * ICMPv6 protocol + * + */ + +struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol; + +/** + * Process received ICMPv6 echo request packet + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v sin6_src Source socket address + * @v sin6_dest Destination socket address + * @ret rc Return status code + */ +static int icmpv6_rx_echo_request ( struct io_buffer *iobuf, + struct net_device *netdev __unused, + struct sockaddr_in6 *sin6_src, + struct sockaddr_in6 *sin6_dest __unused ) { + struct sockaddr_tcpip *st_src = + ( ( struct sockaddr_tcpip * ) sin6_src ); + + return icmp_rx_echo_request ( iobuf, st_src, &icmpv6_echo_protocol ); +} + +/** ICMPv6 echo request handler */ +struct icmpv6_handler icmpv6_echo_request_handler __icmpv6_handler = { + .type = ICMPV6_ECHO_REQUEST, + .rx = icmpv6_rx_echo_request, +}; /** - * Send neighbour solicitation packet + * Process received ICMPv6 echo reply packet * - * @v netdev Network device - * @v src Source address - * @v dest Destination address + * @v iobuf I/O buffer + * @v netdev Network device + * @v sin6_src Source socket address + * @v sin6_dest Destination socket address + * @ret rc Return status code + */ +static int icmpv6_rx_echo_reply ( struct io_buffer *iobuf, + struct net_device *netdev __unused, + struct sockaddr_in6 *sin6_src, + struct sockaddr_in6 *sin6_dest __unused ) { + struct sockaddr_tcpip *st_src = + ( ( struct sockaddr_tcpip * ) sin6_src ); + + return icmp_rx_echo_reply ( iobuf, st_src ); +} + +/** ICMPv6 echo reply handler */ +struct icmpv6_handler icmpv6_echo_reply_handler __icmpv6_handler = { + .type = ICMPV6_ECHO_REPLY, + .rx = icmpv6_rx_echo_reply, +}; + +/** + * Identify ICMPv6 handler * - * This function prepares a neighbour solicitation packet and sends it to the - * network layer. + * @v type ICMPv6 type + * @ret handler ICMPv6 handler, or NULL if not found */ -int icmp6_send_solicit ( struct net_device *netdev, struct in6_addr *src __unused, - struct in6_addr *dest ) { - union { - struct sockaddr_in6 sin6; - struct sockaddr_tcpip st; - } st_dest; - struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct neighbour_solicit *nsolicit; - struct io_buffer *iobuf = alloc_iob ( sizeof ( *nsolicit ) + MIN_IOB_LEN ); - iob_reserve ( iobuf, MAX_HDR_LEN ); - nsolicit = iob_put ( iobuf, sizeof ( *nsolicit ) ); - - /* Fill up the headers */ - memset ( nsolicit, 0, sizeof ( *nsolicit ) ); - nsolicit->type = ICMP6_NSOLICIT; - nsolicit->code = 0; - nsolicit->target = *dest; - nsolicit->opt_type = 1; - nsolicit->opt_len = ( 2 + ll_protocol->ll_addr_len ) / 8; - memcpy ( nsolicit->opt_ll_addr, netdev->ll_addr, - netdev->ll_protocol->ll_addr_len ); - /* Partial checksum */ - nsolicit->csum = 0; - nsolicit->csum = tcpip_chksum ( nsolicit, sizeof ( *nsolicit ) ); - - /* Solicited multicast address */ - st_dest.sin6.sin_family = AF_INET6; - st_dest.sin6.sin6_addr.in6_u.u6_addr8[0] = 0xff; - st_dest.sin6.sin6_addr.in6_u.u6_addr8[2] = 0x02; - st_dest.sin6.sin6_addr.in6_u.u6_addr16[1] = 0x0000; - st_dest.sin6.sin6_addr.in6_u.u6_addr32[1] = 0x00000000; - st_dest.sin6.sin6_addr.in6_u.u6_addr16[4] = 0x0000; - st_dest.sin6.sin6_addr.in6_u.u6_addr16[5] = 0x0001; - st_dest.sin6.sin6_addr.in6_u.u6_addr32[3] = dest->in6_u.u6_addr32[3]; - st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff; - - /* Send packet over IP6 */ - return tcpip_tx ( iobuf, &icmp6_protocol, NULL, &st_dest.st, - NULL, &nsolicit->csum ); +static struct icmpv6_handler * icmpv6_handler ( unsigned int type ) { + struct icmpv6_handler *handler; + + for_each_table_entry ( handler, ICMPV6_HANDLERS ) { + if ( handler->type == type ) + return handler; + } + return NULL; } /** - * Process ICMP6 headers + * Process a received packet * - * @v iobuf I/O buffer - * @v st_src Source address - * @v st_dest Destination address + * @v iobuf I/O buffer + * @v netdev Network device + * @v st_src Partially-filled source address + * @v st_dest Partially-filled destination address + * @v pshdr_csum Pseudo-header checksum + * @ret rc Return status code */ -static int icmp6_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, - struct sockaddr_tcpip *st_dest, __unused uint16_t pshdr_csum ) { - struct icmp6_header *icmp6hdr = iobuf->data; +static int icmpv6_rx ( struct io_buffer *iobuf, struct net_device *netdev, + struct sockaddr_tcpip *st_src, + struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) { + struct sockaddr_in6 *sin6_src = ( ( struct sockaddr_in6 * ) st_src ); + struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest ); + struct icmp_header *icmp = iobuf->data; + size_t len = iob_len ( iobuf ); + struct icmpv6_handler *handler; + unsigned int csum; + int rc; /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *icmp6hdr ) ) { - DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) ); - free_iob ( iobuf ); - return -EINVAL; + if ( len < sizeof ( *icmp ) ) { + DBGC ( netdev, "ICMPv6 packet too short at %zd bytes (min %zd " + "bytes)\n", len, sizeof ( *icmp ) ); + rc = -EINVAL; + goto done; } - /* TODO: Verify checksum */ + /* Verify checksum */ + csum = tcpip_continue_chksum ( pshdr_csum, icmp, len ); + if ( csum != 0 ) { + DBGC ( netdev, "ICMPv6 checksum incorrect (is %04x, should be " + "0000)\n", csum ); + DBGC_HDA ( netdev, 0, icmp, len ); + rc = -EINVAL; + goto done; + } - /* Process the ICMP header */ - switch ( icmp6hdr->type ) { - case ICMP6_NADVERT: - return ndp_process_advert ( iobuf, st_src, st_dest ); + /* Identify handler */ + handler = icmpv6_handler ( icmp->type ); + if ( ! handler ) { + DBGC ( netdev, "ICMPv6 unrecognised type %d\n", icmp->type ); + rc = -ENOTSUP; + goto done; } - return -ENOSYS; -} -#if 0 -void icmp6_test_nadvert (struct net_device *netdev, struct sockaddr_in6 *server_p, char *ll_addr) { - - struct sockaddr_in6 server; - memcpy ( &server, server_p, sizeof ( server ) ); - struct io_buffer *rxiobuf = alloc_iob ( 500 ); - iob_reserve ( rxiobuf, MAX_HDR_LEN ); - struct neighbour_advert *nadvert = iob_put ( rxiobuf, sizeof ( *nadvert ) ); - nadvert->type = 136; - nadvert->code = 0; - nadvert->flags = ICMP6_FLAGS_SOLICITED; - nadvert->csum = 0xffff; - nadvert->target = server.sin6_addr; - nadvert->opt_type = 2; - nadvert->opt_len = 1; - memcpy ( nadvert->opt_ll_addr, ll_addr, 6 ); - struct ip6_header *ip6hdr = iob_push ( rxiobuf, sizeof ( *ip6hdr ) ); - ip6hdr->ver_traffic_class_flow_label = htonl ( 0x60000000 ); - ip6hdr->hop_limit = 255; - ip6hdr->nxt_hdr = 58; - ip6hdr->payload_len = htons ( sizeof ( *nadvert ) ); - ip6hdr->src = server.sin6_addr; - ip6hdr->dest = server.sin6_addr; - hex_dump ( rxiobuf->data, iob_len ( rxiobuf ) ); - net_rx ( rxiobuf, netdev, htons ( ETH_P_IPV6 ), ll_addr ); + /* Pass to handler */ + if ( ( rc = handler->rx ( iob_disown ( iobuf ), netdev, sin6_src, + sin6_dest ) ) != 0 ) { + DBGC ( netdev, "ICMPv6 could not handle type %d: %s\n", + icmp->type, strerror ( rc ) ); + goto done; + } + + done: + free_iob ( iobuf ); + return rc; } -#endif -/** ICMP6 protocol */ -struct tcpip_protocol icmp6_protocol __tcpip_protocol = { - .name = "ICMP6", - .rx = icmp6_rx, - .tcpip_proto = IP_ICMP6, // 58 +/** ICMPv6 TCP/IP protocol */ +struct tcpip_protocol icmpv6_protocol __tcpip_protocol = { + .name = "ICMPv6", + .rx = icmpv6_rx, + .tcpip_proto = IP_ICMP6, +}; + +/** ICMPv6 echo protocol */ +struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol = { + .family = AF_INET6, + .request = ICMPV6_ECHO_REQUEST, + .reply = ICMPV6_ECHO_REPLY, + .tcpip_protocol = &icmpv6_protocol, + .net_checksum = 1, }; diff --git a/roms/ipxe/src/net/ipv4.c b/roms/ipxe/src/net/ipv4.c index 791d41951..9c5cf2eb4 100644 --- a/roms/ipxe/src/net/ipv4.c +++ b/roms/ipxe/src/net/ipv4.c @@ -14,7 +14,9 @@ #include <ipxe/tcpip.h> #include <ipxe/dhcp.h> #include <ipxe/settings.h> -#include <ipxe/timer.h> +#include <ipxe/fragment.h> +#include <ipxe/ipstat.h> +#include <ipxe/profile.h> /** @file * @@ -30,11 +32,21 @@ static uint8_t next_ident_high = 0; /** List of IPv4 miniroutes */ struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes ); -/** List of fragment reassembly buffers */ -static LIST_HEAD ( ipv4_fragments ); +/** IPv4 statistics */ +static struct ip_statistics ipv4_stats; -/** Fragment reassembly timeout */ -#define IP_FRAG_TIMEOUT ( TICKS_PER_SEC / 2 ) +/** IPv4 statistics family */ +struct ip_statistics_family +ipv4_stats_family __ip_statistics_family ( IP_STATISTICS_IPV4 ) = { + .version = 4, + .stats = &ipv4_stats, +}; + +/** Transmit profiler */ +static struct profiler ipv4_tx_profiler __profiler = { .name = "ipv4.tx" }; + +/** Receive profiler */ +static struct profiler ipv4_rx_profiler __profiler = { .name = "ipv4.rx" }; /** * Add IPv4 minirouting table entry @@ -133,131 +145,79 @@ static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) { } /** - * Expire fragment reassembly buffer + * Determine transmitting network device * - * @v timer Retry timer - * @v fail Failure indicator + * @v st_dest Destination network-layer address + * @ret netdev Transmitting network device, or NULL */ -static void ipv4_fragment_expired ( struct retry_timer *timer, - int fail __unused ) { - struct ipv4_fragment *frag = - container_of ( timer, struct ipv4_fragment, timer ); - struct iphdr *iphdr = frag->iobuf->data; - - DBGC ( iphdr->src, "IPv4 fragment %04x expired\n", - ntohs ( iphdr->ident ) ); - free_iob ( frag->iobuf ); - list_del ( &frag->list ); - free ( frag ); +static struct net_device * ipv4_netdev ( struct sockaddr_tcpip *st_dest ) { + struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest ); + struct in_addr dest = sin_dest->sin_addr; + struct ipv4_miniroute *miniroute; + + /* Find routing table entry */ + miniroute = ipv4_route ( &dest ); + if ( ! miniroute ) + return NULL; + + return miniroute->netdev; } /** - * Find matching fragment reassembly buffer + * Check if IPv4 fragment matches fragment reassembly buffer * - * @v iphdr IPv4 header - * @ret frag Fragment reassembly buffer, or NULL + * @v fragment Fragment reassembly buffer + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret is_fragment Fragment matches this reassembly buffer */ -static struct ipv4_fragment * ipv4_fragment ( struct iphdr *iphdr ) { - struct ipv4_fragment *frag; - struct iphdr *frag_iphdr; - - list_for_each_entry ( frag, &ipv4_fragments, list ) { - frag_iphdr = frag->iobuf->data; - - if ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) && - ( iphdr->ident == frag_iphdr->ident ) ) { - return frag; - } - } +static int ipv4_is_fragment ( struct fragment *fragment, + struct io_buffer *iobuf, + size_t hdrlen __unused ) { + struct iphdr *frag_iphdr = fragment->iobuf->data; + struct iphdr *iphdr = iobuf->data; - return NULL; + return ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) && + ( iphdr->ident == frag_iphdr->ident ) ); } /** - * Fragment reassembler + * Get IPv4 fragment offset * * @v iobuf I/O buffer - * @ret iobuf Reassembled packet, or NULL + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret offset Offset */ -static struct io_buffer * ipv4_reassemble ( struct io_buffer *iobuf ) { +static size_t ipv4_fragment_offset ( struct io_buffer *iobuf, + size_t hdrlen __unused ) { struct iphdr *iphdr = iobuf->data; - size_t offset = ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 ); - unsigned int more_frags = ( iphdr->frags & htons ( IP_MASK_MOREFRAGS )); - size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); - struct ipv4_fragment *frag; - size_t expected_offset; - struct io_buffer *new_iobuf; - - /* Find matching fragment reassembly buffer, if any */ - frag = ipv4_fragment ( iphdr ); - - /* Drop out-of-order fragments */ - expected_offset = ( frag ? frag->offset : 0 ); - if ( offset != expected_offset ) { - DBGC ( iphdr->src, "IPv4 dropping out-of-sequence fragment " - "%04x (%zd+%zd, expected %zd)\n", - ntohs ( iphdr->ident ), offset, - ( iob_len ( iobuf ) - hdrlen ), expected_offset ); - goto drop; - } - - /* Create or extend fragment reassembly buffer as applicable */ - if ( frag == NULL ) { - - /* Create new fragment reassembly buffer */ - frag = zalloc ( sizeof ( *frag ) ); - if ( ! frag ) - goto drop; - list_add ( &frag->list, &ipv4_fragments ); - frag->iobuf = iobuf; - frag->offset = ( iob_len ( iobuf ) - hdrlen ); - timer_init ( &frag->timer, ipv4_fragment_expired, NULL ); - - } else { - - /* Extend reassembly buffer */ - iob_pull ( iobuf, hdrlen ); - new_iobuf = alloc_iob ( iob_len ( frag->iobuf ) + - iob_len ( iobuf ) ); - if ( ! new_iobuf ) { - DBGC ( iphdr->src, "IPv4 could not extend reassembly " - "buffer to %zd bytes\n", - iob_len ( frag->iobuf ) + iob_len ( iobuf ) ); - goto drop; - } - memcpy ( iob_put ( new_iobuf, iob_len ( frag->iobuf ) ), - frag->iobuf->data, iob_len ( frag->iobuf ) ); - memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ), - iobuf->data, iob_len ( iobuf ) ); - free_iob ( frag->iobuf ); - frag->iobuf = new_iobuf; - frag->offset += iob_len ( iobuf ); - free_iob ( iobuf ); - iphdr = frag->iobuf->data; - iphdr->len = ntohs ( iob_len ( frag->iobuf ) ); - - /* Stop fragment reassembly timer */ - stop_timer ( &frag->timer ); - - /* If this is the final fragment, return it */ - if ( ! more_frags ) { - iobuf = frag->iobuf; - list_del ( &frag->list ); - free ( frag ); - return iobuf; - } - } - /* (Re)start fragment reassembly timer */ - start_timer_fixed ( &frag->timer, IP_FRAG_TIMEOUT ); + return ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 ); +} - return NULL; +/** + * Check if more fragments exist + * + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret more_frags More fragments exist + */ +static int ipv4_more_fragments ( struct io_buffer *iobuf, + size_t hdrlen __unused ) { + struct iphdr *iphdr = iobuf->data; - drop: - free_iob ( iobuf ); - return NULL; + return ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ); } +/** IPv4 fragment reassembler */ +static struct fragment_reassembler ipv4_reassembler = { + .list = LIST_HEAD_INIT ( ipv4_reassembler.list ), + .is_fragment = ipv4_is_fragment, + .fragment_offset = ipv4_fragment_offset, + .more_fragments = ipv4_more_fragments, + .stats = &ipv4_stats, +}; + /** * Add IPv4 pseudo-header checksum to existing checksum * @@ -310,6 +270,12 @@ static int ipv4_tx ( struct io_buffer *iobuf, const void *ll_dest; int rc; + /* Start profiling */ + profile_start ( &ipv4_tx_profiler ); + + /* Update statistics */ + ipv4_stats.out_requests++; + /* Fill up the IP header, except source address */ memset ( iphdr, 0, sizeof ( *iphdr ) ); iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) ); @@ -333,6 +299,7 @@ static int ipv4_tx ( struct io_buffer *iobuf, if ( ! netdev ) { DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) ); + ipv4_stats.out_no_routes++; rc = -ENETUNREACH; goto err; } @@ -360,15 +327,17 @@ static int ipv4_tx ( struct io_buffer *iobuf, /* Calculate link-layer destination address, if possible */ if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){ /* Broadcast address */ + ipv4_stats.out_bcast_pkts++; ll_dest = netdev->ll_broadcast; } else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) { /* Multicast address */ + ipv4_stats.out_mcast_pkts++; if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop, ll_dest_buf ) ) !=0){ DBGC ( sin_dest->sin_addr, "IPv4 could not hash " "multicast %s: %s\n", inet_ntoa ( next_hop ), strerror ( rc ) ); - return rc; + goto err; } ll_dest = ll_dest_buf; } else { @@ -376,6 +345,10 @@ static int ipv4_tx ( struct io_buffer *iobuf, ll_dest = NULL; } + /* Update statistics */ + ipv4_stats.out_transmits++; + ipv4_stats.out_octets += iob_len ( iobuf ); + /* Hand off to link layer (via ARP if applicable) */ if ( ll_dest ) { if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest, @@ -395,6 +368,7 @@ static int ipv4_tx ( struct io_buffer *iobuf, } } + profile_stop ( &ipv4_tx_profiler ); return 0; err: @@ -467,43 +441,56 @@ static int ipv4_rx ( struct io_buffer *iobuf, uint16_t pshdr_csum; int rc; + /* Start profiling */ + profile_start ( &ipv4_rx_profiler ); + + /* Update statistics */ + ipv4_stats.in_receives++; + ipv4_stats.in_octets += iob_len ( iobuf ); + if ( flags & LL_BROADCAST ) { + ipv4_stats.in_bcast_pkts++; + } else if ( flags & LL_MULTICAST ) { + ipv4_stats.in_mcast_pkts++; + } + /* Sanity check the IPv4 header */ if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) { DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min " "%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) ); - goto err; + goto err_header; } if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) { DBGC ( iphdr->src, "IPv4 version %#02x not supported\n", iphdr->verhdrlen ); - goto err; + goto err_header; } hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); if ( hdrlen < sizeof ( *iphdr ) ) { DBGC ( iphdr->src, "IPv4 header too short at %zd bytes (min " "%zd bytes)\n", hdrlen, sizeof ( *iphdr ) ); - goto err; + goto err_header; } if ( hdrlen > iob_len ( iobuf ) ) { DBGC ( iphdr->src, "IPv4 header too long at %zd bytes " "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) ); - goto err; + goto err_header; } if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) { DBGC ( iphdr->src, "IPv4 checksum incorrect (is %04x " "including checksum field, should be 0000)\n", csum ); - goto err; + goto err_header; } len = ntohs ( iphdr->len ); if ( len < hdrlen ) { DBGC ( iphdr->src, "IPv4 length too short at %zd bytes " "(header is %zd bytes)\n", len, hdrlen ); - goto err; + goto err_header; } if ( len > iob_len ( iobuf ) ) { DBGC ( iphdr->src, "IPv4 length too long at %zd bytes " "(packet is %zd bytes)\n", len, iob_len ( iobuf ) ); - goto err; + ipv4_stats.in_truncated_pkts++; + goto err_other; } /* Truncate packet to correct length */ @@ -521,19 +508,20 @@ static int ipv4_rx ( struct io_buffer *iobuf, ( ! ipv4_has_addr ( netdev, iphdr->dest ) ) ) { DBGC ( iphdr->src, "IPv4 discarding non-local unicast packet " "for %s\n", inet_ntoa ( iphdr->dest ) ); - goto err; + ipv4_stats.in_addr_errors++; + goto err_other; } /* Perform fragment reassembly if applicable */ if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) { - /* Pass the fragment to ipv4_reassemble() which returns + /* Pass the fragment to fragment_reassemble() which returns * either a fully reassembled I/O buffer or NULL. */ - iobuf = ipv4_reassemble ( iobuf ); + iobuf = fragment_reassemble ( &ipv4_reassembler, iobuf, + &hdrlen ); if ( ! iobuf ) return 0; iphdr = iobuf->data; - hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); } /* Construct socket addresses, calculate pseudo-header @@ -547,16 +535,19 @@ static int ipv4_rx ( struct io_buffer *iobuf, dest.sin.sin_addr = iphdr->dest; pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM ); iob_pull ( iobuf, hdrlen ); - if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st, - &dest.st, pshdr_csum ) ) != 0 ) { + if ( ( rc = tcpip_rx ( iobuf, netdev, iphdr->protocol, &src.st, + &dest.st, pshdr_csum, &ipv4_stats ) ) != 0 ) { DBGC ( src.sin.sin_addr, "IPv4 received packet rejected by " "stack: %s\n", strerror ( rc ) ); return rc; } + profile_stop ( &ipv4_rx_profiler ); return 0; - err: + err_header: + ipv4_stats.in_hdr_errors++; + err_other: free_iob ( iobuf ); return -EINVAL; } @@ -602,6 +593,36 @@ static const char * ipv4_ntoa ( const void *net_addr ) { return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) ); } +/** + * Transcribe IPv4 socket address + * + * @v sa Socket address + * @ret string Socket address in standard notation + */ +static const char * ipv4_sock_ntoa ( struct sockaddr *sa ) { + struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa ); + + return inet_ntoa ( sin->sin_addr ); +} + +/** + * Parse IPv4 socket address + * + * @v string Socket address string + * @v sa Socket address to fill in + * @ret rc Return status code + */ +static int ipv4_sock_aton ( const char *string, struct sockaddr *sa ) { + struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa ); + struct in_addr in; + + if ( inet_aton ( string, &in ) ) { + sin->sin_addr = in; + return 0; + } + return -EINVAL; +} + /** IPv4 protocol */ struct net_protocol ipv4_protocol __net_protocol = { .name = "IP", @@ -615,7 +636,9 @@ struct net_protocol ipv4_protocol __net_protocol = { struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = { .name = "IPv4", .sa_family = AF_INET, + .header_len = sizeof ( struct iphdr ), .tx = ipv4_tx, + .netdev = ipv4_netdev, }; /** IPv4 ARP protocol */ @@ -624,6 +647,13 @@ struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = { .check = ipv4_arp_check, }; +/** IPv4 socket address converter */ +struct sockaddr_converter ipv4_sockaddr_converter __sockaddr_converter = { + .family = AF_INET, + .ntoa = ipv4_sock_ntoa, + .aton = ipv4_sock_aton, +}; + /****************************************************************************** * * Settings @@ -631,8 +661,53 @@ struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = { ****************************************************************************** */ +/** + * Parse IPv4 address setting value + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ +int parse_ipv4_setting ( const struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { + struct in_addr ipv4; + + /* Parse IPv4 address */ + if ( inet_aton ( value, &ipv4 ) == 0 ) + return -EINVAL; + + /* Copy to buffer */ + if ( len > sizeof ( ipv4 ) ) + len = sizeof ( ipv4 ); + memcpy ( buf, &ipv4, len ); + + return ( sizeof ( ipv4 ) ); +} + +/** + * Format IPv4 address setting value + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +int format_ipv4_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, + size_t len ) { + const struct in_addr *ipv4 = raw; + + if ( raw_len < sizeof ( *ipv4 ) ) + return -EINVAL; + return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) ); +} + /** IPv4 address setting */ -struct setting ip_setting __setting ( SETTING_IPv4 ) = { +const struct setting ip_setting __setting ( SETTING_IP, ip ) = { .name = "ip", .description = "IP address", .tag = DHCP_EB_YIADDR, @@ -640,7 +715,7 @@ struct setting ip_setting __setting ( SETTING_IPv4 ) = { }; /** IPv4 subnet mask setting */ -struct setting netmask_setting __setting ( SETTING_IPv4 ) = { +const struct setting netmask_setting __setting ( SETTING_IP, netmask ) = { .name = "netmask", .description = "Subnet mask", .tag = DHCP_SUBNET_MASK, @@ -648,7 +723,7 @@ struct setting netmask_setting __setting ( SETTING_IPv4 ) = { }; /** Default gateway setting */ -struct setting gateway_setting __setting ( SETTING_IPv4 ) = { +const struct setting gateway_setting __setting ( SETTING_IP, gateway ) = { .name = "gateway", .description = "Default gateway", .tag = DHCP_ROUTERS, @@ -710,5 +785,5 @@ struct settings_applicator ipv4_settings_applicator __settings_applicator = { .apply = ipv4_create_routes, }; -/* Drag in ICMP */ -REQUIRE_OBJECT ( icmp ); +/* Drag in ICMPv4 */ +REQUIRE_OBJECT ( icmpv4 ); diff --git a/roms/ipxe/src/net/ipv6.c b/roms/ipxe/src/net/ipv6.c index 57bf94d8d..f753751df 100644 --- a/roms/ipxe/src/net/ipv6.c +++ b/roms/ipxe/src/net/ipv6.c @@ -1,370 +1,978 @@ -#include <errno.h> +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + #include <stdint.h> -#include <string.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> #include <byteswap.h> -#include <ipxe/in.h> -#include <ipxe/ip6.h> -#include <ipxe/ndp.h> -#include <ipxe/list.h> -#include <ipxe/icmp6.h> -#include <ipxe/tcpip.h> -#include <ipxe/socket.h> #include <ipxe/iobuf.h> -#include <ipxe/netdevice.h> +#include <ipxe/tcpip.h> #include <ipxe/if_ether.h> +#include <ipxe/crc32.h> +#include <ipxe/fragment.h> +#include <ipxe/ipstat.h> +#include <ipxe/ndp.h> +#include <ipxe/ipv6.h> -/* Unspecified IP6 address */ -static struct in6_addr ip6_none = { - .in6_u.u6_addr32 = { 0,0,0,0 } -}; +/** @file + * + * IPv6 protocol + * + */ -/** An IPv6 routing table entry */ -struct ipv6_miniroute { - /* List of miniroutes */ - struct list_head list; +/* Disambiguate the various error causes */ +#define EINVAL_LEN __einfo_error ( EINFO_EINVAL_LEN ) +#define EINFO_EINVAL_LEN \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid length" ) +#define ENOTSUP_VER __einfo_error ( EINFO_ENOTSUP_VER ) +#define EINFO_ENOTSUP_VER \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported version" ) +#define ENOTSUP_HDR __einfo_error ( EINFO_ENOTSUP_HDR ) +#define EINFO_ENOTSUP_HDR \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported header type" ) +#define ENOTSUP_OPT __einfo_error ( EINFO_ENOTSUP_OPT ) +#define EINFO_ENOTSUP_OPT \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x03, "Unsupported option" ) - /* Network device */ - struct net_device *netdev; +/** List of IPv6 miniroutes */ +struct list_head ipv6_miniroutes = LIST_HEAD_INIT ( ipv6_miniroutes ); - /* Destination prefix */ - struct in6_addr prefix; - /* Prefix length */ - int prefix_len; - /* IPv6 address of interface */ - struct in6_addr address; - /* Gateway address */ - struct in6_addr gateway; +/** IPv6 statistics */ +static struct ip_statistics ipv6_stats; + +/** IPv6 statistics family */ +struct ip_statistics_family +ipv6_statistics_family __ip_statistics_family ( IP_STATISTICS_IPV6 ) = { + .version = 6, + .stats = &ipv6_stats, }; -/** List of IPv6 miniroutes */ -static LIST_HEAD ( miniroutes ); +/** + * Determine debugging colour for IPv6 debug messages + * + * @v in IPv6 address + * @ret col Debugging colour (for DBGC()) + */ +static uint32_t ipv6col ( struct in6_addr *in ) { + return crc32_le ( 0, in, sizeof ( *in ) ); +} /** - * Add IPv6 minirouting table entry + * Dump IPv6 routing table entry + * + * @v miniroute Routing table entry + */ +static inline __attribute__ (( always_inline )) void +ipv6_dump_miniroute ( struct ipv6_miniroute *miniroute ) { + struct net_device *netdev = miniroute->netdev; + + DBGC ( netdev, "IPv6 %s has %s %s/%d", netdev->name, + ( ( miniroute->flags & IPV6_HAS_ADDRESS ) ? + "address" : "prefix" ), + inet6_ntoa ( &miniroute->address ), miniroute->prefix_len ); + if ( miniroute->flags & IPV6_HAS_ROUTER ) + DBGC ( netdev, " router %s", inet6_ntoa ( &miniroute->router )); + DBGC ( netdev, "\n" ); +} + +/** + * Check if network device has a specific IPv6 address * * @v netdev Network device - * @v prefix Destination prefix - * @v address Address of the interface - * @v gateway Gateway address (or ::0 for no gateway) - * @ret miniroute Routing table entry, or NULL + * @v addr IPv6 address + * @ret has_addr Network device has this IPv6 address */ -static struct ipv6_miniroute * __malloc -add_ipv6_miniroute ( struct net_device *netdev, struct in6_addr prefix, - int prefix_len, struct in6_addr address, - struct in6_addr gateway ) { +int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) { struct ipv6_miniroute *miniroute; - - miniroute = malloc ( sizeof ( *miniroute ) ); - if ( miniroute ) { - /* Record routing information */ - miniroute->netdev = netdev_get ( netdev ); - miniroute->prefix = prefix; - miniroute->prefix_len = prefix_len; - miniroute->address = address; - miniroute->gateway = gateway; - - /* Add miniroute to list of miniroutes */ - if ( !IP6_EQUAL ( gateway, ip6_none ) ) { - list_add_tail ( &miniroute->list, &miniroutes ); - } else { - list_add ( &miniroute->list, &miniroutes ); + + list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) { + if ( ( miniroute->netdev == netdev ) && + ( miniroute->flags & IPV6_HAS_ADDRESS ) && + ( memcmp ( &miniroute->address, addr, + sizeof ( miniroute->address ) ) == 0 ) ) { + /* Found matching address */ + return 1; } } - - return miniroute; + return 0; } /** - * Delete IPv6 minirouting table entry + * Check if IPv6 address is within a routing table entry's local network * * @v miniroute Routing table entry + * @v address IPv6 address + * @ret is_on_link Address is within this entry's local network */ -static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) { - netdev_put ( miniroute->netdev ); - list_del ( &miniroute->list ); - free ( miniroute ); +static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute, + struct in6_addr *address ) { + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) / + sizeof ( address->s6_addr32[0] ) ) ; i++ ) { + if ( (( address->s6_addr32[i] ^ miniroute->address.s6_addr32[i]) + & miniroute->prefix_mask.s6_addr32[i] ) != 0 ) + return 0; + } + return 1; } /** - * Add IPv6 interface + * Find IPv6 routing table entry for a given address * - * @v netdev Network device - * @v prefix Destination prefix - * @v address Address of the interface - * @v gateway Gateway address (or ::0 for no gateway) + * @v netdev Network device + * @v address IPv6 address + * @ret miniroute Routing table entry, or NULL if not found */ -int add_ipv6_address ( struct net_device *netdev, struct in6_addr prefix, - int prefix_len, struct in6_addr address, - struct in6_addr gateway ) { +static struct ipv6_miniroute * ipv6_miniroute ( struct net_device *netdev, + struct in6_addr *address ) { struct ipv6_miniroute *miniroute; - /* Clear any existing address for this net device */ - del_ipv6_address ( netdev ); + list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) { + if ( ( miniroute->netdev == netdev ) && + ipv6_is_on_link ( miniroute, address ) ) { + return miniroute; + } + } + return NULL; +} + +/** + * Add IPv6 routing table entry + * + * @v netdev Network device + * @v address IPv6 address (or prefix) + * @v prefix_len Prefix length + * @v flags Flags + * @ret miniroute Routing table entry, or NULL on failure + */ +static struct ipv6_miniroute * ipv6_add_miniroute ( struct net_device *netdev, + struct in6_addr *address, + unsigned int prefix_len, + unsigned int flags ) { + struct ipv6_miniroute *miniroute; + uint8_t *prefix_mask; + + /* Create routing table entry */ + miniroute = zalloc ( sizeof ( *miniroute ) ); + if ( ! miniroute ) + return NULL; + miniroute->netdev = netdev_get ( netdev ); + memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) ); + miniroute->prefix_len = prefix_len; + assert ( prefix_len <= ( 8 * sizeof ( miniroute->prefix_mask ) ) ); + for ( prefix_mask = miniroute->prefix_mask.s6_addr ; prefix_len >= 8 ; + prefix_mask++, prefix_len -= 8 ) { + *prefix_mask = 0xff; + } + if ( prefix_len ) + *prefix_mask <<= ( 8 - prefix_len ); + miniroute->flags = flags; + list_add ( &miniroute->list, &ipv6_miniroutes ); + ipv6_dump_miniroute ( miniroute ); + + return miniroute; +} + +/** + * Define IPv6 on-link prefix + * + * @v netdev Network device + * @v prefix IPv6 address prefix + * @v prefix_len Prefix length + * @v router Router address (or NULL) + * @ret rc Return status code + */ +int ipv6_set_prefix ( struct net_device *netdev, struct in6_addr *prefix, + unsigned int prefix_len, struct in6_addr *router ) { + struct ipv6_miniroute *miniroute; + int changed; - /* Add new miniroute */ - miniroute = add_ipv6_miniroute ( netdev, prefix, prefix_len, address, - gateway ); + /* Find or create routing table entry */ + miniroute = ipv6_miniroute ( netdev, prefix ); + if ( ! miniroute ) + miniroute = ipv6_add_miniroute ( netdev, prefix, prefix_len, 0); if ( ! miniroute ) return -ENOMEM; + /* Record router and add to start or end of list as appropriate */ + list_del ( &miniroute->list ); + if ( router ) { + changed = ( ( ! ( miniroute->flags & IPV6_HAS_ROUTER ) ) || + ( memcmp ( &miniroute->router, router, + sizeof ( miniroute->router ) ) != 0 ) ); + miniroute->flags |= IPV6_HAS_ROUTER; + memcpy ( &miniroute->router, router, + sizeof ( miniroute->router ) ); + list_add_tail ( &miniroute->list, &ipv6_miniroutes ); + } else { + changed = ( miniroute->flags & IPV6_HAS_ROUTER ); + miniroute->flags &= ~IPV6_HAS_ROUTER; + list_add ( &miniroute->list, &ipv6_miniroutes ); + } + if ( changed ) + ipv6_dump_miniroute ( miniroute ); + return 0; } /** - * Remove IPv6 interface + * Add IPv6 on-link address * - * @v netdev Network device + * @v netdev Network device + * @v address IPv6 address + * @ret rc Return status code + * + * An on-link prefix for the address must already exist. */ -void del_ipv6_address ( struct net_device *netdev ) { +int ipv6_set_address ( struct net_device *netdev, struct in6_addr *address ) { struct ipv6_miniroute *miniroute; + int changed; - list_for_each_entry ( miniroute, &miniroutes, list ) { - if ( miniroute->netdev == netdev ) { - del_ipv6_miniroute ( miniroute ); - break; + /* Find routing table entry */ + miniroute = ipv6_miniroute ( netdev, address ); + if ( ! miniroute ) + return -EADDRNOTAVAIL; + + /* Record address */ + changed = ( ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) || + ( memcmp ( &miniroute->address, address, + sizeof ( miniroute->address ) ) != 0 ) ); + memcpy ( &miniroute->address, address, sizeof ( miniroute->address ) ); + miniroute->flags |= IPV6_HAS_ADDRESS; + if ( changed ) + ipv6_dump_miniroute ( miniroute ); + + return 0; +} + +/** + * Perform IPv6 routing + * + * @v scope_id Destination address scope ID (for link-local addresses) + * @v dest Final destination address + * @ret dest Next hop destination address + * @ret miniroute Routing table entry to use, or NULL if no route + */ +static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id, + struct in6_addr **dest ) { + struct ipv6_miniroute *miniroute; + + /* Find first usable route in routing table */ + list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) { + + /* Skip closed network devices */ + if ( ! netdev_is_open ( miniroute->netdev ) ) + continue; + + /* Skip routing table entries with no usable source address */ + if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) + continue; + + if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) || + IN6_IS_ADDR_MULTICAST ( *dest ) ) { + + /* If destination is non-global, and the scope ID + * matches this network device, then use this route. + */ + if ( miniroute->netdev->index == scope_id ) + return miniroute; + + } else { + + /* If destination is an on-link global + * address, then use this route. + */ + if ( ipv6_is_on_link ( miniroute, *dest ) ) + return miniroute; + + /* If destination is an off-link global + * address, and we have a default gateway, + * then use this route. + */ + if ( miniroute->flags & IPV6_HAS_ROUTER ) { + *dest = &miniroute->router; + return miniroute; + } } } + + return NULL; } /** - * Calculate TCPIP checksum + * Determine transmitting network device * - * @v iobuf I/O buffer - * @v tcpip TCP/IP protocol + * @v st_dest Destination network-layer address + * @ret netdev Transmitting network device, or NULL + */ +static struct net_device * ipv6_netdev ( struct sockaddr_tcpip *st_dest ) { + struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest ); + struct in6_addr *dest = &sin6_dest->sin6_addr; + struct ipv6_miniroute *miniroute; + + /* Find routing table entry */ + miniroute = ipv6_route ( sin6_dest->sin6_scope_id, &dest ); + if ( ! miniroute ) + return NULL; + + return miniroute->netdev; +} + +/** + * Check that received options can be safely ignored * - * This function constructs the pseudo header and completes the checksum in the - * upper layer header. + * @v iphdr IPv6 header + * @v options Options extension header + * @v len Maximum length of header + * @ret rc Return status code */ -static uint16_t ipv6_tx_csum ( struct io_buffer *iobuf, uint16_t csum ) { - struct ip6_header *ip6hdr = iobuf->data; - struct ipv6_pseudo_header pshdr; +static int ipv6_check_options ( struct ipv6_header *iphdr, + struct ipv6_options_header *options, + size_t len ) { + struct ipv6_option *option = options->options; + struct ipv6_option *end = ( ( ( void * ) options ) + len ); - /* Calculate pseudo header */ - memset ( &pshdr, 0, sizeof ( pshdr ) ); - pshdr.src = ip6hdr->src; - pshdr.dest = ip6hdr->dest; - pshdr.len = htons ( iob_len ( iobuf ) - sizeof ( *ip6hdr ) ); - pshdr.nxt_hdr = ip6hdr->nxt_hdr; + while ( option < end ) { + if ( ! IPV6_CAN_IGNORE_OPT ( option->type ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 unrecognised " + "option type %#02x:\n", option->type ); + DBGC_HDA ( ipv6col ( &iphdr->src ), 0, + options, len ); + return -ENOTSUP_OPT; + } + if ( option->type == IPV6_OPT_PAD1 ) { + option = ( ( ( void * ) option ) + 1 ); + } else { + option = ( ( ( void * ) option->value ) + option->len ); + } + } + return 0; +} - /* Update checksum value */ - return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) ); +/** + * Check if fragment matches fragment reassembly buffer + * + * @v fragment Fragment reassembly buffer + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret is_fragment Fragment matches this reassembly buffer + */ +static int ipv6_is_fragment ( struct fragment *fragment, + struct io_buffer *iobuf, size_t hdrlen ) { + struct ipv6_header *frag_iphdr = fragment->iobuf->data; + struct ipv6_fragment_header *frag_fhdr = + ( fragment->iobuf->data + fragment->hdrlen - + sizeof ( *frag_fhdr ) ); + struct ipv6_header *iphdr = iobuf->data; + struct ipv6_fragment_header *fhdr = + ( iobuf->data + hdrlen - sizeof ( *fhdr ) ); + + return ( ( memcmp ( &iphdr->src, &frag_iphdr->src, + sizeof ( iphdr->src ) ) == 0 ) && + ( fhdr->ident == frag_fhdr->ident ) ); } /** - * Dump IP6 header for debugging + * Get fragment offset * - * ip6hdr IPv6 header + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret offset Offset */ -void ipv6_dump ( struct ip6_header *ip6hdr ) { - DBG ( "IP6 %p src %s dest %s nxt_hdr %d len %d\n", ip6hdr, - inet6_ntoa ( ip6hdr->src ), inet6_ntoa ( ip6hdr->dest ), - ip6hdr->nxt_hdr, ntohs ( ip6hdr->payload_len ) ); +static size_t ipv6_fragment_offset ( struct io_buffer *iobuf, size_t hdrlen ) { + struct ipv6_fragment_header *fhdr = + ( iobuf->data + hdrlen - sizeof ( *fhdr ) ); + + return ( ntohs ( fhdr->offset_more ) & IPV6_MASK_OFFSET ); } /** - * Transmit IP6 packet + * Check if more fragments exist * - * iobuf I/O buffer - * tcpip TCP/IP protocol - * st_dest Destination socket address + * @v iobuf I/O buffer + * @v hdrlen Length of non-fragmentable potion of I/O buffer + * @ret more_frags More fragments exist + */ +static int ipv6_more_fragments ( struct io_buffer *iobuf, size_t hdrlen ) { + struct ipv6_fragment_header *fhdr = + ( iobuf->data + hdrlen - sizeof ( *fhdr ) ); + + return ( fhdr->offset_more & htons ( IPV6_MASK_MOREFRAGS ) ); +} + +/** Fragment reassembler */ +static struct fragment_reassembler ipv6_reassembler = { + .list = LIST_HEAD_INIT ( ipv6_reassembler.list ), + .is_fragment = ipv6_is_fragment, + .fragment_offset = ipv6_fragment_offset, + .more_fragments = ipv6_more_fragments, + .stats = &ipv6_stats, +}; + +/** + * Calculate IPv6 pseudo-header checksum * - * This function prepends the IPv6 headers to the payload an transmits it. + * @v iphdr IPv6 header + * @v len Payload length + * @v next_header Next header type + * @v csum Existing checksum + * @ret csum Updated checksum + */ +static uint16_t ipv6_pshdr_chksum ( struct ipv6_header *iphdr, size_t len, + int next_header, uint16_t csum ) { + struct ipv6_pseudo_header pshdr; + + /* Build pseudo-header */ + memcpy ( &pshdr.src, &iphdr->src, sizeof ( pshdr.src ) ); + memcpy ( &pshdr.dest, &iphdr->dest, sizeof ( pshdr.dest ) ); + pshdr.len = htonl ( len ); + memset ( pshdr.zero, 0, sizeof ( pshdr.zero ) ); + pshdr.next_header = next_header; + + /* Update the checksum value */ + return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) ); +} + +/** + * Transmit IPv6 packet + * + * @v iobuf I/O buffer + * @v tcpip Transport-layer protocol + * @v st_src Source network-layer address + * @v st_dest Destination network-layer address + * @v netdev Network device to use if no route found, or NULL + * @v trans_csum Transport-layer checksum to complete, or NULL + * @ret rc Status + * + * This function expects a transport-layer segment and prepends the + * IPv6 header */ static int ipv6_tx ( struct io_buffer *iobuf, - struct tcpip_protocol *tcpip, - struct sockaddr_tcpip *st_src __unused, + struct tcpip_protocol *tcpip_protocol, + struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ) { - struct sockaddr_in6 *dest = ( struct sockaddr_in6* ) st_dest; - struct in6_addr next_hop; + struct sockaddr_in6 *sin6_src = ( ( struct sockaddr_in6 * ) st_src ); + struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest ); struct ipv6_miniroute *miniroute; + struct ipv6_header *iphdr; + struct in6_addr *src = NULL; + struct in6_addr *next_hop; uint8_t ll_dest_buf[MAX_LL_ADDR_LEN]; - const uint8_t *ll_dest = ll_dest_buf; + const void *ll_dest; + size_t len; int rc; - /* Construct the IPv6 packet */ - struct ip6_header *ip6hdr = iob_push ( iobuf, sizeof ( *ip6hdr ) ); - memset ( ip6hdr, 0, sizeof ( *ip6hdr) ); - ip6hdr->ver_traffic_class_flow_label = htonl ( 0x60000000 );//IP6_VERSION; - ip6hdr->payload_len = htons ( iob_len ( iobuf ) - sizeof ( *ip6hdr ) ); - ip6hdr->nxt_hdr = tcpip->tcpip_proto; - ip6hdr->hop_limit = IP6_HOP_LIMIT; // 255 - - /* Determine the next hop address and interface - * - * TODO: Implement the routing table. - */ - next_hop = dest->sin6_addr; - list_for_each_entry ( miniroute, &miniroutes, list ) { - if ( ( memcmp ( &ip6hdr->dest, &miniroute->prefix, - miniroute->prefix_len ) == 0 ) || - ( IP6_EQUAL ( miniroute->gateway, ip6_none ) ) ) { - netdev = miniroute->netdev; - ip6hdr->src = miniroute->address; - if ( ! ( IS_UNSPECIFIED ( miniroute->gateway ) ) ) { - next_hop = miniroute->gateway; - } - break; - } + /* Update statistics */ + ipv6_stats.out_requests++; + + /* Fill up the IPv6 header, except source address */ + len = iob_len ( iobuf ); + iphdr = iob_push ( iobuf, sizeof ( *iphdr ) ); + memset ( iphdr, 0, sizeof ( *iphdr ) ); + iphdr->ver_tc_label = htonl ( IPV6_VER ); + iphdr->len = htons ( len ); + iphdr->next_header = tcpip_protocol->tcpip_proto; + iphdr->hop_limit = IPV6_HOP_LIMIT; + memcpy ( &iphdr->dest, &sin6_dest->sin6_addr, sizeof ( iphdr->dest ) ); + + /* Use routing table to identify next hop and transmitting netdev */ + next_hop = &iphdr->dest; + if ( ( miniroute = ipv6_route ( sin6_dest->sin6_scope_id, + &next_hop ) ) != NULL ) { + src = &miniroute->address; + netdev = miniroute->netdev; } - /* No network interface identified */ - if ( !netdev ) { - DBG ( "No route to host %s\n", inet6_ntoa ( ip6hdr->dest ) ); + if ( ! netdev ) { + DBGC ( ipv6col ( &iphdr->dest ), "IPv6 has no route to %s\n", + inet6_ntoa ( &iphdr->dest ) ); + ipv6_stats.out_no_routes++; rc = -ENETUNREACH; goto err; } + if ( sin6_src && ! IN6_IS_ADDR_UNSPECIFIED ( &sin6_src->sin6_addr ) ) + src = &sin6_src->sin6_addr; + memcpy ( &iphdr->src, src, sizeof ( iphdr->src ) ); - /* Complete the transport layer checksum */ - if ( trans_csum ) - *trans_csum = ipv6_tx_csum ( iobuf, *trans_csum ); - - /* Print IPv6 header */ - ipv6_dump ( ip6hdr ); - - /* Resolve link layer address */ - if ( next_hop.in6_u.u6_addr8[0] == 0xff ) { - ll_dest_buf[0] = 0x33; - ll_dest_buf[1] = 0x33; - ll_dest_buf[2] = next_hop.in6_u.u6_addr8[12]; - ll_dest_buf[3] = next_hop.in6_u.u6_addr8[13]; - ll_dest_buf[4] = next_hop.in6_u.u6_addr8[14]; - ll_dest_buf[5] = next_hop.in6_u.u6_addr8[15]; - } else { - /* Unicast address needs to be resolved by NDP */ - if ( ( rc = ndp_resolve ( netdev, &next_hop, &ip6hdr->src, - ll_dest_buf ) ) != 0 ) { - DBG ( "No entry for %s\n", inet6_ntoa ( next_hop ) ); + /* Fix up checksums */ + if ( trans_csum ) { + *trans_csum = ipv6_pshdr_chksum ( iphdr, len, + tcpip_protocol->tcpip_proto, + *trans_csum ); + } + + /* Print IPv6 header for debugging */ + DBGC2 ( ipv6col ( &iphdr->dest ), "IPv6 TX %s->", + inet6_ntoa ( &iphdr->src ) ); + DBGC2 ( ipv6col ( &iphdr->dest ), "%s len %zd next %d\n", + inet6_ntoa ( &iphdr->dest ), len, iphdr->next_header ); + + /* Calculate link-layer destination address, if possible */ + if ( IN6_IS_ADDR_MULTICAST ( next_hop ) ) { + /* Multicast address */ + ipv6_stats.out_mcast_pkts++; + if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET6, next_hop, + ll_dest_buf ) ) !=0){ + DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not hash " + "multicast %s: %s\n", inet6_ntoa ( next_hop ), + strerror ( rc ) ); goto err; } + ll_dest = ll_dest_buf; + } else { + /* Unicast address */ + ll_dest = NULL; + } + + /* Update statistics */ + ipv6_stats.out_transmits++; + ipv6_stats.out_octets += iob_len ( iobuf ); + + /* Hand off to link layer (via NDP if applicable) */ + if ( ll_dest ) { + if ( ( rc = net_tx ( iobuf, netdev, &ipv6_protocol, ll_dest, + netdev->ll_addr ) ) != 0 ) { + DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not " + "transmit packet via %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } + } else { + if ( ( rc = ndp_tx ( iobuf, netdev, next_hop, &iphdr->src, + netdev->ll_addr ) ) != 0 ) { + DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not " + "transmit packet via %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } } - /* Transmit packet */ - return net_tx ( iobuf, netdev, &ipv6_protocol, ll_dest, - netdev->ll_addr ); + return 0; - err: + err: free_iob ( iobuf ); return rc; } /** - * Process next IP6 header - * - * @v iobuf I/O buffer - * @v nxt_hdr Next header number - * @v src Source socket address - * @v dest Destination socket address - * - * Refer http://www.iana.org/assignments/ipv6-parameters for the numbers - */ -static int ipv6_process_nxt_hdr ( struct io_buffer *iobuf, uint8_t nxt_hdr, - struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest ) { - switch ( nxt_hdr ) { - case IP6_HOPBYHOP: - case IP6_ROUTING: - case IP6_FRAGMENT: - case IP6_AUTHENTICATION: - case IP6_DEST_OPTS: - case IP6_ESP: - DBG ( "Function not implemented for header %d\n", nxt_hdr ); - return -ENOSYS; - case IP6_ICMP6: - break; - case IP6_NO_HEADER: - DBG ( "No next header\n" ); - return 0; - } - /* Next header is not a IPv6 extension header */ - return tcpip_rx ( iobuf, nxt_hdr, src, dest, 0 /* fixme */ ); -} - -/** - * Process incoming IP6 packets + * Process incoming IPv6 packets * * @v iobuf I/O buffer * @v netdev Network device * @v ll_dest Link-layer destination address - * @v ll_source Link-layer source address + * @v ll_source Link-layer destination source * @v flags Packet flags + * @ret rc Return status code * - * This function processes a IPv6 packet + * This function expects an IPv6 network datagram. It processes the + * headers and sends it to the transport layer. */ -static int ipv6_rx ( struct io_buffer *iobuf, - __unused struct net_device *netdev, - __unused const void *ll_dest, - __unused const void *ll_source, - __unused unsigned int flags ) { - - struct ip6_header *ip6hdr = iobuf->data; +static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_dest __unused, + const void *ll_source __unused, + unsigned int flags __unused ) { + struct ipv6_header *iphdr = iobuf->data; + union ipv6_extension_header *ext; union { struct sockaddr_in6 sin6; struct sockaddr_tcpip st; } src, dest; + uint16_t pshdr_csum; + size_t len; + size_t hdrlen; + size_t extlen; + int this_header; + int next_header; + int rc; - /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *ip6hdr ) ) { - DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) ); - goto drop; + /* Update statistics */ + ipv6_stats.in_receives++; + ipv6_stats.in_octets += iob_len ( iobuf ); + if ( flags & LL_BROADCAST ) { + ipv6_stats.in_bcast_pkts++; + } else if ( flags & LL_MULTICAST ) { + ipv6_stats.in_mcast_pkts++; } - /* TODO: Verify checksum */ - - /* Print IP6 header for debugging */ - ipv6_dump ( ip6hdr ); + /* Sanity check the IPv6 header */ + if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 packet too short at %zd " + "bytes (min %zd bytes)\n", iob_len ( iobuf ), + sizeof ( *iphdr ) ); + rc = -EINVAL_LEN; + goto err_header; + } + if ( ( iphdr->ver_tc_label & htonl ( IPV6_MASK_VER ) ) != + htonl ( IPV6_VER ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 version %#08x not " + "supported\n", ntohl ( iphdr->ver_tc_label ) ); + rc = -ENOTSUP_VER; + goto err_header; + } - /* Check header version */ - if ( ( ip6hdr->ver_traffic_class_flow_label & 0xf0000000 ) != 0x60000000 ) { - DBG ( "Invalid protocol version\n" ); - goto drop; + /* Truncate packet to specified length */ + len = ntohs ( iphdr->len ); + if ( len > iob_len ( iobuf ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 length too long at %zd " + "bytes (packet is %zd bytes)\n", len, iob_len ( iobuf )); + ipv6_stats.in_truncated_pkts++; + rc = -EINVAL_LEN; + goto err_other; } + iob_unput ( iobuf, ( iob_len ( iobuf ) - len - sizeof ( *iphdr ) ) ); + hdrlen = sizeof ( *iphdr ); + + /* Print IPv6 header for debugging */ + DBGC2 ( ipv6col ( &iphdr->src ), "IPv6 RX %s<-", + inet6_ntoa ( &iphdr->dest ) ); + DBGC2 ( ipv6col ( &iphdr->src ), "%s len %zd next %d\n", + inet6_ntoa ( &iphdr->src ), len, iphdr->next_header ); - /* Check the payload length */ - if ( ntohs ( ip6hdr->payload_len ) > iob_len ( iobuf ) ) { - DBG ( "Inconsistent packet length (%d bytes)\n", - ip6hdr->payload_len ); - goto drop; + /* Discard unicast packets not destined for us */ + if ( ( ! ( flags & LL_MULTICAST ) ) && + ( ! ipv6_has_addr ( netdev, &iphdr->dest ) ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 discarding non-local " + "unicast packet for %s\n", inet6_ntoa ( &iphdr->dest ) ); + ipv6_stats.in_addr_errors++; + rc = -EPIPE; + goto err_other; } - /* Ignore the traffic class and flow control values */ + /* Process any extension headers */ + next_header = iphdr->next_header; + while ( 1 ) { - /* Construct socket address */ + /* Extract extension header */ + this_header = next_header; + ext = ( iobuf->data + hdrlen ); + extlen = sizeof ( ext->pad ); + if ( iob_len ( iobuf ) < ( hdrlen + extlen ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 too short for " + "extension header type %d at %zd bytes (min " + "%zd bytes)\n", this_header, + ( iob_len ( iobuf ) - hdrlen ), extlen ); + rc = -EINVAL_LEN; + goto err_header; + } + + /* Determine size of extension header (if applicable) */ + if ( ( this_header == IPV6_HOPBYHOP ) || + ( this_header == IPV6_DESTINATION ) || + ( this_header == IPV6_ROUTING ) ) { + /* Length field is present */ + extlen += ext->common.len; + } else if ( this_header == IPV6_FRAGMENT ) { + /* Length field is reserved and ignored (RFC2460) */ + } else { + /* Not an extension header; assume rest is payload */ + break; + } + if ( iob_len ( iobuf ) < ( hdrlen + extlen ) ) { + DBGC ( ipv6col ( &iphdr->src ), "IPv6 too short for " + "extension header type %d at %zd bytes (min " + "%zd bytes)\n", this_header, + ( iob_len ( iobuf ) - hdrlen ), extlen ); + rc = -EINVAL_LEN; + goto err_header; + } + hdrlen += extlen; + next_header = ext->common.next_header; + DBGC2 ( ipv6col ( &iphdr->src ), "IPv6 RX %s<-", + inet6_ntoa ( &iphdr->dest ) ); + DBGC2 ( ipv6col ( &iphdr->src ), "%s ext type %d len %zd next " + "%d\n", inet6_ntoa ( &iphdr->src ), this_header, + extlen, next_header ); + + /* Process this extension header */ + if ( ( this_header == IPV6_HOPBYHOP ) || + ( this_header == IPV6_DESTINATION ) ) { + + /* Check that all options can be ignored */ + if ( ( rc = ipv6_check_options ( iphdr, &ext->options, + extlen ) ) != 0 ) + goto err_header; + + } else if ( this_header == IPV6_FRAGMENT ) { + + /* Reassemble fragments */ + iobuf = fragment_reassemble ( &ipv6_reassembler, iobuf, + &hdrlen ); + if ( ! iobuf ) + return 0; + iphdr = iobuf->data; + } + } + + /* Construct socket address, calculate pseudo-header checksum, + * and hand off to transport layer + */ memset ( &src, 0, sizeof ( src ) ); - src.sin6.sin_family = AF_INET6; - src.sin6.sin6_addr = ip6hdr->src; + src.sin6.sin6_family = AF_INET6; + memcpy ( &src.sin6.sin6_addr, &iphdr->src, + sizeof ( src.sin6.sin6_addr ) ); + src.sin6.sin6_scope_id = netdev->index; memset ( &dest, 0, sizeof ( dest ) ); - dest.sin6.sin_family = AF_INET6; - dest.sin6.sin6_addr = ip6hdr->dest; - - /* Strip header */ - iob_unput ( iobuf, iob_len ( iobuf ) - ntohs ( ip6hdr->payload_len ) - - sizeof ( *ip6hdr ) ); - iob_pull ( iobuf, sizeof ( *ip6hdr ) ); + dest.sin6.sin6_family = AF_INET6; + memcpy ( &dest.sin6.sin6_addr, &iphdr->dest, + sizeof ( dest.sin6.sin6_addr ) ); + dest.sin6.sin6_scope_id = netdev->index; + iob_pull ( iobuf, hdrlen ); + pshdr_csum = ipv6_pshdr_chksum ( iphdr, iob_len ( iobuf ), + next_header, TCPIP_EMPTY_CSUM ); + if ( ( rc = tcpip_rx ( iobuf, netdev, next_header, &src.st, &dest.st, + pshdr_csum, &ipv6_stats ) ) != 0 ) { + DBGC ( ipv6col ( &src.sin6.sin6_addr ), "IPv6 received packet " + "rejected by stack: %s\n", strerror ( rc ) ); + return rc; + } - /* Send it to the transport layer */ - return ipv6_process_nxt_hdr ( iobuf, ip6hdr->nxt_hdr, &src.st, &dest.st ); + return 0; - drop: - DBG ( "Packet dropped\n" ); + err_header: + ipv6_stats.in_hdr_errors++; + err_other: free_iob ( iobuf ); - return -1; + return rc; +} + +/** + * Parse IPv6 address + * + * @v string IPv6 address string + * @ret in IPv6 address to fill in + * @ret rc Return status code + */ +int inet6_aton ( const char *string, struct in6_addr *in ) { + uint16_t *word = in->s6_addr16; + uint16_t *end = ( word + ( sizeof ( in->s6_addr16 ) / + sizeof ( in->s6_addr16[0] ) ) ); + uint16_t *pad = NULL; + const char *nptr = string; + char *endptr; + unsigned long value; + size_t pad_len; + size_t move_len; + + /* Parse string */ + while ( 1 ) { + + /* Parse current word */ + value = strtoul ( nptr, &endptr, 16 ); + if ( value > 0xffff ) { + DBG ( "IPv6 invalid word value %#lx in \"%s\"\n", + value, string ); + return -EINVAL; + } + *(word++) = htons ( value ); + + /* Parse separator */ + if ( ! *endptr ) + break; + if ( *endptr != ':' ) { + DBG ( "IPv6 invalid separator '%c' in \"%s\"\n", + *endptr, string ); + return -EINVAL; + } + if ( ( endptr == nptr ) && ( nptr != string ) ) { + if ( pad ) { + DBG ( "IPv6 invalid multiple \"::\" in " + "\"%s\"\n", string ); + return -EINVAL; + } + pad = word; + } + nptr = ( endptr + 1 ); + + /* Check for overrun */ + if ( word == end ) { + DBG ( "IPv6 too many words in \"%s\"\n", string ); + return -EINVAL; + } + } + + /* Insert padding if specified */ + if ( pad ) { + move_len = ( ( ( void * ) word ) - ( ( void * ) pad ) ); + pad_len = ( ( ( void * ) end ) - ( ( void * ) word ) ); + memmove ( ( ( ( void * ) pad ) + pad_len ), pad, move_len ); + memset ( pad, 0, pad_len ); + } else if ( word != end ) { + DBG ( "IPv6 underlength address \"%s\"\n", string ); + return -EINVAL; + } + + return 0; } /** - * Print a IP6 address as xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx + * Convert IPv6 address to standard notation + * + * @v in IPv6 address + * @ret string IPv6 address string in canonical format + * + * RFC5952 defines the canonical format for IPv6 textual representation. */ -char * inet6_ntoa ( struct in6_addr in6 ) { - static char buf[40]; - uint16_t *bytes = ( uint16_t* ) &in6; - sprintf ( buf, "%x:%x:%x:%x:%x:%x:%x:%x", bytes[0], bytes[1], bytes[2], - bytes[3], bytes[4], bytes[5], bytes[6], bytes[7] ); - return buf; +char * inet6_ntoa ( const struct in6_addr *in ) { + static char buf[41]; /* ":xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" */ + char *out = buf; + char *longest_start = NULL; + char *start = NULL; + int longest_len = 1; + int len = 0; + char *dest; + unsigned int i; + uint16_t value; + + /* Format address, keeping track of longest run of zeros */ + for ( i = 0 ; i < ( sizeof ( in->s6_addr16 ) / + sizeof ( in->s6_addr16[0] ) ) ; i++ ) { + value = ntohs ( in->s6_addr16[i] ); + if ( value == 0 ) { + if ( len++ == 0 ) + start = out; + if ( len > longest_len ) { + longest_start = start; + longest_len = len; + } + } else { + len = 0; + } + out += sprintf ( out, ":%x", value ); + } + + /* Abbreviate longest run of zeros, if applicable */ + if ( longest_start ) { + dest = strcpy ( ( longest_start + 1 ), + ( longest_start + ( 2 * longest_len ) ) ); + if ( dest[0] == '\0' ) + dest[1] = '\0'; + dest[0] = ':'; + } + return ( ( longest_start == buf ) ? buf : ( buf + 1 ) ); } +/** + * Transcribe IPv6 address + * + * @v net_addr IPv6 address + * @ret string IPv6 address in standard notation + * + */ static const char * ipv6_ntoa ( const void *net_addr ) { - return inet6_ntoa ( * ( ( struct in6_addr * ) net_addr ) ); + return inet6_ntoa ( net_addr ); +} + +/** + * Transcribe IPv6 socket address + * + * @v sa Socket address + * @ret string Socket address in standard notation + */ +static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) { + static char buf[ 39 /* "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" */ + + 1 /* "%" */ + NETDEV_NAME_LEN + 1 /* NUL */ ]; + struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) sa ); + struct in6_addr *in = &sin6->sin6_addr; + struct net_device *netdev; + const char *netdev_name; + + /* Identify network device, if applicable */ + if ( IN6_IS_ADDR_LINKLOCAL ( in ) ) { + netdev = find_netdev_by_index ( sin6->sin6_scope_id ); + netdev_name = ( netdev ? netdev->name : "UNKNOWN" ); + } else { + netdev_name = NULL; + } + + /* Format socket address */ + snprintf ( buf, sizeof ( buf ), "%s%s%s", inet6_ntoa ( in ), + ( netdev_name ? "%" : "" ), + ( netdev_name ? netdev_name : "" ) ); + return buf; +} + +/** + * Parse IPv6 socket address + * + * @v string Socket address string + * @v sa Socket address to fill in + * @ret rc Return status code + */ +static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) { + struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) sa ); + struct in6_addr in; + struct net_device *netdev; + size_t len; + char *tmp; + char *in_string; + char *netdev_string; + int rc; + + /* Create modifiable copy of string */ + tmp = strdup ( string ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + in_string = tmp; + + /* Strip surrounding "[...]", if present */ + len = strlen ( in_string ); + if ( ( in_string[0] == '[' ) && ( in_string[ len - 1 ] == ']' ) ) { + in_string[ len - 1 ] = '\0'; + in_string++; + } + + /* Split at network device name, if present */ + netdev_string = strchr ( in_string, '%' ); + if ( netdev_string ) + *(netdev_string++) = '\0'; + + /* Parse IPv6 address portion */ + if ( ( rc = inet6_aton ( in_string, &in ) ) != 0 ) + goto err_inet6_aton; + + /* Parse network device name, if present */ + if ( netdev_string ) { + netdev = find_netdev ( netdev_string ); + if ( ! netdev ) { + rc = -ENODEV; + goto err_find_netdev; + } + sin6->sin6_scope_id = netdev->index; + } + + /* Copy IPv6 address portion to socket address */ + memcpy ( &sin6->sin6_addr, &in, sizeof ( sin6->sin6_addr ) ); + + err_find_netdev: + err_inet6_aton: + free ( tmp ); + err_alloc: + return rc; } /** IPv6 protocol */ @@ -380,5 +988,123 @@ struct net_protocol ipv6_protocol __net_protocol = { struct tcpip_net_protocol ipv6_tcpip_protocol __tcpip_net_protocol = { .name = "IPv6", .sa_family = AF_INET6, + .header_len = sizeof ( struct ipv6_header ), .tx = ipv6_tx, + .netdev = ipv6_netdev, +}; + +/** IPv6 socket address converter */ +struct sockaddr_converter ipv6_sockaddr_converter __sockaddr_converter = { + .family = AF_INET6, + .ntoa = ipv6_sock_ntoa, + .aton = ipv6_sock_aton, }; + +/** + * Parse IPv6 address setting value + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ +int parse_ipv6_setting ( const struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { + struct in6_addr ipv6; + int rc; + + /* Parse IPv6 address */ + if ( ( rc = inet6_aton ( value, &ipv6 ) ) != 0 ) + return rc; + + /* Copy to buffer */ + if ( len > sizeof ( ipv6 ) ) + len = sizeof ( ipv6 ); + memcpy ( buf, &ipv6, len ); + + return ( sizeof ( ipv6 ) ); +} + +/** + * Format IPv6 address setting value + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +int format_ipv6_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, + size_t len ) { + const struct in6_addr *ipv6 = raw; + + if ( raw_len < sizeof ( *ipv6 ) ) + return -EINVAL; + return snprintf ( buf, len, "%s", inet6_ntoa ( ipv6 ) ); +} + +/** + * Create IPv6 network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int ipv6_probe ( struct net_device *netdev ) { + struct ipv6_miniroute *miniroute; + struct in6_addr address; + int prefix_len; + int rc; + + /* Construct link-local address from EUI-64 as per RFC 2464 */ + memset ( &address, 0, sizeof ( address ) ); + prefix_len = ipv6_link_local ( &address, netdev ); + if ( prefix_len < 0 ) { + rc = prefix_len; + DBGC ( netdev, "IPv6 %s could not construct link-local " + "address: %s\n", netdev->name, strerror ( rc ) ); + return rc; + } + + /* Create link-local address for this network device */ + miniroute = ipv6_add_miniroute ( netdev, &address, prefix_len, + IPV6_HAS_ADDRESS ); + if ( ! miniroute ) + return -ENOMEM; + + return 0; +} + +/** + * Destroy IPv6 network device + * + * @v netdev Network device + */ +static void ipv6_remove ( struct net_device *netdev ) { + struct ipv6_miniroute *miniroute; + struct ipv6_miniroute *tmp; + + /* Delete all miniroutes for this network device */ + list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) { + if ( miniroute->netdev == netdev ) { + netdev_put ( miniroute->netdev ); + list_del ( &miniroute->list ); + free ( miniroute ); + } + } +} + +/** IPv6 network device driver */ +struct net_driver ipv6_driver __net_driver = { + .name = "IPv6", + .probe = ipv6_probe, + .remove = ipv6_remove, +}; + +/* Drag in ICMPv6 */ +REQUIRE_OBJECT ( icmpv6 ); + +/* Drag in NDP */ +REQUIRE_OBJECT ( ndp ); diff --git a/roms/ipxe/src/net/ndp.c b/roms/ipxe/src/net/ndp.c index 4d3713353..6450aa9f0 100644 --- a/roms/ipxe/src/net/ndp.c +++ b/roms/ipxe/src/net/ndp.c @@ -1,180 +1,1011 @@ -#include <stdint.h> +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdlib.h> #include <string.h> -#include <byteswap.h> #include <errno.h> -#include <ipxe/if_ether.h> +#include <byteswap.h> +#include <ipxe/in.h> #include <ipxe/iobuf.h> +#include <ipxe/tcpip.h> +#include <ipxe/ipv6.h> +#include <ipxe/icmpv6.h> +#include <ipxe/neighbour.h> +#include <ipxe/dhcpv6.h> #include <ipxe/ndp.h> -#include <ipxe/icmp6.h> -#include <ipxe/ip6.h> -#include <ipxe/netdevice.h> /** @file * - * Neighbour Discovery Protocol + * IPv6 neighbour discovery protocol + * + */ + +static int +ipv6conf_rx_router_advertisement ( struct net_device *netdev, + struct ndp_router_advertisement_header *radv, + size_t len ); + +/** + * Transmit NDP packet with link-layer address option * - * This file implements address resolution as specified by the neighbour - * discovery protocol in RFC2461. This protocol is part of the IPv6 protocol - * family. + * @v netdev Network device + * @v sin6_src Source socket address + * @v sin6_dest Destination socket address + * @v data NDP header + * @v len Size of NDP header + * @v option_type NDP option type + * @ret rc Return status code */ +static int ndp_tx_ll_addr ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + struct sockaddr_in6 *sin6_dest, + const void *data, size_t len, + unsigned int option_type ) { + struct sockaddr_tcpip *st_src = + ( ( struct sockaddr_tcpip * ) sin6_src ); + struct sockaddr_tcpip *st_dest = + ( ( struct sockaddr_tcpip * ) sin6_dest ); + struct ll_protocol *ll_protocol = netdev->ll_protocol; + struct io_buffer *iobuf; + struct ndp_ll_addr_option *ll_addr_opt; + union ndp_header *ndp; + size_t option_len; + int rc; + + /* Allocate and populate buffer */ + option_len = ( ( sizeof ( *ll_addr_opt ) + + ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) & + ~( NDP_OPTION_BLKSZ - 1 ) ); + iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len ); + if ( ! iobuf ) + return -ENOMEM; + iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); + memcpy ( iob_put ( iobuf, len ), data, len ); + ll_addr_opt = iob_put ( iobuf, option_len ); + ll_addr_opt->header.type = option_type; + ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ ); + memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr, + ll_protocol->ll_addr_len ); + ndp = iobuf->data; + ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) ); + + /* Transmit packet */ + if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest, + netdev, &ndp->icmp.chksum ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not transmit packet: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Transmit NDP neighbour discovery request + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @ret rc Return status code + */ +static int ndp_tx_request ( struct net_device *netdev, + struct net_protocol *net_protocol __unused, + const void *net_dest, const void *net_source ) { + struct sockaddr_in6 sin6_src; + struct sockaddr_in6 sin6_dest; + struct ndp_neighbour_header neigh; + int rc; + + /* Construct source address */ + memset ( &sin6_src, 0, sizeof ( sin6_src ) ); + sin6_src.sin6_family = AF_INET6; + memcpy ( &sin6_src.sin6_addr, net_source, + sizeof ( sin6_src.sin6_addr ) ); + sin6_src.sin6_scope_id = netdev->index; + + /* Construct multicast destination address */ + memset ( &sin6_dest, 0, sizeof ( sin6_dest ) ); + sin6_dest.sin6_family = AF_INET6; + sin6_dest.sin6_scope_id = netdev->index; + ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest ); + + /* Construct neighbour header */ + memset ( &neigh, 0, sizeof ( neigh ) ); + neigh.icmp.type = ICMPV6_NEIGHBOUR_SOLICITATION; + memcpy ( &neigh.target, net_dest, sizeof ( neigh.target ) ); + + /* Transmit neighbour discovery packet */ + if ( ( rc = ndp_tx_ll_addr ( netdev, &sin6_src, &sin6_dest, &neigh, + sizeof ( neigh ), + NDP_OPT_LL_SOURCE ) ) != 0 ) + return rc; + + return 0; +} -/* A neighbour entry */ -struct ndp_entry { - /** Target IP6 address */ - struct in6_addr in6; - /** Link layer protocol */ - struct ll_protocol *ll_protocol; - /** Link-layer address */ - uint8_t ll_addr[MAX_LL_ADDR_LEN]; - /** State of the neighbour entry */ - int state; +/** NDP neighbour discovery protocol */ +struct neighbour_discovery ndp_discovery = { + .name = "NDP", + .tx_request = ndp_tx_request, }; -/** Number of entries in the neighbour cache table */ -#define NUM_NDP_ENTRIES 4 +/** + * Transmit NDP router solicitation + * + * @v netdev Network device + * @ret rc Return status code + */ +static int ndp_tx_router_solicitation ( struct net_device *netdev ) { + struct ndp_router_solicitation_header rsol; + struct sockaddr_in6 sin6_dest; + int rc; + + /* Construct multicast destination address */ + memset ( &sin6_dest, 0, sizeof ( sin6_dest ) ); + sin6_dest.sin6_family = AF_INET6; + sin6_dest.sin6_scope_id = netdev->index; + ipv6_all_routers ( &sin6_dest.sin6_addr ); + + /* Construct router solicitation */ + memset ( &rsol, 0, sizeof ( rsol ) ); + rsol.icmp.type = ICMPV6_ROUTER_SOLICITATION; -/** The neighbour cache table */ -static struct ndp_entry ndp_table[NUM_NDP_ENTRIES]; -#define ndp_table_end &ndp_table[NUM_NDP_ENTRIES] + /* Transmit packet */ + if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, &sin6_dest, &rsol, + sizeof ( rsol ), NDP_OPT_LL_SOURCE ) ) !=0) + return rc; -static unsigned int next_new_ndp_entry = 0; + return 0; +} /** - * Find entry in the neighbour cache + * Process NDP neighbour solicitation source link-layer address option * - * @v in6 IP6 address + * @v netdev Network device + * @v sin6_src Source socket address + * @v ndp NDP packet + * @v option NDP option + * @v len NDP option length + * @ret rc Return status code */ -static struct ndp_entry * -ndp_find_entry ( struct in6_addr *in6 ) { - struct ndp_entry *ndp; +static int +ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + union ndp_header *ndp, + union ndp_option *option, + size_t len ) { + struct ndp_neighbour_header *neigh = &ndp->neigh; + struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; - for ( ndp = ndp_table ; ndp < ndp_table_end ; ndp++ ) { - if ( IP6_EQUAL ( ( *in6 ), ndp->in6 ) && - ( ndp->state != NDP_STATE_INVALID ) ) { - return ndp; - } + /* Silently ignore neighbour solicitations for addresses we do + * not own. + */ + if ( ! ipv6_has_addr ( netdev, &neigh->target ) ) + return 0; + + /* Sanity check */ + if ( offsetof ( typeof ( *ll_addr_opt ), + ll_addr[ll_protocol->ll_addr_len] ) > len ) { + DBGC ( netdev, "NDP %s neighbour solicitation link-layer " + "address option too short at %zd bytes\n", + netdev->name, len ); + return -EINVAL; } - return NULL; + + /* Create or update neighbour cache entry */ + if ( ( rc = neighbour_define ( netdev, &ipv6_protocol, + &sin6_src->sin6_addr, + ll_addr_opt->ll_addr ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not define %s => %s: %s\n", + netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ), + ll_protocol->ntoa ( ll_addr_opt->ll_addr ), + strerror ( rc ) ); + return rc; + } + + /* Convert neighbour header to advertisement */ + memset ( neigh, 0, offsetof ( typeof ( *neigh ), target ) ); + neigh->icmp.type = ICMPV6_NEIGHBOUR_ADVERTISEMENT; + neigh->flags = ( NDP_NEIGHBOUR_SOLICITED | NDP_NEIGHBOUR_OVERRIDE ); + + /* Send neighbour advertisement */ + if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, sin6_src, neigh, + sizeof ( *neigh ), + NDP_OPT_LL_TARGET ) ) != 0 ) + return rc; + + return 0; } /** - * Add NDP entry - * - * @v netdev Network device - * @v in6 IP6 address - * @v ll_addr Link-layer address - * @v state State of the entry - one of the NDP_STATE_XXX values + * Process NDP neighbour advertisement target link-layer address option + * + * @v netdev Network device + * @v sin6_src Source socket address + * @v ndp NDP packet + * @v option NDP option + * @v len NDP option length + * @ret rc Return status code */ -static void -add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6, - void *ll_addr, int state ) { - struct ndp_entry *ndp; - ndp = &ndp_table[next_new_ndp_entry++ % NUM_NDP_ENTRIES]; +static int +ndp_rx_neighbour_advertisement_ll_target ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src + __unused, + union ndp_header *ndp, + union ndp_option *option, + size_t len ) { + struct ndp_neighbour_header *neigh = &ndp->neigh; + struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; + + /* Sanity check */ + if ( offsetof ( typeof ( *ll_addr_opt ), + ll_addr[ll_protocol->ll_addr_len] ) > len ) { + DBGC ( netdev, "NDP %s neighbour advertisement link-layer " + "address option too short at %zd bytes\n", + netdev->name, len ); + return -EINVAL; + } - /* Fill up entry */ - ndp->ll_protocol = netdev->ll_protocol; - memcpy ( &ndp->in6, &( *in6 ), sizeof ( *in6 ) ); - if ( ll_addr ) { - memcpy ( ndp->ll_addr, ll_addr, netdev->ll_protocol->ll_addr_len ); - } else { - memset ( ndp->ll_addr, 0, netdev->ll_protocol->ll_addr_len ); + /* Update neighbour cache entry, if any */ + if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target, + ll_addr_opt->ll_addr ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not update %s => %s: %s\n", + netdev->name, inet6_ntoa ( &neigh->target ), + ll_protocol->ntoa ( ll_addr_opt->ll_addr ), + strerror ( rc ) ); + return rc; } - ndp->state = state; - DBG ( "New neighbour cache entry: IP6 %s => %s %s\n", - inet6_ntoa ( ndp->in6 ), netdev->ll_protocol->name, - netdev->ll_protocol->ntoa ( ndp->ll_addr ) ); + + return 0; } /** - * Resolve the link-layer address + * Process NDP router advertisement source link-layer address option * * @v netdev Network device - * @v dest Destination address - * @v src Source address - * @ret dest_ll_addr Destination link-layer address or NULL - * @ret rc Status - * - * This function looks up the neighbour cache for an entry corresponding to the - * destination address. If it finds a valid entry, it fills up dest_ll_addr and - * returns 0. Otherwise it sends a neighbour solicitation to the solicited - * multicast address. - */ -int ndp_resolve ( struct net_device *netdev, struct in6_addr *dest, - struct in6_addr *src, void *dest_ll_addr ) { + * @v sin6_src Source socket address + * @v ndp NDP packet + * @v option NDP option + * @v len NDP option length + * @ret rc Return status code + */ +static int +ndp_rx_router_advertisement_ll_source ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + union ndp_header *ndp __unused, + union ndp_option *option, size_t len ) { + struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr; struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct ndp_entry *ndp; int rc; - ndp = ndp_find_entry ( dest ); - /* Check if the entry is valid */ - if ( ndp && ndp->state == NDP_STATE_REACHABLE ) { - DBG ( "Neighbour cache hit: IP6 %s => %s %s\n", - inet6_ntoa ( *dest ), ll_protocol->name, - ll_protocol->ntoa ( ndp->ll_addr ) ); - memcpy ( dest_ll_addr, ndp->ll_addr, ll_protocol->ll_addr_len ); - return 0; + /* Sanity check */ + if ( offsetof ( typeof ( *ll_addr_opt ), + ll_addr[ll_protocol->ll_addr_len] ) > len ) { + DBGC ( netdev, "NDP %s router advertisement link-layer address " + "option too short at %zd bytes\n", netdev->name, len ); + return -EINVAL; } - /* Check if the entry was already created */ - if ( ndp ) { - DBG ( "Awaiting neighbour advertisement\n" ); - /* For test */ -// ndp->state = NDP_STATE_REACHABLE; -// memcpy ( ndp->ll_addr, netdev->ll_addr, 6 ); -// assert ( ndp->ll_protocol->ll_addr_len == 6 ); -// icmp6_test_nadvert ( netdev, dest, ndp->ll_addr ); -// assert ( ndp->state == NDP_STATE_REACHABLE ); - /* Take it out till here */ - return -ENOENT; + /* Define neighbour cache entry */ + if ( ( rc = neighbour_define ( netdev, &ipv6_protocol, + &sin6_src->sin6_addr, + ll_addr_opt->ll_addr ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not define %s => %s: %s\n", + netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ), + ll_protocol->ntoa ( ll_addr_opt->ll_addr ), + strerror ( rc ) ); + return rc; } - DBG ( "Neighbour cache miss: IP6 %s\n", inet6_ntoa ( *dest ) ); - /* Add entry in the neighbour cache */ - add_ndp_entry ( netdev, dest, NULL, NDP_STATE_INCOMPLETE ); + return 0; +} + +/** + * Process NDP router advertisement prefix information option + * + * @v netdev Network device + * @v sin6_src Source socket address + * @v ndp NDP packet + * @v option NDP option + * @v len NDP option length + * @ret rc Return status code + */ +static int +ndp_rx_router_advertisement_prefix ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + union ndp_header *ndp, + union ndp_option *option, size_t len ) { + struct ndp_router_advertisement_header *radv = &ndp->radv; + struct ndp_prefix_information_option *prefix_opt = &option->prefix; + struct in6_addr *router = &sin6_src->sin6_addr; + struct in6_addr address; + int prefix_len; + int rc; - /* Send neighbour solicitation */ - if ( ( rc = icmp6_send_solicit ( netdev, src, dest ) ) != 0 ) { + /* Sanity check */ + if ( sizeof ( *prefix_opt ) > len ) { + DBGC ( netdev, "NDP %s router advertisement prefix option too " + "short at %zd bytes\n", netdev->name, len ); + return -EINVAL; + } + DBGC ( netdev, "NDP %s found %sdefault router %s ", + netdev->name, ( radv->lifetime ? "" : "non-" ), + inet6_ntoa ( &sin6_src->sin6_addr ) ); + DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d\n", + ( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ), + ( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ), + inet6_ntoa ( &prefix_opt->prefix ), + prefix_opt->prefix_len ); + + /* Ignore off-link prefixes */ + if ( ! ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ) + return 0; + + /* Define prefix */ + if ( ( rc = ipv6_set_prefix ( netdev, &prefix_opt->prefix, + prefix_opt->prefix_len, + ( radv->lifetime ? + router : NULL ) ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not define prefix %s/%d: %s\n", + netdev->name, inet6_ntoa ( &prefix_opt->prefix ), + prefix_opt->prefix_len, strerror ( rc ) ); return rc; } - return -ENOENT; + + /* Perform stateless address autoconfiguration, if applicable */ + if ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) { + memcpy ( &address, &prefix_opt->prefix, sizeof ( address ) ); + prefix_len = ipv6_eui64 ( &address, netdev ); + if ( prefix_len < 0 ) { + rc = prefix_len; + DBGC ( netdev, "NDP %s could not construct SLAAC " + "address: %s\n", netdev->name, strerror ( rc ) ); + return rc; + } + if ( prefix_len != prefix_opt->prefix_len ) { + DBGC ( netdev, "NDP %s incorrect SLAAC prefix length " + "%d (expected %d)\n", netdev->name, + prefix_opt->prefix_len, prefix_len ); + return -EINVAL; + } + if ( ( rc = ipv6_set_address ( netdev, &address ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not set address %s: %s\n", + netdev->name, inet6_ntoa ( &address ), + strerror ( rc ) ); + return rc; + } + } + + return 0; +} + +/** An NDP option handler */ +struct ndp_option_handler { + /** ICMPv6 type */ + uint8_t icmp_type; + /** Option type */ + uint8_t option_type; + /** + * Handle received option + * + * @v netdev Network device + * @v sin6_src Source socket address + * @v ndp NDP packet + * @v option NDP option + * @ret rc Return status code + */ + int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src, + union ndp_header *ndp, union ndp_option *option, + size_t len ); +}; + +/** NDP option handlers */ +static struct ndp_option_handler ndp_option_handlers[] = { + { + .icmp_type = ICMPV6_NEIGHBOUR_SOLICITATION, + .option_type = NDP_OPT_LL_SOURCE, + .rx = ndp_rx_neighbour_solicitation_ll_source, + }, + { + .icmp_type = ICMPV6_NEIGHBOUR_ADVERTISEMENT, + .option_type = NDP_OPT_LL_TARGET, + .rx = ndp_rx_neighbour_advertisement_ll_target, + }, + { + .icmp_type = ICMPV6_ROUTER_ADVERTISEMENT, + .option_type = NDP_OPT_LL_SOURCE, + .rx = ndp_rx_router_advertisement_ll_source, + }, + { + .icmp_type = ICMPV6_ROUTER_ADVERTISEMENT, + .option_type = NDP_OPT_PREFIX, + .rx = ndp_rx_router_advertisement_prefix, + }, +}; + +/** + * Process received NDP option + * + * @v netdev Network device + * @v sin6_src Source socket address + * @v ndp NDP packet + * @v option NDP option + * @v len Option length + * @ret rc Return status code + */ +static int ndp_rx_option ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src, union ndp_header *ndp, + union ndp_option *option, size_t len ) { + struct ndp_option_handler *handler; + unsigned int i; + + /* Locate a suitable option handler, if any */ + for ( i = 0 ; i < ( sizeof ( ndp_option_handlers ) / + sizeof ( ndp_option_handlers[0] ) ) ; i++ ) { + handler = &ndp_option_handlers[i]; + if ( ( handler->icmp_type == ndp->icmp.type ) && + ( handler->option_type == option->header.type ) ) { + return handler->rx ( netdev, sin6_src, ndp, + option, len ); + } + } + + /* Silently ignore unknown options as per RFC 4861 */ + return 0; } /** - * Process neighbour advertisement + * Process received NDP packet options * - * @v iobuf I/O buffer - * @v st_src Source address - * @v st_dest Destination address + * @v netdev Network device + * @v sin6_src Source socket address + * @v ndp NDP header + * @v offset Offset to NDP options + * @v len Length of NDP packet + * @ret rc Return status code */ -int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src __unused, - struct sockaddr_tcpip *st_dest __unused ) { - struct neighbour_advert *nadvert = iobuf->data; - struct ndp_entry *ndp; +static int ndp_rx_options ( struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + union ndp_header *ndp, size_t offset, size_t len ) { + union ndp_option *option; + size_t remaining; + size_t option_len; + int rc; /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *nadvert ) ) { - DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) ); + if ( len < offset ) { + DBGC ( netdev, "NDP %s packet too short at %zd bytes (min %zd " + "bytes)\n", netdev->name, len, offset ); return -EINVAL; } - assert ( nadvert->code == 0 ); - assert ( nadvert->flags & ICMP6_FLAGS_SOLICITED ); - assert ( nadvert->opt_type == 2 ); + /* Search for option */ + option = ( ( ( void * ) ndp ) + offset ); + remaining = ( len - offset ); + while ( remaining ) { + + /* Sanity check */ + if ( ( remaining < sizeof ( option->header ) ) || + ( option->header.blocks == 0 ) || + ( remaining < ( option->header.blocks * + NDP_OPTION_BLKSZ ) ) ) { + DBGC ( netdev, "NDP %s bad option length:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, option, remaining ); + return -EINVAL; + } + option_len = ( option->header.blocks * NDP_OPTION_BLKSZ ); + + /* Handle option */ + if ( ( rc = ndp_rx_option ( netdev, sin6_src, ndp, option, + option_len ) ) != 0 ) + return rc; + + /* Move to next option */ + option = ( ( ( void * ) option ) + option_len ); + remaining -= option_len; + } + + return 0; +} + +/** + * Process received NDP neighbour solicitation or advertisement + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v sin6_src Source socket address + * @v sin6_dest Destination socket address + * @ret rc Return status code + */ +static int ndp_rx_neighbour ( struct io_buffer *iobuf, + struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + struct sockaddr_in6 *sin6_dest __unused ) { + union ndp_header *ndp = iobuf->data; + struct ndp_neighbour_header *neigh = &ndp->neigh; + size_t len = iob_len ( iobuf ); + int rc; + + /* Process options */ + if ( ( rc = ndp_rx_options ( netdev, sin6_src, ndp, + offsetof ( typeof ( *neigh ), option ), + len ) ) != 0 ) + goto err_options; + + err_options: + free_iob ( iobuf ); + return rc; +} + +/** + * Process received NDP router advertisement + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v sin6_src Source socket address + * @v sin6_dest Destination socket address + * @ret rc Return status code + */ +static int +ndp_rx_router_advertisement ( struct io_buffer *iobuf, + struct net_device *netdev, + struct sockaddr_in6 *sin6_src, + struct sockaddr_in6 *sin6_dest __unused ) { + union ndp_header *ndp = iobuf->data; + struct ndp_router_advertisement_header *radv = &ndp->radv; + size_t len = iob_len ( iobuf ); + int rc; + + /* Process options */ + if ( ( rc = ndp_rx_options ( netdev, sin6_src, ndp, + offsetof ( typeof ( *radv ), option ), + len ) ) != 0 ) + goto err_options; + + /* Pass to IPv6 autoconfiguration */ + if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, radv, + len ) ) != 0 ) + goto err_ipv6conf; + + err_ipv6conf: + err_options: + free_iob ( iobuf ); + return rc; +} + +/** NDP ICMPv6 handlers */ +struct icmpv6_handler ndp_handlers[] __icmpv6_handler = { + { + .type = ICMPV6_NEIGHBOUR_SOLICITATION, + .rx = ndp_rx_neighbour, + }, + { + .type = ICMPV6_NEIGHBOUR_ADVERTISEMENT, + .rx = ndp_rx_neighbour, + }, + { + .type = ICMPV6_ROUTER_ADVERTISEMENT, + .rx = ndp_rx_router_advertisement, + }, +}; + +/**************************************************************************** + * + * NDP settings + * + */ + +/** An NDP settings block */ +struct ndp_settings { + /** Reference counter */ + struct refcnt refcnt; + /** Settings interface */ + struct settings settings; + /** Length of NDP options */ + size_t len; + /** NDP options */ + union ndp_option option[0]; +}; + +/** NDP settings scope */ +static const struct settings_scope ndp_settings_scope; + +/** + * Construct NDP tag + * + * @v type NDP option type + * @v offset Starting offset of data + * @ret tag NDP tag + */ +#define NDP_TAG( type, offset ) ( ( (offset) << 8 ) | (type) ) + +/** + * Extract NDP tag type + * + * @v tag NDP tag + * @ret type NDP option type + */ +#define NDP_TAG_TYPE( tag ) ( (tag) & 0xff ) + +/** + * Extract NDP tag offset + * + * @v tag NDP tag + * @ret offset Starting offset of data + */ +#define NDP_TAG_OFFSET( tag ) ( (tag) >> 8 ) + +/** + * Check applicability of NDP setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @ret applies Setting applies within this settings block + */ +static int ndp_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &ndp_settings_scope ); +} + +/** + * Fetch value of NDP setting + * + * @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 + */ +static int ndp_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct ndp_settings *ndpset = + container_of ( settings, struct ndp_settings, settings ); + struct net_device *netdev = + container_of ( settings->parent, struct net_device, + settings.settings ); + union ndp_option *option; + unsigned int type = NDP_TAG_TYPE ( setting->tag ); + unsigned int offset = NDP_TAG_OFFSET ( setting->tag ); + size_t remaining; + size_t option_len; + size_t payload_len; + + /* Scan through NDP options for requested type. We can assume + * that the options are well-formed, otherwise they would have + * been rejected prior to being stored. + */ + option = ndpset->option; + remaining = ndpset->len; + while ( remaining ) { + + /* Calculate option length */ + option_len = ( option->header.blocks * NDP_OPTION_BLKSZ ); + + /* If this is the requested option, return it */ + if ( option->header.type == type ) { + + /* Sanity check */ + if ( offset > option_len ) { + DBGC ( netdev, "NDP %s option %d too short\n", + netdev->name, type ); + return -EINVAL; + } + payload_len = ( option_len - offset ); + + /* Copy data to output buffer */ + if ( len > payload_len ) + len = payload_len; + memcpy ( data, ( ( ( void * ) option ) + offset ), len); + return payload_len; + } + + /* Move to next option */ + option = ( ( ( void * ) option ) + option_len ); + remaining -= option_len; + } + + return -ENOENT; +} + +/** NDP settings operations */ +static struct settings_operations ndp_settings_operations = { + .applies = ndp_applies, + .fetch = ndp_fetch, +}; + +/** + * Register NDP settings + * + * @v netdev Network device + * @v option NDP options + * @v len Length of options + * @ret rc Return status code + */ +static int ndp_register_settings ( struct net_device *netdev, + union ndp_option *option, size_t len ) { + struct settings *parent = netdev_settings ( netdev ); + struct ndp_settings *ndpset; + int rc; + + /* Allocate and initialise structure */ + ndpset = zalloc ( sizeof ( *ndpset ) + len ); + if ( ! ndpset ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &ndpset->refcnt, NULL ); + settings_init ( &ndpset->settings, &ndp_settings_operations, + &ndpset->refcnt, &ndp_settings_scope ); + ndpset->len = len; + memcpy ( ndpset->option, option, len ); + + /* Register settings */ + if ( ( rc = register_settings ( &ndpset->settings, parent, + NDP_SETTINGS_NAME ) ) != 0 ) + goto err_register; + + err_register: + ref_put ( &ndpset->refcnt ); + err_alloc: + return rc; +} + +/** DNS server setting */ +const struct setting ndp_dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = { + .name = "dns6", + .description = "DNS server", + .tag = NDP_TAG ( NDP_OPT_RDNSS, + offsetof ( struct ndp_rdnss_option, addresses ) ), + .type = &setting_type_ipv6, + .scope = &ndp_settings_scope, +}; + +/** DNS search list setting */ +const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = { + .name = "dnssl", + .description = "DNS search list", + .tag = NDP_TAG ( NDP_OPT_DNSSL, + offsetof ( struct ndp_dnssl_option, names ) ), + .type = &setting_type_dnssl, + .scope = &ndp_settings_scope, +}; + +/**************************************************************************** + * + * IPv6 autoconfiguration + * + */ + +/** An IPv6 configurator */ +struct ipv6conf { + /** Reference count */ + struct refcnt refcnt; + /** List of configurators */ + struct list_head list; + + /** Job control interface */ + struct interface job; + /** DHCPv6 interface */ + struct interface dhcp; + + /** Network device being configured */ + struct net_device *netdev; + + /** Retransmission timer */ + struct retry_timer timer; +}; + +/** List of IPv6 configurators */ +static LIST_HEAD ( ipv6confs ); + +/** + * Free IPv6 configurator + * + * @v refcnt Reference count + */ +static void ipv6conf_free ( struct refcnt *refcnt ) { + struct ipv6conf *ipv6conf = + container_of ( refcnt, struct ipv6conf, refcnt ); + + netdev_put ( ipv6conf->netdev ); + free ( ipv6conf ); +} + +/** + * Identify IPv6 configurator by network device + * + * @v netdev Network device + * @ret ipv6 IPv6 configurator, or NULL + */ +static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev ) { + struct ipv6conf *ipv6conf; + + list_for_each_entry ( ipv6conf, &ipv6confs, list ) { + if ( ipv6conf->netdev == netdev ) + return ipv6conf; + } + return NULL; +} + +/** + * Finish IPv6 autoconfiguration + * + * @v ipv6 IPv6 configurator + * @v rc Reason for finishing + */ +static void ipv6conf_done ( struct ipv6conf *ipv6conf, int rc ) { + + /* Shut down interfaces */ + intf_shutdown ( &ipv6conf->job, rc ); + intf_shutdown ( &ipv6conf->dhcp, rc ); + + /* Stop timer */ + stop_timer ( &ipv6conf->timer ); + + /* Remove from list and drop list's reference */ + list_del ( &ipv6conf->list ); + ref_put ( &ipv6conf->refcnt ); +} + +/** + * Handle IPv6 configurator timer expiry + * + * @v timer Retry timer + * @v fail Failure indicator + */ +static void ipv6conf_expired ( struct retry_timer *timer, int fail ) { + struct ipv6conf *ipv6conf = + container_of ( timer, struct ipv6conf, timer ); + + /* If we have failed, terminate autoconfiguration */ + if ( fail ) { + ipv6conf_done ( ipv6conf, -ETIMEDOUT ); + return; + } + + /* Otherwise, transmit router solicitation and restart timer */ + start_timer ( &ipv6conf->timer ); + ndp_tx_router_solicitation ( ipv6conf->netdev ); +} + +/** + * Handle router advertisement during IPv6 autoconfiguration + * + * @v netdev Network device + * @v radv Router advertisement + * @v len Length of router advertisement + * @ret rc Return status code + * + * This function assumes that the router advertisement is well-formed, + * since it must have already passed through option processing. + */ +static int +ipv6conf_rx_router_advertisement ( struct net_device *netdev, + struct ndp_router_advertisement_header *radv, + size_t len ) { + struct ipv6conf *ipv6conf; + size_t option_len; + int stateful; + int rc; + + /* Identify IPv6 configurator, if any */ + ipv6conf = ipv6conf_demux ( netdev ); + if ( ! ipv6conf ) { + /* Not an error; router advertisements are processed + * as a background activity even when no explicit + * autoconfiguration is taking place. + */ + return 0; + } - /* Update the neighbour cache, if entry is present */ - ndp = ndp_find_entry ( &nadvert->target ); - if ( ndp ) { + /* If this is not the first solicited router advertisement, ignore it */ + if ( ! timer_running ( &ipv6conf->timer ) ) + return 0; - assert ( nadvert->opt_len == - ( ( 2 + ndp->ll_protocol->ll_addr_len ) / 8 ) ); + /* Stop router solicitation timer */ + stop_timer ( &ipv6conf->timer ); + + /* Register NDP settings */ + option_len = ( len - offsetof ( typeof ( *radv ), option ) ); + if ( ( rc = ndp_register_settings ( netdev, radv->option, + option_len ) ) != 0 ) + return rc; - if ( IP6_EQUAL ( ndp->in6, nadvert->target ) ) { - memcpy ( ndp->ll_addr, nadvert->opt_ll_addr, - ndp->ll_protocol->ll_addr_len ); - ndp->state = NDP_STATE_REACHABLE; - return 0; + /* Start DHCPv6 if required */ + if ( radv->flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) { + stateful = ( radv->flags & NDP_ROUTER_MANAGED ); + if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev, + stateful ) ) != 0 ) { + DBGC ( netdev, "NDP %s could not start state%s DHCPv6: " + "%s\n", netdev->name, + ( stateful ? "ful" : "less" ), strerror ( rc ) ); + ipv6conf_done ( ipv6conf, rc ); + return rc; } + return 0; } - DBG ( "Unsolicited advertisement (dropping packet)\n" ); + + /* Otherwise, terminate autoconfiguration */ + ipv6conf_done ( ipv6conf, 0 ); + return 0; } + +/** IPv6 configurator job interface operations */ +static struct interface_operation ipv6conf_job_op[] = { + INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ), +}; + +/** IPv6 configurator job interface descriptor */ +static struct interface_descriptor ipv6conf_job_desc = + INTF_DESC ( struct ipv6conf, job, ipv6conf_job_op ); + +/** IPv6 configurator DHCPv6 interface operations */ +static struct interface_operation ipv6conf_dhcp_op[] = { + INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ), +}; + +/** IPv6 configurator DHCPv6 interface descriptor */ +static struct interface_descriptor ipv6conf_dhcp_desc = + INTF_DESC ( struct ipv6conf, dhcp, ipv6conf_dhcp_op ); + +/** + * Start IPv6 autoconfiguration + * + * @v job Job control interface + * @v netdev Network device + * @ret rc Return status code + */ +int start_ipv6conf ( struct interface *job, struct net_device *netdev ) { + struct ipv6conf *ipv6conf; + + /* Allocate and initialise structure */ + ipv6conf = zalloc ( sizeof ( *ipv6conf ) ); + if ( ! ipv6conf ) + return -ENOMEM; + ref_init ( &ipv6conf->refcnt, ipv6conf_free ); + intf_init ( &ipv6conf->job, &ipv6conf_job_desc, &ipv6conf->refcnt ); + intf_init ( &ipv6conf->dhcp, &ipv6conf_dhcp_desc, &ipv6conf->refcnt ); + timer_init ( &ipv6conf->timer, ipv6conf_expired, &ipv6conf->refcnt ); + ipv6conf->netdev = netdev_get ( netdev ); + + /* Start timer to initiate router solicitation */ + start_timer_nodelay ( &ipv6conf->timer ); + + /* Attach parent interface, transfer reference to list, and return */ + intf_plug_plug ( &ipv6conf->job, job ); + list_add ( &ipv6conf->list, &ipv6confs ); + return 0; +} + +/** IPv6 network device configurator */ +struct net_device_configurator ipv6_configurator __net_device_configurator = { + .name = "ipv6", + .start = start_ipv6conf, +}; diff --git a/roms/ipxe/src/net/neighbour.c b/roms/ipxe/src/net/neighbour.c new file mode 100644 index 000000000..e3026ce46 --- /dev/null +++ b/roms/ipxe/src/net/neighbour.c @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ipxe/iobuf.h> +#include <ipxe/retry.h> +#include <ipxe/timer.h> +#include <ipxe/malloc.h> +#include <ipxe/neighbour.h> + +/** @file + * + * Neighbour discovery + * + * This file implements the abstract functions of neighbour discovery, + * independent of the underlying network protocol (e.g. ARP or NDP). + * + */ + +/** Neighbour discovery minimum timeout */ +#define NEIGHBOUR_MIN_TIMEOUT ( TICKS_PER_SEC / 8 ) + +/** Neighbour discovery maximum timeout */ +#define NEIGHBOUR_MAX_TIMEOUT ( TICKS_PER_SEC * 3 ) + +/** The neighbour cache */ +struct list_head neighbours = LIST_HEAD_INIT ( neighbours ); + +static void neighbour_expired ( struct retry_timer *timer, int over ); + +/** + * Free neighbour cache entry + * + * @v refcnt Reference count + */ +static void neighbour_free ( struct refcnt *refcnt ) { + struct neighbour *neighbour = + container_of ( refcnt, struct neighbour, refcnt ); + + /* Sanity check */ + assert ( list_empty ( &neighbour->tx_queue ) ); + + /* Drop reference to network device */ + netdev_put ( neighbour->netdev ); + + /* Free neighbour */ + free ( neighbour ); +} + +/** + * Create neighbour cache entry + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @ret neighbour Neighbour cache entry, or NULL if allocation failed + */ +static struct neighbour * neighbour_create ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest ) { + struct neighbour *neighbour; + + /* Allocate and initialise entry */ + neighbour = zalloc ( sizeof ( *neighbour ) ); + if ( ! neighbour ) + return NULL; + ref_init ( &neighbour->refcnt, neighbour_free ); + neighbour->netdev = netdev_get ( netdev ); + neighbour->net_protocol = net_protocol; + memcpy ( neighbour->net_dest, net_dest, + net_protocol->net_addr_len ); + timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt ); + neighbour->timer.min_timeout = NEIGHBOUR_MIN_TIMEOUT; + neighbour->timer.max_timeout = NEIGHBOUR_MAX_TIMEOUT; + INIT_LIST_HEAD ( &neighbour->tx_queue ); + + /* Transfer ownership to cache */ + list_add ( &neighbour->list, &neighbours ); + + DBGC ( neighbour, "NEIGHBOUR %s %s %s created\n", netdev->name, + net_protocol->name, net_protocol->ntoa ( net_dest ) ); + return neighbour; +} + +/** + * Find neighbour cache entry + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @ret neighbour Neighbour cache entry, or NULL if not found + */ +static struct neighbour * neighbour_find ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest ) { + struct neighbour *neighbour; + + list_for_each_entry ( neighbour, &neighbours, list ) { + if ( ( neighbour->netdev == netdev ) && + ( neighbour->net_protocol == net_protocol ) && + ( memcmp ( neighbour->net_dest, net_dest, + net_protocol->net_addr_len ) == 0 ) ) { + + /* Move to start of cache */ + list_del ( &neighbour->list ); + list_add ( &neighbour->list, &neighbours ); + + return neighbour; + } + } + return NULL; +} + +/** + * Start neighbour discovery + * + * @v neighbour Neighbour cache entry + * @v discovery Neighbour discovery protocol + * @v net_source Source network-layer address + */ +static void neighbour_discover ( struct neighbour *neighbour, + struct neighbour_discovery *discovery, + const void *net_source ) { + struct net_device *netdev = neighbour->netdev; + struct net_protocol *net_protocol = neighbour->net_protocol; + + /* Record discovery protocol and source network-layer address */ + neighbour->discovery = discovery; + memcpy ( neighbour->net_source, net_source, + net_protocol->net_addr_len ); + + /* Start timer to trigger neighbour discovery */ + start_timer_nodelay ( &neighbour->timer ); + + DBGC ( neighbour, "NEIGHBOUR %s %s %s discovering via %s\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( neighbour->net_dest ), + neighbour->discovery->name ); +} + +/** + * Complete neighbour discovery + * + * @v neighbour Neighbour cache entry + * @v ll_dest Destination link-layer address + */ +static void neighbour_discovered ( struct neighbour *neighbour, + const void *ll_dest ) { + struct net_device *netdev = neighbour->netdev; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + struct net_protocol *net_protocol = neighbour->net_protocol; + struct io_buffer *iobuf; + int rc; + + /* Fill in link-layer address */ + memcpy ( neighbour->ll_dest, ll_dest, ll_protocol->ll_addr_len ); + DBGC ( neighbour, "NEIGHBOUR %s %s %s is %s %s\n", netdev->name, + net_protocol->name, net_protocol->ntoa ( neighbour->net_dest ), + ll_protocol->name, ll_protocol->ntoa ( neighbour->ll_dest ) ); + + /* Stop retransmission timer */ + stop_timer ( &neighbour->timer ); + + /* Transmit any packets in queue. Take out a temporary + * reference on the entry to prevent it from going out of + * scope during the call to net_tx(). + */ + ref_get ( &neighbour->refcnt ); + while ( ( iobuf = list_first_entry ( &neighbour->tx_queue, + struct io_buffer, list )) != NULL){ + DBGC2 ( neighbour, "NEIGHBOUR %s %s %s transmitting deferred " + "packet\n", netdev->name, net_protocol->name, + net_protocol->ntoa ( neighbour->net_dest ) ); + list_del ( &iobuf->list ); + if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest, + netdev->ll_addr ) ) != 0 ) { + DBGC ( neighbour, "NEIGHBOUR %s %s %s could not " + "transmit deferred packet: %s\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( neighbour->net_dest ), + strerror ( rc ) ); + /* Ignore error and continue */ + } + } + ref_put ( &neighbour->refcnt ); +} + +/** + * Destroy neighbour cache entry + * + * @v neighbour Neighbour cache entry + * @v rc Reason for destruction + */ +static void neighbour_destroy ( struct neighbour *neighbour, int rc ) { + struct net_device *netdev = neighbour->netdev; + struct net_protocol *net_protocol = neighbour->net_protocol; + struct io_buffer *iobuf; + + /* Take ownership from cache */ + list_del ( &neighbour->list ); + + /* Stop timer */ + stop_timer ( &neighbour->timer ); + + /* Discard any outstanding I/O buffers */ + while ( ( iobuf = list_first_entry ( &neighbour->tx_queue, + struct io_buffer, list )) != NULL){ + DBGC2 ( neighbour, "NEIGHBOUR %s %s %s discarding deferred " + "packet: %s\n", netdev->name, net_protocol->name, + net_protocol->ntoa ( neighbour->net_dest ), + strerror ( rc ) ); + list_del ( &iobuf->list ); + netdev_tx_err ( neighbour->netdev, iobuf, rc ); + } + + DBGC ( neighbour, "NEIGHBOUR %s %s %s destroyed: %s\n", netdev->name, + net_protocol->name, net_protocol->ntoa ( neighbour->net_dest ), + strerror ( rc ) ); + + /* Drop remaining reference */ + ref_put ( &neighbour->refcnt ); +} + +/** + * Handle neighbour timer expiry + * + * @v timer Retry timer + * @v fail Failure indicator + */ +static void neighbour_expired ( struct retry_timer *timer, int fail ) { + struct neighbour *neighbour = + container_of ( timer, struct neighbour, timer ); + struct net_device *netdev = neighbour->netdev; + struct net_protocol *net_protocol = neighbour->net_protocol; + struct neighbour_discovery *discovery = + neighbour->discovery; + const void *net_dest = neighbour->net_dest; + const void *net_source = neighbour->net_source; + int rc; + + /* If we have failed, destroy the cache entry */ + if ( fail ) { + neighbour_destroy ( neighbour, -ETIMEDOUT ); + return; + } + + /* Restart the timer */ + start_timer ( &neighbour->timer ); + + /* Transmit neighbour request */ + if ( ( rc = discovery->tx_request ( netdev, net_protocol, net_dest, + net_source ) ) != 0 ) { + DBGC ( neighbour, "NEIGHBOUR %s %s %s could not transmit %s " + "request: %s\n", netdev->name, net_protocol->name, + net_protocol->ntoa ( neighbour->net_dest ), + neighbour->discovery->name, strerror ( rc ) ); + /* Retransmit when timer expires */ + return; + } +} + +/** + * Transmit packet, determining link-layer address via neighbour discovery + * + * @v iobuf I/O buffer + * @v netdev Network device + * @v discovery Neighbour discovery protocol + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @v ll_source Source link-layer address + * @ret rc Return status code + */ +int neighbour_tx ( struct io_buffer *iobuf, struct net_device *netdev, + struct net_protocol *net_protocol, const void *net_dest, + struct neighbour_discovery *discovery, + const void *net_source, const void *ll_source ) { + struct neighbour *neighbour; + + /* Find or create neighbour cache entry */ + neighbour = neighbour_find ( netdev, net_protocol, net_dest ); + if ( ! neighbour ) { + neighbour = neighbour_create ( netdev, net_protocol, net_dest ); + if ( ! neighbour ) + return -ENOMEM; + neighbour_discover ( neighbour, discovery, net_source ); + } + + /* If a link-layer address is available then transmit + * immediately, otherwise queue for later transmission. + */ + if ( neighbour_has_ll_dest ( neighbour ) ) { + return net_tx ( iobuf, netdev, net_protocol, neighbour->ll_dest, + ll_source ); + } else { + DBGC2 ( neighbour, "NEIGHBOUR %s %s %s deferring packet\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( net_dest ) ); + list_add_tail ( &iobuf->list, &neighbour->tx_queue ); + return -EAGAIN; + } +} + +/** + * Update existing neighbour cache entry + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v ll_dest Destination link-layer address + * @ret rc Return status code + */ +int neighbour_update ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *ll_dest ) { + struct neighbour *neighbour; + + /* Find neighbour cache entry */ + neighbour = neighbour_find ( netdev, net_protocol, net_dest ); + if ( ! neighbour ) + return -ENOENT; + + /* Set destination address */ + neighbour_discovered ( neighbour, ll_dest ); + + return 0; +} + +/** + * Define neighbour cache entry + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v ll_dest Destination link-layer address, if known + * @ret rc Return status code + */ +int neighbour_define ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, const void *ll_dest ) { + struct neighbour *neighbour; + + /* Find or create neighbour cache entry */ + neighbour = neighbour_find ( netdev, net_protocol, net_dest ); + if ( ! neighbour ) { + neighbour = neighbour_create ( netdev, net_protocol, net_dest ); + if ( ! neighbour ) + return -ENOMEM; + } + + /* Set destination address */ + neighbour_discovered ( neighbour, ll_dest ); + + return 0; +} + +/** + * Update neighbour cache on network device state change or removal + * + * @v netdev Network device + */ +static void neighbour_flush ( struct net_device *netdev ) { + struct neighbour *neighbour; + struct neighbour *tmp; + + /* Remove all neighbour cache entries when a network device is closed */ + if ( ! netdev_is_open ( netdev ) ) { + list_for_each_entry_safe ( neighbour, tmp, &neighbours, list ) + neighbour_destroy ( neighbour, -ENODEV ); + } +} + +/** Neighbour driver (for net device notifications) */ +struct net_driver neighbour_net_driver __net_driver = { + .name = "Neighbour", + .notify = neighbour_flush, + .remove = neighbour_flush, +}; + +/** + * Discard some cached neighbour entries + * + * @ret discarded Number of cached items discarded + */ +static unsigned int neighbour_discard ( void ) { + struct neighbour *neighbour; + + /* Drop oldest cache entry, if any */ + neighbour = list_last_entry ( &neighbours, struct neighbour, list ); + if ( neighbour ) { + neighbour_destroy ( neighbour, -ENOBUFS ); + return 1; + } else { + return 0; + } +} + +/** + * Neighbour cache discarder + * + * Neighbour cache entries are deemed to have a high replacement cost, + * since flushing an active neighbour cache entry midway through a TCP + * transfer will cause substantial disruption. + */ +struct cache_discarder neighbour_discarder __cache_discarder (CACHE_EXPENSIVE)={ + .discard = neighbour_discard, +}; diff --git a/roms/ipxe/src/net/netdev_settings.c b/roms/ipxe/src/net/netdev_settings.c index 9efe6811c..b3b2e68d8 100644 --- a/roms/ipxe/src/net/netdev_settings.c +++ b/roms/ipxe/src/net/netdev_settings.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/settings.h> #include <ipxe/device.h> #include <ipxe/netdevice.h> +#include <ipxe/init.h> /** @file * @@ -34,35 +35,195 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** Network device named settings */ -struct setting mac_setting __setting ( SETTING_NETDEV ) = { +/** Network device predefined settings */ +const struct setting mac_setting __setting ( SETTING_NETDEV, mac ) = { .name = "mac", .description = "MAC address", .type = &setting_type_hex, - .tag = NETDEV_SETTING_TAG_MAC, }; -struct setting busid_setting __setting ( SETTING_NETDEV ) = { +const struct setting bustype_setting __setting ( SETTING_NETDEV, bustype ) = { + .name = "bustype", + .description = "Bus type", + .type = &setting_type_string, +}; +const struct setting busloc_setting __setting ( SETTING_NETDEV, busloc ) = { + .name = "busloc", + .description = "Bus location", + .type = &setting_type_uint32, +}; +const struct setting busid_setting __setting ( SETTING_NETDEV, busid ) = { .name = "busid", .description = "Bus ID", .type = &setting_type_hex, - .tag = NETDEV_SETTING_TAG_BUS_ID, +}; +const struct setting chip_setting __setting ( SETTING_NETDEV, chip ) = { + .name = "chip", + .description = "Chip", + .type = &setting_type_string, }; /** - * Check applicability of network device setting + * Store MAC address setting * - * @v settings Settings block - * @v setting Setting - * @ret applies Setting applies within this settings block + * @v netdev Network device + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ +static int netdev_store_mac ( struct net_device *netdev, + const void *data, size_t len ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + + /* Record new MAC address */ + if ( data ) { + if ( len != netdev->ll_protocol->ll_addr_len ) + return -EINVAL; + memcpy ( netdev->ll_addr, data, len ); + } else { + /* Reset MAC address if clearing setting */ + ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); + } + + return 0; +} + +/** + * Fetch MAC address setting + * + * @v netdev Network device + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error */ -static int netdev_applies ( struct settings *settings __unused, - struct setting *setting ) { +static int netdev_fetch_mac ( struct net_device *netdev, void *data, + size_t len ) { - return ( IS_NETDEV_SETTING_TAG ( setting->tag ) || - dhcpopt_applies ( setting->tag ) ); + if ( len > netdev->ll_protocol->ll_addr_len ) + len = netdev->ll_protocol->ll_addr_len; + memcpy ( data, netdev->ll_addr, len ); + return netdev->ll_protocol->ll_addr_len; } /** + * Fetch bus type setting + * + * @v netdev Network device + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int netdev_fetch_bustype ( struct net_device *netdev, void *data, + size_t len ) { + static const char *bustypes[] = { + [BUS_TYPE_PCI] = "PCI", + [BUS_TYPE_ISAPNP] = "ISAPNP", + [BUS_TYPE_EISA] = "EISA", + [BUS_TYPE_MCA] = "MCA", + [BUS_TYPE_ISA] = "ISA", + [BUS_TYPE_TAP] = "TAP", + }; + struct device_description *desc = &netdev->dev->desc; + const char *bustype; + + assert ( desc->bus_type < ( sizeof ( bustypes ) / + sizeof ( bustypes[0] ) ) ); + bustype = bustypes[desc->bus_type]; + assert ( bustype != NULL ); + strncpy ( data, bustype, len ); + return strlen ( bustype ); +} + +/** + * Fetch bus location setting + * + * @v netdev Network device + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int netdev_fetch_busloc ( struct net_device *netdev, void *data, + size_t len ) { + struct device_description *desc = &netdev->dev->desc; + uint32_t busloc; + + busloc = cpu_to_be32 ( desc->location ); + if ( len > sizeof ( busloc ) ) + len = sizeof ( busloc ); + memcpy ( data, &busloc, len ); + return sizeof ( busloc ); +} + +/** + * Fetch bus ID setting + * + * @v netdev Network device + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int netdev_fetch_busid ( struct net_device *netdev, void *data, + size_t len ) { + struct device_description *desc = &netdev->dev->desc; + struct dhcp_netdev_desc dhcp_desc; + + dhcp_desc.type = desc->bus_type; + dhcp_desc.vendor = htons ( desc->vendor ); + dhcp_desc.device = htons ( desc->device ); + if ( len > sizeof ( dhcp_desc ) ) + len = sizeof ( dhcp_desc ); + memcpy ( data, &dhcp_desc, len ); + return sizeof ( dhcp_desc ); +} + +/** + * Fetch chip setting + * + * @v netdev Network device + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int netdev_fetch_chip ( struct net_device *netdev, void *data, + size_t len ) { + const char *chip = netdev->dev->driver_name; + + strncpy ( data, chip, len ); + return strlen ( chip ); +} + +/** A network device setting operation */ +struct netdev_setting_operation { + /** Setting */ + const struct setting *setting; + /** Store setting (or NULL if not supported) + * + * @v netdev Network device + * @v data Setting data, or NULL to clear setting + * @v len Length of setting data + * @ret rc Return status code + */ + int ( * store ) ( struct net_device *netdev, const void *data, + size_t len ); + /** Fetch setting + * + * @v netdev Network device + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ + int ( * fetch ) ( struct net_device *netdev, void *data, size_t len ); +}; + +/** Network device settings */ +static struct netdev_setting_operation netdev_setting_operations[] = { + { &mac_setting, netdev_store_mac, netdev_fetch_mac }, + { &bustype_setting, NULL, netdev_fetch_bustype }, + { &busloc_setting, NULL, netdev_fetch_busloc }, + { &busid_setting, NULL, netdev_fetch_busid }, + { &chip_setting, NULL, netdev_fetch_chip }, +}; + +/** * Store value of network device setting * * @v settings Settings block @@ -71,19 +232,26 @@ static int netdev_applies ( struct settings *settings __unused, * @v len Length of setting data * @ret rc Return status code */ -static int netdev_store ( struct settings *settings, struct setting *setting, +static int netdev_store ( struct settings *settings, + const struct setting *setting, const void *data, size_t len ) { struct net_device *netdev = container_of ( settings, struct net_device, settings.settings ); + struct netdev_setting_operation *op; + unsigned int i; - if ( setting_cmp ( setting, &mac_setting ) == 0 ) { - if ( len != netdev->ll_protocol->ll_addr_len ) - return -EINVAL; - memcpy ( netdev->ll_addr, data, len ); - return 0; + /* Handle network device-specific settings */ + for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) / + sizeof ( netdev_setting_operations[0] ) ) ; i++ ) { + op = &netdev_setting_operations[i]; + if ( setting_cmp ( setting, op->setting ) == 0 ) { + if ( op->store ) { + return op->store ( netdev, data, len ); + } else { + return -ENOTSUP; + } + } } - if ( setting_cmp ( setting, &busid_setting ) == 0 ) - return -ENOTSUP; return generic_settings_store ( settings, setting, data, len ); } @@ -93,31 +261,23 @@ static int netdev_store ( struct settings *settings, struct setting *setting, * * @v settings Settings block * @v setting Setting to fetch - * @v data Setting data, or NULL to clear setting - * @v len Length of setting data - * @ret rc Return status code + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error */ static int netdev_fetch ( struct settings *settings, struct setting *setting, void *data, size_t len ) { struct net_device *netdev = container_of ( settings, struct net_device, settings.settings ); - struct device_description *desc = &netdev->dev->desc; - struct dhcp_netdev_desc dhcp_desc; + struct netdev_setting_operation *op; + unsigned int i; - if ( setting_cmp ( setting, &mac_setting ) == 0 ) { - if ( len > netdev->ll_protocol->ll_addr_len ) - len = netdev->ll_protocol->ll_addr_len; - memcpy ( data, netdev->ll_addr, len ); - return netdev->ll_protocol->ll_addr_len; - } - if ( setting_cmp ( setting, &busid_setting ) == 0 ) { - dhcp_desc.type = desc->bus_type; - dhcp_desc.vendor = htons ( desc->vendor ); - dhcp_desc.device = htons ( desc->device ); - if ( len > sizeof ( dhcp_desc ) ) - len = sizeof ( dhcp_desc ); - memcpy ( data, &dhcp_desc, len ); - return sizeof ( dhcp_desc ); + /* Handle network device-specific settings */ + for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) / + sizeof ( netdev_setting_operations[0] ) ) ; i++ ) { + op = &netdev_setting_operations[i]; + if ( setting_cmp ( setting, op->setting ) == 0 ) + return op->fetch ( netdev, data, len ); } return generic_settings_fetch ( settings, setting, data, len ); @@ -134,8 +294,55 @@ static void netdev_clear ( struct settings *settings ) { /** Network device configuration settings operations */ struct settings_operations netdev_settings_operations = { - .applies = netdev_applies, .store = netdev_store, .fetch = netdev_fetch, .clear = netdev_clear, }; + +/** + * Redirect "netX" settings block + * + * @v settings Settings block + * @ret settings Underlying settings block + */ +static struct settings * netdev_redirect ( struct settings *settings ) { + struct net_device *netdev; + + /* Redirect to most recently opened network device */ + netdev = last_opened_netdev(); + if ( netdev ) { + return netdev_settings ( netdev ); + } else { + return settings; + } +} + +/** "netX" settings operations */ +static struct settings_operations netdev_redirect_settings_operations = { + .redirect = netdev_redirect, +}; + +/** "netX" settings */ +static struct settings netdev_redirect_settings = { + .refcnt = NULL, + .siblings = LIST_HEAD_INIT ( netdev_redirect_settings.siblings ), + .children = LIST_HEAD_INIT ( netdev_redirect_settings.children ), + .op = &netdev_redirect_settings_operations, +}; + +/** Initialise "netX" settings */ +static void netdev_redirect_settings_init ( void ) { + int rc; + + if ( ( rc = register_settings ( &netdev_redirect_settings, NULL, + "netX" ) ) != 0 ) { + DBG ( "Could not register netX settings: %s\n", + strerror ( rc ) ); + return; + } +} + +/** "netX" settings initialiser */ +struct init_fn netdev_redirect_settings_init_fn __init_fn ( INIT_LATE ) = { + .initialise = netdev_redirect_settings_init, +}; diff --git a/roms/ipxe/src/net/netdevice.c b/roms/ipxe/src/net/netdevice.c index ec3456a93..a05d6610b 100644 --- a/roms/ipxe/src/net/netdevice.c +++ b/roms/ipxe/src/net/netdevice.c @@ -31,8 +31,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/tables.h> #include <ipxe/process.h> #include <ipxe/init.h> +#include <ipxe/malloc.h> #include <ipxe/device.h> #include <ipxe/errortab.h> +#include <ipxe/profile.h> +#include <ipxe/vlan.h> #include <ipxe/netdevice.h> /** @file @@ -47,11 +50,30 @@ struct list_head net_devices = LIST_HEAD_INIT ( net_devices ); /** List of open network devices, in reverse order of opening */ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices ); +/** Network polling profiler */ +static struct profiler net_poll_profiler __profiler = { .name = "net.poll" }; + +/** Network receive profiler */ +static struct profiler net_rx_profiler __profiler = { .name = "net.rx" }; + +/** Network transmit profiler */ +static struct profiler net_tx_profiler __profiler = { .name = "net.tx" }; + /** Default unknown link status code */ #define EUNKNOWN_LINK_STATUS __einfo_error ( EINFO_EUNKNOWN_LINK_STATUS ) #define EINFO_EUNKNOWN_LINK_STATUS \ __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" ) +/** Default not-yet-attempted-configuration status code */ +#define EUNUSED_CONFIG __einfo_error ( EINFO_EUNUSED_CONFIG ) +#define EINFO_EUNUSED_CONFIG \ + __einfo_uniqify ( EINFO_EINPROGRESS, 0x02, "Unused" ) + +/** Default configuration-in-progress status code */ +#define EINPROGRESS_CONFIG __einfo_error ( EINFO_EINPROGRESS_CONFIG ) +#define EINFO_EINPROGRESS_CONFIG \ + __einfo_uniqify ( EINFO_EINPROGRESS, 0x03, "Incomplete" ) + /** Default link-down status code */ #define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN ) #define EINFO_ENOTCONN_LINK_DOWN \ @@ -61,6 +83,8 @@ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices ); struct errortab netdev_errors[] __errortab = { __einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ), __einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ), + __einfo_errortab ( EINFO_EUNUSED_CONFIG ), + __einfo_errortab ( EINFO_EINPROGRESS_CONFIG ), }; /** @@ -88,8 +112,38 @@ static int netdev_has_ll_addr ( struct net_device *netdev ) { static void netdev_notify ( struct net_device *netdev ) { struct net_driver *driver; - for_each_table_entry ( driver, NET_DRIVERS ) - driver->notify ( netdev ); + for_each_table_entry ( driver, NET_DRIVERS ) { + if ( driver->notify ) + driver->notify ( netdev ); + } +} + +/** + * Freeze network device receive queue processing + * + * @v netdev Network device + */ +void netdev_rx_freeze ( struct net_device *netdev ) { + + /* Mark receive queue processing as frozen */ + netdev->state |= NETDEV_RX_FROZEN; + + /* Notify drivers of change */ + netdev_notify ( netdev ); +} + +/** + * Unfreeze network device receive queue processing + * + * @v netdev Network device + */ +void netdev_rx_unfreeze ( struct net_device *netdev ) { + + /* Mark receive queue processing as not frozen */ + netdev->state &= ~NETDEV_RX_FROZEN; + + /* Notify drivers of change */ + netdev_notify ( netdev ); } /** @@ -183,6 +237,7 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { DBGC2 ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n", netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); + profile_start ( &net_tx_profiler ); /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->tx_queue ); @@ -204,6 +259,7 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) goto err; + profile_stop ( &net_tx_profiler ); return 0; err: @@ -212,6 +268,43 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { } /** + * Defer transmitted packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * + * Drivers may call netdev_tx_defer() if there is insufficient space + * in the transmit descriptor ring. Any packets deferred in this way + * will be automatically retransmitted as soon as space becomes + * available (i.e. as soon as the driver calls netdev_tx_complete()). + * + * The packet must currently be in the network device's TX queue. + * + * Drivers utilising netdev_tx_defer() must ensure that space in the + * transmit descriptor ring is freed up @b before calling + * netdev_tx_complete(). For example, if the ring is modelled using a + * producer counter and a consumer counter, then the consumer counter + * must be incremented before the call to netdev_tx_complete(). + * Failure to do this will cause the retransmitted packet to be + * immediately redeferred (which will result in out-of-order + * transmissions and other nastiness). + */ +void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { + + /* Catch data corruption as early as possible */ + list_check_contains_entry ( iobuf, &netdev->tx_queue, list ); + + /* Remove from transmit queue */ + list_del ( &iobuf->list ); + + /* Add to deferred transmit queue */ + list_add_tail ( &iobuf->list, &netdev->tx_deferred ); + + /* Record "out of space" statistic */ + netdev_tx_err ( netdev, NULL, -ENOBUFS ); +} + +/** * Discard transmitted packet * * @v netdev Network device @@ -256,6 +349,13 @@ void netdev_tx_complete_err ( struct net_device *netdev, /* Dequeue and free I/O buffer */ list_del ( &iobuf->list ); netdev_tx_err ( netdev, iobuf, rc ); + + /* Transmit first pending packet, if any */ + if ( ( iobuf = list_first_entry ( &netdev->tx_deferred, + struct io_buffer, list ) ) != NULL ) { + list_del ( &iobuf->list ); + netdev_tx ( netdev, iobuf ); + } } /** @@ -269,9 +369,9 @@ void netdev_tx_complete_err ( struct net_device *netdev, void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) { struct io_buffer *iobuf; - list_for_each_entry ( iobuf, &netdev->tx_queue, list ) { + if ( ( iobuf = list_first_entry ( &netdev->tx_queue, struct io_buffer, + list ) ) != NULL ) { netdev_tx_complete_err ( netdev, iobuf, rc ); - return; } } @@ -282,10 +382,15 @@ void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ) { */ static void netdev_tx_flush ( struct net_device *netdev ) { - /* Discard any packets in the TX queue */ + /* Discard any packets in the TX queue. This will also cause + * any packets in the deferred TX queue to be discarded + * automatically. + */ while ( ! list_empty ( &netdev->tx_queue ) ) { netdev_tx_complete_next_err ( netdev, -ECANCELED ); } + assert ( list_empty ( &netdev->tx_queue ) ); + assert ( list_empty ( &netdev->tx_deferred ) ); } /** @@ -391,6 +496,41 @@ static void netdev_rx_flush ( struct net_device *netdev ) { } /** + * Finish network device configuration + * + * @v config Network device configuration + * @v rc Reason for completion + */ +static void netdev_config_close ( struct net_device_configuration *config, + int rc ) { + struct net_device_configurator *configurator = config->configurator; + struct net_device *netdev = config->netdev; + + /* Restart interface */ + intf_restart ( &config->job, rc ); + + /* Record configuration result */ + config->rc = rc; + if ( rc == 0 ) { + DBGC ( netdev, "NETDEV %s configured via %s\n", + netdev->name, configurator->name ); + } else { + DBGC ( netdev, "NETDEV %s configuration via %s failed: %s\n", + netdev->name, configurator->name, strerror ( rc ) ); + } +} + +/** Network device configuration interface operations */ +static struct interface_operation netdev_config_ops[] = { + INTF_OP ( intf_close, struct net_device_configuration *, + netdev_config_close ), +}; + +/** Network device configuration interface descriptor */ +static struct interface_descriptor netdev_config_desc = + INTF_DESC ( struct net_device_configuration, job, netdev_config_ops ); + +/** * Free network device * * @v refcnt Network device reference counter @@ -408,24 +548,41 @@ static void free_netdev ( struct refcnt *refcnt ) { /** * Allocate network device * - * @v priv_size Size of private data area (net_device::priv) + * @v priv_len Length of private data area (net_device::priv) * @ret netdev Network device, or NULL * * Allocates space for a network device and its private data area. */ -struct net_device * alloc_netdev ( size_t priv_size ) { +struct net_device * alloc_netdev ( size_t priv_len ) { struct net_device *netdev; + struct net_device_configurator *configurator; + struct net_device_configuration *config; + unsigned int num_configs; + size_t confs_len; size_t total_len; - total_len = ( sizeof ( *netdev ) + priv_size ); + num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); + confs_len = ( num_configs * sizeof ( netdev->configs[0] ) ); + total_len = ( sizeof ( *netdev ) + confs_len + priv_len ); netdev = zalloc ( total_len ); if ( netdev ) { ref_init ( &netdev->refcnt, free_netdev ); netdev->link_rc = -EUNKNOWN_LINK_STATUS; INIT_LIST_HEAD ( &netdev->tx_queue ); + INIT_LIST_HEAD ( &netdev->tx_deferred ); INIT_LIST_HEAD ( &netdev->rx_queue ); netdev_settings_init ( netdev ); - netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); + config = netdev->configs; + for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ){ + config->netdev = netdev; + config->configurator = configurator; + config->rc = -EUNUSED_CONFIG; + intf_init ( &config->job, &netdev_config_desc, + &netdev->refcnt ); + config++; + } + netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) + + confs_len ); } return netdev; } @@ -441,21 +598,31 @@ struct net_device * alloc_netdev ( size_t priv_size ) { */ int register_netdev ( struct net_device *netdev ) { static unsigned int ifindex = 0; + struct ll_protocol *ll_protocol = netdev->ll_protocol; struct net_driver *driver; + uint32_t seed; int rc; - /* Create device name */ + /* Record device index and create device name */ + netdev->index = ifindex++; if ( netdev->name[0] == '\0' ) { snprintf ( netdev->name, sizeof ( netdev->name ), "net%d", - ifindex++ ); + netdev->index ); } /* Set initial link-layer address, if not already set */ if ( ! netdev_has_ll_addr ( netdev ) ) { - netdev->ll_protocol->init_addr ( netdev->hw_addr, - netdev->ll_addr ); + ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr ); } + /* Use least significant bits of the link-layer address to + * improve the randomness of the (non-cryptographic) random + * number generator. + */ + memcpy ( &seed, ( netdev->ll_addr + ll_protocol->ll_addr_len + - sizeof ( seed ) ), sizeof ( seed ) ); + srand ( rand() ^ seed ); + /* Add to device list */ netdev_get ( netdev ); list_add_tail ( &netdev->list, &net_devices ); @@ -473,7 +640,7 @@ int register_netdev ( struct net_device *netdev ) { /* Probe device */ for_each_table_entry ( driver, NET_DRIVERS ) { - if ( ( rc = driver->probe ( netdev ) ) != 0 ) { + if ( driver->probe && ( rc = driver->probe ( netdev ) ) != 0 ) { DBGC ( netdev, "NETDEV %s could not add %s device: " "%s\n", netdev->name, driver->name, strerror ( rc ) ); @@ -484,8 +651,10 @@ int register_netdev ( struct net_device *netdev ) { return 0; err_probe: - for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) - driver->remove ( netdev ); + for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) { + if ( driver->remove ) + driver->remove ( netdev ); + } clear_settings ( netdev_settings ( netdev ) ); unregister_settings ( netdev_settings ( netdev ) ); err_register_settings: @@ -507,13 +676,13 @@ int netdev_open ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %s opening\n", netdev->name ); - /* Open the device */ - if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) - return rc; - /* Mark as opened */ netdev->state |= NETDEV_OPEN; + /* Open the device */ + if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) + goto err; + /* Add to head of open devices list */ list_add ( &netdev->open_list, &open_net_devices ); @@ -521,6 +690,10 @@ int netdev_open ( struct net_device *netdev ) { netdev_notify ( netdev ); return 0; + + err: + netdev->state &= ~NETDEV_OPEN; + return rc; } /** @@ -529,6 +702,8 @@ int netdev_open ( struct net_device *netdev ) { * @v netdev Network device */ void netdev_close ( struct net_device *netdev ) { + unsigned int num_configs; + unsigned int i; /* Do nothing if device is already closed */ if ( ! ( netdev->state & NETDEV_OPEN ) ) @@ -536,6 +711,15 @@ void netdev_close ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %s closing\n", netdev->name ); + /* Terminate any ongoing configurations. Use intf_close() + * rather than intf_restart() to allow the cancellation to be + * reported back to us if a configuration is actually in + * progress. + */ + num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); + for ( i = 0 ; i < num_configs ; i++ ) + intf_close ( &netdev->configs[i].job, -ECANCELED ); + /* Remove from open devices list */ list_del ( &netdev->open_list ); @@ -567,17 +751,19 @@ void unregister_netdev ( struct net_device *netdev ) { netdev_close ( netdev ); /* Remove device */ - for_each_table_entry_reverse ( driver, NET_DRIVERS ) - driver->remove ( netdev ); + for_each_table_entry_reverse ( driver, NET_DRIVERS ) { + if ( driver->remove ) + driver->remove ( netdev ); + } /* Unregister per-netdev configuration settings */ clear_settings ( netdev_settings ( netdev ) ); unregister_settings ( netdev_settings ( netdev ) ); /* Remove from device list */ + DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name ); list_del ( &netdev->list ); netdev_put ( netdev ); - DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name ); } /** Enable or disable interrupts @@ -609,6 +795,11 @@ void netdev_irq ( struct net_device *netdev, int enable ) { struct net_device * find_netdev ( const char *name ) { struct net_device *netdev; + /* Allow "netX" shortcut */ + if ( strcmp ( name, "netX" ) == 0 ) + return last_opened_netdev(); + + /* Identify network device by name */ list_for_each_entry ( netdev, &net_devices, list ) { if ( strcmp ( netdev->name, name ) == 0 ) return netdev; @@ -618,6 +809,24 @@ struct net_device * find_netdev ( const char *name ) { } /** + * Get network device by index + * + * @v index Network device index + * @ret netdev Network device, or NULL + */ +struct net_device * find_netdev_by_index ( unsigned int index ) { + struct net_device *netdev; + + /* Identify network device by index */ + list_for_each_entry ( netdev, &net_devices, list ) { + if ( netdev->index == index ) + return netdev; + } + + return NULL; +} + +/** * Get network device by PCI bus:dev.fn address * * @v bus_type Bus type @@ -735,7 +944,9 @@ void net_poll ( void ) { list_for_each_entry ( netdev, &net_devices, list ) { /* Poll for new packets */ + profile_start ( &net_poll_profiler ); netdev_poll ( netdev ); + profile_stop ( &net_poll_profiler ); /* Leave received packets on the queue if receive * queue processing is currently frozen. This will @@ -752,6 +963,7 @@ void net_poll ( void ) { DBGC2 ( netdev, "NETDEV %s processing %p (%p+%zx)\n", netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) ); + profile_start ( &net_rx_profiler ); /* Remove link-layer header */ ll_protocol = netdev->ll_protocol; @@ -770,6 +982,7 @@ void net_poll ( void ) { /* Record error for diagnosis */ netdev_rx_err ( netdev, NULL, rc ); } + profile_stop ( &net_rx_profiler ); } } } @@ -783,5 +996,184 @@ static void net_step ( struct process *process __unused ) { net_poll(); } +/** + * Get the VLAN tag (when VLAN support is not present) + * + * @v netdev Network device + * @ret tag 0, indicating that device is not a VLAN device + */ +__weak unsigned int vlan_tag ( struct net_device *netdev __unused ) { + return 0; +} + +/** + * Identify VLAN device (when VLAN support is not present) + * + * @v trunk Trunk network device + * @v tag VLAN tag + * @ret netdev VLAN device, if any + */ +__weak struct net_device * vlan_find ( struct net_device *trunk __unused, + unsigned int tag __unused ) { + return NULL; +} + /** Networking stack process */ PERMANENT_PROCESS ( net_process, net_step ); + +/** + * Discard some cached network device data + * + * @ret discarded Number of cached items discarded + */ +static unsigned int net_discard ( void ) { + struct net_device *netdev; + struct io_buffer *iobuf; + unsigned int discarded = 0; + + /* Try to drop one deferred TX packet from each network device */ + for_each_netdev ( netdev ) { + if ( ( iobuf = list_first_entry ( &netdev->tx_deferred, + struct io_buffer, + list ) ) != NULL ) { + + /* Discard first deferred packet */ + list_del ( &iobuf->list ); + free ( iobuf ); + + /* Report discard */ + discarded++; + } + } + + return discarded; +} + +/** Network device cache discarder */ +struct cache_discarder net_discarder __cache_discarder ( CACHE_NORMAL ) = { + .discard = net_discard, +}; + +/** + * Find network device configurator + * + * @v name Name + * @ret configurator Network device configurator, or NULL + */ +struct net_device_configurator * find_netdev_configurator ( const char *name ) { + struct net_device_configurator *configurator; + + for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ) { + if ( strcmp ( configurator->name, name ) == 0 ) + return configurator; + } + return NULL; +} + +/** + * Start network device configuration + * + * @v netdev Network device + * @v configurator Network device configurator + * @ret rc Return status code + */ +int netdev_configure ( struct net_device *netdev, + struct net_device_configurator *configurator ) { + struct net_device_configuration *config = + netdev_configuration ( netdev, configurator ); + int rc; + + /* Check applicability of configurator */ + if ( ! netdev_configurator_applies ( netdev, configurator ) ) { + DBGC ( netdev, "NETDEV %s does not support configuration via " + "%s\n", netdev->name, configurator->name ); + return -ENOTSUP; + } + + /* Terminate any ongoing configuration */ + intf_restart ( &config->job, -ECANCELED ); + + /* Mark configuration as being in progress */ + config->rc = -EINPROGRESS_CONFIG; + + DBGC ( netdev, "NETDEV %s starting configuration via %s\n", + netdev->name, configurator->name ); + + /* Start configuration */ + if ( ( rc = configurator->start ( &config->job, netdev ) ) != 0 ) { + DBGC ( netdev, "NETDEV %s could not start configuration via " + "%s: %s\n", netdev->name, configurator->name, + strerror ( rc ) ); + config->rc = rc; + return rc; + } + + return 0; +} + +/** + * Start network device configuration via all supported configurators + * + * @v netdev Network device + * @ret rc Return status code + */ +int netdev_configure_all ( struct net_device *netdev ) { + struct net_device_configurator *configurator; + int rc; + + /* Start configuration for each configurator */ + for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ) { + + /* Skip any inapplicable configurators */ + if ( ! netdev_configurator_applies ( netdev, configurator ) ) + continue; + + /* Start configuration */ + if ( ( rc = netdev_configure ( netdev, configurator ) ) != 0 ) + return rc; + } + + return 0; +} + +/** + * Check if network device has a configuration with a specified status code + * + * @v netdev Network device + * @v rc Status code + * @ret has_rc Network device has a configuration with this status code + */ +static int netdev_has_configuration_rc ( struct net_device *netdev, int rc ) { + unsigned int num_configs; + unsigned int i; + + num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); + for ( i = 0 ; i < num_configs ; i++ ) { + if ( netdev->configs[i].rc == rc ) + return 1; + } + return 0; +} + +/** + * Check if network device configuration is in progress + * + * @v netdev Network device + * @ret is_in_progress Network device configuration is in progress + */ +int netdev_configuration_in_progress ( struct net_device *netdev ) { + + return netdev_has_configuration_rc ( netdev, -EINPROGRESS_CONFIG ); +} + +/** + * Check if network device has at least one successful configuration + * + * @v netdev Network device + * @v configurator Configurator + * @ret rc Return status code + */ +int netdev_configuration_ok ( struct net_device *netdev ) { + + return netdev_has_configuration_rc ( netdev, 0 ); +} diff --git a/roms/ipxe/src/net/oncrpc/mount.c b/roms/ipxe/src/net/oncrpc/mount.c new file mode 100644 index 000000000..8838a147c --- /dev/null +++ b/roms/ipxe/src/net/oncrpc/mount.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <libgen.h> +#include <byteswap.h> +#include <ipxe/time.h> +#include <ipxe/iobuf.h> +#include <ipxe/open.h> +#include <ipxe/features.h> +#include <ipxe/oncrpc.h> +#include <ipxe/oncrpc_iob.h> +#include <ipxe/nfs.h> +#include <ipxe/mount.h> + +/** @file + * + * NFS MOUNT protocol + * + */ + +/** MNT procedure number */ +#define MOUNT_MNT 1 +/** UMNT procedure number */ +#define MOUNT_UMNT 3 + +/** + * Send a MNT request + * + * @v intf Interface to send the request on + * @v session ONC RPC session + * @v mountpoinrt The path of the directory to mount. + * @ret rc Return status code + */ +int mount_mnt ( struct interface *intf, struct oncrpc_session *session, + const char *mountpoint ) { + struct oncrpc_field fields[] = { + ONCRPC_FIELD ( str, mountpoint ), + ONCRPC_FIELD_END, + }; + + return oncrpc_call ( intf, session, MOUNT_MNT, fields ); +} + +/** + * Send a UMNT request + * + * @v intf Interface to send the request on + * @v session ONC RPC session + * @v mountpoinrt The path of the directory to unmount. + * @ret rc Return status code + */ +int mount_umnt ( struct interface *intf, struct oncrpc_session *session, + const char *mountpoint ) { + struct oncrpc_field fields[] = { + ONCRPC_FIELD ( str, mountpoint ), + ONCRPC_FIELD_END, + }; + + return oncrpc_call ( intf, session, MOUNT_UMNT, fields ); +} + +/** + * Parse an MNT reply + * + * @v mnt_reply A structure where the data will be saved + * @v reply The ONC RPC reply to get data from + * @ret rc Return status code + */ +int mount_get_mnt_reply ( struct mount_mnt_reply *mnt_reply, + struct oncrpc_reply *reply ) { + if ( ! mnt_reply || ! reply ) + return -EINVAL; + + mnt_reply->status = oncrpc_iob_get_int ( reply->data ); + + switch ( mnt_reply->status ) + { + case MNT3_OK: + break; + case MNT3ERR_NOENT: + return -ENOENT; + case MNT3ERR_IO: + return -EIO; + case MNT3ERR_ACCES: + return -EACCES; + case MNT3ERR_NOTDIR: + return -ENOTDIR; + case MNT3ERR_NAMETOOLONG: + return -ENAMETOOLONG; + default: + return -EPROTO; + } + + nfs_iob_get_fh ( reply->data, &mnt_reply->fh ); + + return 0; +} diff --git a/roms/ipxe/src/net/oncrpc/nfs.c b/roms/ipxe/src/net/oncrpc/nfs.c new file mode 100644 index 000000000..b6118f91a --- /dev/null +++ b/roms/ipxe/src/net/oncrpc/nfs.c @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <libgen.h> +#include <byteswap.h> +#include <ipxe/time.h> +#include <ipxe/iobuf.h> +#include <ipxe/open.h> +#include <ipxe/features.h> +#include <ipxe/nfs.h> +#include <ipxe/oncrpc.h> +#include <ipxe/oncrpc_iob.h> +#include <ipxe/portmap.h> +#include <ipxe/mount.h> +#include <ipxe/settings.h> + +/** @file + * + * Network File System protocol + * + */ + +/** NFS LOOKUP procedure */ +#define NFS_LOOKUP 3 +/** NFS READLINK procedure */ +#define NFS_READLINK 5 +/** NFS READ procedure */ +#define NFS_READ 6 + +/** + * Extract a file handle from the beginning of an I/O buffer + * + * @v io_buf I/O buffer + * @v fh File handle + * @ret size Size of the data read + */ +size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh ) { + fh->size = oncrpc_iob_get_int ( io_buf ); + + if ( fh->size > 64 ) + return sizeof ( uint32_t ); + + memcpy (fh->fh, io_buf->data, fh->size ); + iob_pull ( io_buf, fh->size ); + + return fh->size + sizeof ( uint32_t ); +} + +/** + * Add a file handle to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v fh File handle + * @ret size Size of the data written + */ +size_t nfs_iob_add_fh ( struct io_buffer *io_buf, const struct nfs_fh *fh ) { + size_t s; + + s = oncrpc_iob_add_int ( io_buf, fh->size ); + memcpy ( iob_put ( io_buf, fh->size ), &fh->fh, fh->size ); + + return s + fh->size; +} + +/** + * Send a LOOKUP request + * + * @v intf Interface to send the request on + * @v session ONC RPC session + * @v fh The file handle of the the directory + * @v filename The file name + * @ret rc Return status code + */ +int nfs_lookup ( struct interface *intf, struct oncrpc_session *session, + const struct nfs_fh *fh, const char *filename ) { + struct oncrpc_field fields[] = { + ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ), + ONCRPC_FIELD ( str, filename ), + ONCRPC_FIELD_END, + }; + + return oncrpc_call ( intf, session, NFS_LOOKUP, fields ); +} + +/** + * Send a READLINK request + * + * @v intf Interface to send the request on + * @v session ONC RPC session + * @v fh The symlink file handle + * @ret rc Return status code + */ +int nfs_readlink ( struct interface *intf, struct oncrpc_session *session, + const struct nfs_fh *fh ) { + struct oncrpc_field fields[] = { + ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ), + ONCRPC_FIELD_END, + }; + + return oncrpc_call ( intf, session, NFS_READLINK, fields ); +} + +/** + * Send a READ request + * + * @v intf Interface to send the request on + * @v session ONC RPC session + * @v fh The file handle + * @v offset Offset + * @v count Byte count + * @ret rc Return status code + */ +int nfs_read ( struct interface *intf, struct oncrpc_session *session, + const struct nfs_fh *fh, uint64_t offset, uint32_t count ) { + struct oncrpc_field fields[] = { + ONCRPC_SUBFIELD ( array, fh->size, &fh->fh ), + ONCRPC_FIELD ( int64, offset ), + ONCRPC_FIELD ( int32, count ), + ONCRPC_FIELD_END, + }; + + return oncrpc_call ( intf, session, NFS_READ, fields ); +} + +/** + * Parse a LOOKUP reply + * + * @v lookup_reply A structure where the data will be saved + * @v reply The ONC RPC reply to get data from + * @ret rc Return status code + */ +int nfs_get_lookup_reply ( struct nfs_lookup_reply *lookup_reply, + struct oncrpc_reply *reply ) { + if ( ! lookup_reply || ! reply ) + return -EINVAL; + + lookup_reply->status = oncrpc_iob_get_int ( reply->data ); + switch ( lookup_reply->status ) + { + case NFS3_OK: + break; + case NFS3ERR_PERM: + return -EPERM; + case NFS3ERR_NOENT: + return -ENOENT; + case NFS3ERR_IO: + return -EIO; + case NFS3ERR_ACCES: + return -EACCES; + case NFS3ERR_NOTDIR: + return -ENOTDIR; + case NFS3ERR_NAMETOOLONG: + return -ENAMETOOLONG; + case NFS3ERR_STALE: + return -ESTALE; + case NFS3ERR_BADHANDLE: + case NFS3ERR_SERVERFAULT: + default: + return -EPROTO; + } + + nfs_iob_get_fh ( reply->data, &lookup_reply->fh ); + + if ( oncrpc_iob_get_int ( reply->data ) == 1 ) + lookup_reply->ent_type = oncrpc_iob_get_int ( reply->data ); + + return 0; +} +/** + * Parse a READLINK reply + * + * @v readlink_reply A structure where the data will be saved + * @v reply The ONC RPC reply to get data from + * @ret rc Return status code + */ +int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply, + struct oncrpc_reply *reply ) { + if ( ! readlink_reply || ! reply ) + return -EINVAL; + + readlink_reply->status = oncrpc_iob_get_int ( reply->data ); + switch ( readlink_reply->status ) + { + case NFS3_OK: + break; + case NFS3ERR_IO: + return -EIO; + case NFS3ERR_ACCES: + return -EACCES; + case NFS3ERR_INVAL: + return -EINVAL; + case NFS3ERR_NOTSUPP: + return -ENOTSUP; + case NFS3ERR_STALE: + return -ESTALE; + case NFS3ERR_BADHANDLE: + case NFS3ERR_SERVERFAULT: + default: + return -EPROTO; + } + + if ( oncrpc_iob_get_int ( reply->data ) == 1 ) + iob_pull ( reply->data, 5 * sizeof ( uint32_t ) + + 8 * sizeof ( uint64_t ) ); + + readlink_reply->path_len = oncrpc_iob_get_int ( reply->data ); + readlink_reply->path = reply->data->data; + + return 0; +} + +/** + * Parse a READ reply + * + * @v read_reply A structure where the data will be saved + * @v reply The ONC RPC reply to get data from + * @ret rc Return status code + */ +int nfs_get_read_reply ( struct nfs_read_reply *read_reply, + struct oncrpc_reply *reply ) { + if ( ! read_reply || ! reply ) + return -EINVAL; + + read_reply->status = oncrpc_iob_get_int ( reply->data ); + switch ( read_reply->status ) + { + case NFS3_OK: + break; + case NFS3ERR_PERM: + return -EPERM; + case NFS3ERR_NOENT: + return -ENOENT; + case NFS3ERR_IO: + return -EIO; + case NFS3ERR_NXIO: + return -ENXIO; + case NFS3ERR_ACCES: + return -EACCES; + case NFS3ERR_INVAL: + return -EINVAL; + case NFS3ERR_STALE: + return -ESTALE; + case NFS3ERR_BADHANDLE: + case NFS3ERR_SERVERFAULT: + default: + return -EPROTO; + } + + if ( oncrpc_iob_get_int ( reply->data ) == 1 ) + { + iob_pull ( reply->data, 5 * sizeof ( uint32_t ) ); + read_reply->filesize = oncrpc_iob_get_int64 ( reply->data ); + iob_pull ( reply->data, 7 * sizeof ( uint64_t ) ); + } + + read_reply->count = oncrpc_iob_get_int ( reply->data ); + read_reply->eof = oncrpc_iob_get_int ( reply->data ); + read_reply->data_len = oncrpc_iob_get_int ( reply->data ); + read_reply->data = reply->data->data; + + if ( read_reply->count != read_reply->data_len ) + return -EPROTO; + + return 0; +} + diff --git a/roms/ipxe/src/net/oncrpc/nfs_open.c b/roms/ipxe/src/net/oncrpc/nfs_open.c new file mode 100644 index 000000000..349957ffe --- /dev/null +++ b/roms/ipxe/src/net/oncrpc/nfs_open.c @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <libgen.h> +#include <byteswap.h> +#include <ipxe/time.h> +#include <ipxe/socket.h> +#include <ipxe/tcpip.h> +#include <ipxe/in.h> +#include <ipxe/iobuf.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/uri.h> +#include <ipxe/features.h> +#include <ipxe/nfs.h> +#include <ipxe/nfs_open.h> +#include <ipxe/oncrpc.h> +#include <ipxe/oncrpc_iob.h> +#include <ipxe/portmap.h> +#include <ipxe/mount.h> + +/** @file + * + * Network File System protocol + * + */ + +FEATURE ( FEATURE_PROTOCOL, "NFS", DHCP_EB_FEATURE_NFS, 1 ); + +#define NFS_RSIZE 100000 + +enum nfs_pm_state { + NFS_PORTMAP_NONE = 0, + NFS_PORTMAP_MOUNTPORT, + NFS_PORTMAP_NFSPORT, + MFS_PORTMAP_CLOSED, +}; + +enum nfs_mount_state { + NFS_MOUNT_NONE = 0, + NFS_MOUNT_MNT, + NFS_MOUNT_UMNT, + NFS_MOUNT_CLOSED, +}; + +enum nfs_state { + NFS_NONE = 0, + NFS_LOOKUP, + NFS_LOOKUP_SENT, + NFS_READLINK, + NFS_READLINK_SENT, + NFS_READ, + NFS_READ_SENT, + NFS_CLOSED, +}; + +/** + * A NFS request + * + */ +struct nfs_request { + /** Reference counter */ + struct refcnt refcnt; + /** Data transfer interface */ + struct interface xfer; + + struct interface pm_intf; + struct interface mount_intf; + struct interface nfs_intf; + + enum nfs_pm_state pm_state; + enum nfs_mount_state mount_state; + enum nfs_state nfs_state; + + struct oncrpc_session pm_session; + struct oncrpc_session mount_session; + struct oncrpc_session nfs_session; + + struct oncrpc_cred_sys auth_sys; + + char * hostname; + char * path; + char * mountpoint; + char * filename; + size_t filename_offset; + + struct nfs_fh readlink_fh; + struct nfs_fh current_fh; + uint64_t file_offset; + + size_t remaining; + int eof; +}; + +static void nfs_step ( struct nfs_request *nfs ); + +/** + * Free NFS request + * + * @v refcnt Reference counter + */ +static void nfs_free ( struct refcnt *refcnt ) { + struct nfs_request *nfs; + + nfs = container_of ( refcnt, struct nfs_request, refcnt ); + DBGC ( nfs, "NFS_OPEN %p freed\n", nfs ); + + free ( nfs->hostname ); + free ( nfs->path ); + free ( nfs->auth_sys.hostname ); + free ( nfs ); +} + +/** + * Mark NFS operation as complete + * + * @v nfs NFS request + * @v rc Return status code + */ +static void nfs_done ( struct nfs_request *nfs, int rc ) { + if ( rc == 0 && nfs->nfs_state != NFS_CLOSED ) + rc = -ECONNRESET; + + DBGC ( nfs, "NFS_OPEN %p completed (%s)\n", nfs, strerror ( rc ) ); + + intf_shutdown ( &nfs->xfer, rc ); + intf_shutdown ( &nfs->pm_intf, rc ); + intf_shutdown ( &nfs->mount_intf, rc ); + intf_shutdown ( &nfs->nfs_intf, rc ); +} + +static int nfs_connect ( struct interface *intf, uint16_t port, + const char *hostname ) { + struct sockaddr_tcpip peer; + struct sockaddr_tcpip local; + + if ( ! intf || ! hostname || ! port ) + return -EINVAL; + + memset ( &peer, 0, sizeof ( peer ) ); + memset ( &local, 0, sizeof ( local ) ); + peer.st_port = htons ( port ); + + /* Use a local port < 1024 to avoid using the 'insecure' option in + * /etc/exports file. */ + local.st_flags = TCPIP_BIND_PRIVILEGED; + + return xfer_open_named_socket ( intf, SOCK_STREAM, + ( struct sockaddr * ) &peer, hostname, + ( struct sockaddr * ) &local ); +} + +static void nfs_pm_step ( struct nfs_request *nfs ) { + int rc; + + if ( ! xfer_window ( &nfs->pm_intf ) ) + return; + + if ( nfs->pm_state == NFS_PORTMAP_NONE ) { + DBGC ( nfs, "NFS_OPEN %p GETPORT call (mount)\n", nfs ); + + rc = portmap_getport ( &nfs->pm_intf, &nfs->pm_session, + ONCRPC_MOUNT, MOUNT_VERS, + PORTMAP_PROTO_TCP ); + if ( rc != 0 ) + goto err; + + nfs->pm_state++; + return; + } + + if ( nfs->pm_state == NFS_PORTMAP_NFSPORT ) { + DBGC ( nfs, "NFS_OPEN %p GETPORT call (nfs)\n", nfs ); + + rc = portmap_getport ( &nfs->pm_intf, &nfs->pm_session, + ONCRPC_NFS, NFS_VERS, + PORTMAP_PROTO_TCP ); + if ( rc != 0 ) + goto err; + + return; + } + + return; +err: + nfs_done ( nfs, rc ); +} + +static int nfs_pm_deliver ( struct nfs_request *nfs, + struct io_buffer *io_buf, + struct xfer_metadata *meta __unused ) { + int rc; + struct oncrpc_reply reply; + struct portmap_getport_reply getport_reply; + + oncrpc_get_reply ( &nfs->pm_session, &reply, io_buf ); + if ( reply.accept_state != 0 ) + { + rc = -EPROTO; + goto err; + } + + if ( nfs->pm_state == NFS_PORTMAP_MOUNTPORT ) { + DBGC ( nfs, "NFS_OPEN %p got GETPORT reply (mount)\n", nfs ); + + rc = portmap_get_getport_reply ( &getport_reply, &reply ); + if ( rc != 0 ) + goto err; + + rc = nfs_connect ( &nfs->mount_intf, getport_reply.port, + nfs->hostname ); + if ( rc != 0 ) + goto err; + + nfs->pm_state++; + nfs_pm_step ( nfs ); + + goto done; + } + + if ( nfs->pm_state == NFS_PORTMAP_NFSPORT ) { + DBGC ( nfs, "NFS_OPEN %p got GETPORT reply (nfs)\n", nfs ); + + rc = portmap_get_getport_reply ( &getport_reply, &reply ); + if ( rc != 0 ) + goto err; + + rc = nfs_connect ( &nfs->nfs_intf, getport_reply.port, + nfs->hostname ); + if ( rc != 0 ) + goto err; + + intf_shutdown ( &nfs->pm_intf, 0 ); + nfs->pm_state++; + + goto done; + } + + rc = -EPROTO; +err: + nfs_done ( nfs, rc ); +done: + free_iob ( io_buf ); + return 0; +} + +static void nfs_mount_step ( struct nfs_request *nfs ) { + int rc; + + if ( ! xfer_window ( &nfs->mount_intf ) ) + return; + + if ( nfs->mount_state == NFS_MOUNT_NONE ) { + DBGC ( nfs, "NFS_OPEN %p MNT call (%s)\n", nfs, + nfs->mountpoint ); + + rc = mount_mnt ( &nfs->mount_intf, &nfs->mount_session, + nfs->mountpoint ); + if ( rc != 0 ) + goto err; + + nfs->mount_state++; + return; + } + + if ( nfs->mount_state == NFS_MOUNT_UMNT ) { + DBGC ( nfs, "NFS_OPEN %p UMNT call\n", nfs ); + + rc = mount_umnt ( &nfs->mount_intf, &nfs->mount_session, + nfs->mountpoint ); + if ( rc != 0 ) + goto err; + } + + return; +err: + nfs_done ( nfs, rc ); +} + +static int nfs_mount_deliver ( struct nfs_request *nfs, + struct io_buffer *io_buf, + struct xfer_metadata *meta __unused ) { + int rc; + char *sep; + struct oncrpc_reply reply; + struct mount_mnt_reply mnt_reply; + + oncrpc_get_reply ( &nfs->mount_session, &reply, io_buf ); + if ( reply.accept_state != 0 ) + { + rc = -EPROTO; + goto err; + } + + if ( nfs->mount_state == NFS_MOUNT_MNT ) { + DBGC ( nfs, "NFS_OPEN %p got MNT reply\n", nfs ); + rc = mount_get_mnt_reply ( &mnt_reply, &reply ); + if ( rc != 0 ) { + if ( mnt_reply.status != MNT3ERR_NOTDIR ) + goto err; + + if ( strcmp ( nfs->mountpoint, "/" ) == 0 ) + goto err; + + sep = strrchr ( nfs->mountpoint, '/' ); + nfs->filename[-1] = '/'; + nfs->filename = sep + 1; + *sep = '\0'; + + DBGC ( nfs, "NFS_OPEN %p ENOTDIR received retrying" \ + "with %s\n", nfs, nfs->mountpoint ); + goto done; + } + + nfs->current_fh = mnt_reply.fh; + nfs->nfs_state = NFS_LOOKUP; + nfs_step ( nfs ); + + goto done; + } + + if ( nfs->mount_state == NFS_MOUNT_UMNT ) { + DBGC ( nfs, "NFS_OPEN %p got UMNT reply\n", nfs ); + nfs_done ( nfs, 0 ); + + goto done; + } + + rc = -EPROTO; +err: + nfs_done ( nfs, rc ); +done: + free_iob ( io_buf ); + return 0; +} + +static void nfs_step ( struct nfs_request *nfs ) { + int rc; + char *path_component = NULL; + + if ( ! xfer_window ( &nfs->nfs_intf ) ) + return; + + if ( nfs->nfs_state == NFS_LOOKUP ) { + while ( path_component == NULL || path_component[0] == '\0') { + path_component = nfs->filename; + while ( *nfs->filename != '\0' ) { + nfs->filename_offset++; + if ( *nfs->filename++ == '/' ) { + *(nfs->filename - 1) = '\0'; + break; + } + } + } + + DBGC ( nfs, "NFS_OPEN %p LOOKUP call (%s)\n", nfs, + path_component ); + + rc = nfs_lookup ( &nfs->nfs_intf, &nfs->nfs_session, + &nfs->current_fh, path_component ); + if ( rc != 0 ) + goto err; + + nfs->nfs_state++; + return; + } + + + if ( nfs->nfs_state == NFS_READLINK ) { + DBGC ( nfs, "NFS_OPEN %p READLINK call\n", nfs ); + + rc = nfs_readlink ( &nfs->nfs_intf, &nfs->nfs_session, + &nfs->readlink_fh ); + if ( rc != 0 ) + goto err; + + nfs->nfs_state++; + return; + } + + if ( nfs->nfs_state == NFS_READ ) { + DBGC ( nfs, "NFS_OPEN %p READ call\n", nfs ); + + rc = nfs_read ( &nfs->nfs_intf, &nfs->nfs_session, + &nfs->current_fh, nfs->file_offset, + NFS_RSIZE ); + if ( rc != 0 ) + goto err; + + nfs->nfs_state++; + return; + } + + return; +err: + nfs_done ( nfs, rc ); +} + +static int nfs_deliver ( struct nfs_request *nfs, + struct io_buffer *io_buf, + struct xfer_metadata *meta __unused ) { + int rc; + struct oncrpc_reply reply; + + if ( nfs->remaining == 0 ) { + oncrpc_get_reply ( &nfs->nfs_session, &reply, io_buf ); + if ( reply.accept_state != 0 ) { + rc = -EPROTO; + goto err; + } + } + + if ( nfs->nfs_state == NFS_LOOKUP_SENT ) { + struct nfs_lookup_reply lookup_reply; + + DBGC ( nfs, "NFS_OPEN %p got LOOKUP reply\n", nfs ); + + rc = nfs_get_lookup_reply ( &lookup_reply, &reply ); + if ( rc != 0 ) + goto err; + + if ( lookup_reply.ent_type == NFS_ATTR_SYMLINK ) { + nfs->readlink_fh = lookup_reply.fh; + nfs->nfs_state = NFS_READLINK; + } else { + nfs->current_fh = lookup_reply.fh; + + if ( nfs->filename[0] == '\0' ) + nfs->nfs_state = NFS_READ; + else + nfs->nfs_state--; + } + + nfs_step ( nfs ); + goto done; + } + + if ( nfs->nfs_state == NFS_READLINK_SENT ) { + char *new_filename; + struct nfs_readlink_reply readlink_reply; + + DBGC ( nfs, "NFS_OPEN %p got READLINK reply\n", nfs ); + + rc = nfs_get_readlink_reply ( &readlink_reply, &reply ); + if ( rc != 0 ) + goto err; + + if ( readlink_reply.path_len == 0 ) + return -EINVAL; + + if ( readlink_reply.path[0] == '/' ) { + if ( strncmp ( readlink_reply.path, nfs->mountpoint, + strlen ( nfs->mountpoint ) ) != 0 ) + return -EINVAL; + + /* The mountpoint part of the path is ended by a '/' */ + if ( strlen ( nfs->mountpoint ) != + readlink_reply.path_len ) { + readlink_reply.path += 1; + readlink_reply.path_len -= 1; + } + + /* We are considering the last part of the absolute + * path as a relative path from the mountpoint. + */ + readlink_reply.path += strlen ( nfs->mountpoint ); + readlink_reply.path_len -= strlen ( nfs->mountpoint ); + } + + new_filename = malloc ( readlink_reply.path_len + + strlen ( nfs->filename ) + 2 ); + if ( ! new_filename ) { + rc = -ENOMEM; + goto err; + } + + memcpy ( new_filename, readlink_reply.path, + readlink_reply.path_len ); + strcpy ( new_filename + readlink_reply.path_len + 1, + nfs->filename ); + new_filename[readlink_reply.path_len] = '/'; + + free ( nfs->filename - nfs->filename_offset ); + nfs->filename = new_filename; + nfs->filename_offset = 0; + + DBGC ( nfs, "NFS_OPEN %p new filename: %s\n", nfs, + nfs->filename ); + + nfs->nfs_state = NFS_LOOKUP; + nfs_step ( nfs ); + goto done; + } + + if ( nfs->nfs_state == NFS_READ_SENT ) { + if ( nfs->remaining == 0 ) { + DBGC ( nfs, "NFS_OPEN %p got READ reply\n", nfs ); + + struct nfs_read_reply read_reply; + + rc = nfs_get_read_reply ( &read_reply, &reply ); + if ( rc != 0 ) + goto err; + + if ( nfs->file_offset == 0 ) { + DBGC2 ( nfs, "NFS_OPEN %p size: %llu bytes\n", + nfs, read_reply.filesize ); + + xfer_seek ( &nfs->xfer, read_reply.filesize ); + xfer_seek ( &nfs->xfer, 0 ); + } + + nfs->file_offset += read_reply.count; + nfs->remaining = read_reply.count; + nfs->eof = read_reply.eof; + } + + size_t len = iob_len ( io_buf ); + if ( len > nfs->remaining ) + iob_unput ( io_buf, len - nfs->remaining ); + + nfs->remaining -= iob_len ( io_buf ); + + DBGC ( nfs, "NFS_OPEN %p got %zd bytes\n", nfs, + iob_len ( io_buf ) ); + + rc = xfer_deliver_iob ( &nfs->xfer, iob_disown ( io_buf ) ); + if ( rc != 0 ) + goto err; + + if ( nfs->remaining == 0 ) { + if ( ! nfs->eof ) { + nfs->nfs_state--; + nfs_step ( nfs ); + } else { + intf_shutdown ( &nfs->nfs_intf, 0 ); + nfs->nfs_state++; + nfs->mount_state++; + nfs_mount_step ( nfs ); + } + } + + return 0; + } + + rc = -EPROTO; +err: + nfs_done ( nfs, rc ); +done: + free_iob ( io_buf ); + return 0; +} + +/***************************************************************************** + * Interfaces + * + */ + +static struct interface_operation nfs_xfer_operations[] = { + INTF_OP ( intf_close, struct nfs_request *, nfs_done ), +}; + +/** NFS data transfer interface descriptor */ +static struct interface_descriptor nfs_xfer_desc = + INTF_DESC ( struct nfs_request, xfer, nfs_xfer_operations ); + +static struct interface_operation nfs_pm_operations[] = { + INTF_OP ( intf_close, struct nfs_request *, nfs_done ), + INTF_OP ( xfer_deliver, struct nfs_request *, nfs_pm_deliver ), + INTF_OP ( xfer_window_changed, struct nfs_request *, nfs_pm_step ), +}; + +static struct interface_descriptor nfs_pm_desc = + INTF_DESC ( struct nfs_request, pm_intf, nfs_pm_operations ); + +static struct interface_operation nfs_mount_operations[] = { + INTF_OP ( intf_close, struct nfs_request *, nfs_done ), + INTF_OP ( xfer_deliver, struct nfs_request *, nfs_mount_deliver ), + INTF_OP ( xfer_window_changed, struct nfs_request *, nfs_mount_step ), +}; + +static struct interface_descriptor nfs_mount_desc = + INTF_DESC ( struct nfs_request, mount_intf, nfs_mount_operations ); + +static struct interface_operation nfs_operations[] = { + INTF_OP ( intf_close, struct nfs_request *, nfs_done ), + INTF_OP ( xfer_deliver, struct nfs_request *, nfs_deliver ), + INTF_OP ( xfer_window_changed, struct nfs_request *, nfs_step ), +}; + +static struct interface_descriptor nfs_desc = + INTF_DESC_PASSTHRU ( struct nfs_request, nfs_intf, nfs_operations, + xfer ); + +/***************************************************************************** + * + * URI opener + * + */ + +static int nfs_parse_uri ( struct nfs_request *nfs, const struct uri *uri ) { + int rc; + + if ( ! uri || ! uri->host || ! uri->path ) + return -EINVAL; + + if ( ! ( nfs->path = strdup ( uri->path ) ) ) + return -ENOMEM; + + if ( ! ( nfs->hostname = strdup ( uri->host ) ) ) { + rc = -ENOMEM; + goto err_hostname; + } + + nfs->filename = basename ( nfs->path ); + nfs->mountpoint = dirname ( nfs->path ); + + if ( nfs->filename[0] == '\0' ) + goto err_filename; + + DBGC ( nfs, "NFS_OPEN %p URI parsed: (mountpoint=%s, filename=%s)\n", + nfs, nfs->mountpoint, nfs->filename ); + + return 0; + +err_filename: + rc = -EINVAL; + free ( nfs->hostname ); +err_hostname: + free ( nfs->path ); + return rc; +} + +/** + * Initiate a NFS connection + * + * @v xfer Data transfer interface + * @v uri Uniform Resource Identifier + * @ret rc Return status code + */ +static int nfs_open ( struct interface *xfer, struct uri *uri ) { + int rc; + struct nfs_request *nfs; + + nfs = zalloc ( sizeof ( *nfs ) ); + if ( ! nfs ) + return -ENOMEM; + + rc = nfs_parse_uri( nfs, uri ); + if ( rc != 0 ) + goto err_uri; + + rc = oncrpc_init_cred_sys ( &nfs->auth_sys ); + if ( rc != 0 ) + goto err_cred; + + ref_init ( &nfs->refcnt, nfs_free ); + intf_init ( &nfs->xfer, &nfs_xfer_desc, &nfs->refcnt ); + intf_init ( &nfs->pm_intf, &nfs_pm_desc, &nfs->refcnt ); + intf_init ( &nfs->mount_intf, &nfs_mount_desc, &nfs->refcnt ); + intf_init ( &nfs->nfs_intf, &nfs_desc, &nfs->refcnt ); + + portmap_init_session ( &nfs->pm_session, &nfs->auth_sys.credential ); + mount_init_session ( &nfs->mount_session, &nfs->auth_sys.credential ); + nfs_init_session ( &nfs->nfs_session, &nfs->auth_sys.credential ); + + rc = nfs_connect ( &nfs->pm_intf, PORTMAP_PORT, nfs->hostname ); + if ( rc != 0 ) + goto err_connect; + + /* Attach to parent interface, mortalise self, and return */ + intf_plug_plug ( &nfs->xfer, xfer ); + ref_put ( &nfs->refcnt ); + + return 0; + +err_connect: + free ( nfs->auth_sys.hostname ); +err_cred: +err_uri: + free ( nfs ); + return rc; +} + +/** NFS URI opener */ +struct uri_opener nfs_uri_opener __uri_opener = { + .scheme = "nfs", + .open = nfs_open, +}; diff --git a/roms/ipxe/src/net/oncrpc/oncrpc_iob.c b/roms/ipxe/src/net/oncrpc/oncrpc_iob.c new file mode 100644 index 000000000..be51805e7 --- /dev/null +++ b/roms/ipxe/src/net/oncrpc/oncrpc_iob.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/socket.h> +#include <ipxe/tcpip.h> +#include <ipxe/in.h> +#include <ipxe/iobuf.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/uri.h> +#include <ipxe/features.h> +#include <ipxe/oncrpc.h> +#include <ipxe/oncrpc_iob.h> + +/** @file + * + * SUN ONC RPC protocol + * + */ + +size_t oncrpc_iob_add_fields ( struct io_buffer *io_buf, + const struct oncrpc_field fields[] ) { + size_t i; + size_t s = 0; + + struct oncrpc_field f; + + if ( ! io_buf ) + return 0; + + for ( i = 0; fields[i].type != oncrpc_none; i++ ) { + f = fields[i]; + switch ( f.type ) { + case oncrpc_int32: + s += oncrpc_iob_add_int ( io_buf, f.value.int32 ); + break; + + case oncrpc_int64: + s += oncrpc_iob_add_int64 ( io_buf, f.value.int64 ); + break; + + case oncrpc_str: + s += oncrpc_iob_add_string ( io_buf, f.value.str ); + break; + + case oncrpc_array: + s += oncrpc_iob_add_array ( io_buf, + f.value.array.length, + f.value.array.ptr ); + break; + + case oncrpc_intarray: + s += oncrpc_iob_add_intarray ( io_buf, + f.value.intarray.length, + f.value.intarray.ptr ); + break; + + case oncrpc_cred: + s += oncrpc_iob_add_cred ( io_buf, f.value.cred); + break; + + default: + return s; + } + } + + return s; +} + +/** + * Add an array of bytes to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v val String + * @ret size Size of the data written + * + * In the ONC RPC protocol, every data is four byte paded, we add padding when + * necessary by using oncrpc_align() + */ +size_t oncrpc_iob_add_array ( struct io_buffer *io_buf, size_t length, + const void *data ) { + size_t padding = oncrpc_align ( length ) - length; + + oncrpc_iob_add_int ( io_buf, length ); + memcpy ( iob_put ( io_buf, length ), data, length ); + memset ( iob_put ( io_buf, padding ), 0, padding ); + + return length + padding + sizeof ( uint32_t ); +} + +/** + * Add an int array to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v length Length od the array + * @v val Int array + * @ret size Size of the data written + */ +size_t oncrpc_iob_add_intarray ( struct io_buffer *io_buf, size_t length, + const uint32_t *array ) { + size_t i; + + oncrpc_iob_add_int ( io_buf, length ); + + for ( i = 0; i < length; ++i ) + oncrpc_iob_add_int ( io_buf, array[i] ); + + return ( ( length + 1 ) * sizeof ( uint32_t ) ); +} + +/** + * Add credential information to the end of an I/O buffer + * + * @v io_buf I/O buffer + * @v cred Credential information + * @ret size Size of the data written + */ +size_t oncrpc_iob_add_cred ( struct io_buffer *io_buf, + const struct oncrpc_cred *cred ) { + struct oncrpc_cred_sys *syscred; + size_t s; + + struct oncrpc_field credfields[] = { + ONCRPC_FIELD ( int32, cred->flavor ), + ONCRPC_FIELD ( int32, cred->length ), + ONCRPC_FIELD_END, + }; + + if ( ! io_buf || ! cred ) + return 0; + + s = oncrpc_iob_add_fields ( io_buf, credfields); + + switch ( cred->flavor ) { + case ONCRPC_AUTH_NONE: + break; + + case ONCRPC_AUTH_SYS: + syscred = container_of ( cred, struct oncrpc_cred_sys, + credential ); + + struct oncrpc_field syscredfields[] = { + ONCRPC_FIELD ( int32, syscred->stamp ), + ONCRPC_FIELD ( str, syscred->hostname ), + ONCRPC_FIELD ( int32, syscred->uid ), + ONCRPC_FIELD ( int32, syscred->gid ), + ONCRPC_SUBFIELD ( intarray, syscred->aux_gid_len, + syscred->aux_gid ), + ONCRPC_FIELD_END, + }; + + s += oncrpc_iob_add_fields ( io_buf, syscredfields ); + break; + } + + return s; +} + +/** + * Get credential information from the beginning of an I/O buffer + * + * @v io_buf I/O buffer + * @v cred Struct where the information will be saved + * @ret size Size of the data read + */ +size_t oncrpc_iob_get_cred ( struct io_buffer *io_buf, + struct oncrpc_cred *cred ) { + if ( cred == NULL ) + return * ( uint32_t * ) io_buf->data; + + cred->flavor = oncrpc_iob_get_int ( io_buf ); + cred->length = oncrpc_iob_get_int ( io_buf ); + + iob_pull ( io_buf, cred->length ); + + return ( 2 * sizeof ( uint32_t ) + cred->length ); +} diff --git a/roms/ipxe/src/net/oncrpc/portmap.c b/roms/ipxe/src/net/oncrpc/portmap.c new file mode 100644 index 000000000..df62221dc --- /dev/null +++ b/roms/ipxe/src/net/oncrpc/portmap.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/socket.h> +#include <ipxe/tcpip.h> +#include <ipxe/in.h> +#include <ipxe/iobuf.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/uri.h> +#include <ipxe/features.h> +#include <ipxe/timer.h> +#include <ipxe/oncrpc.h> +#include <ipxe/oncrpc_iob.h> +#include <ipxe/portmap.h> + +/** @file + * + * PORTMAPPER protocol. + * + */ + +/** PORTMAP GETPORT procedure. */ +#define PORTMAP_GETPORT 3 + +/** + * Send a GETPORT request + * + * @v intf Interface to send the request on + * @v session ONC RPC session + * @v prog ONC RPC program number + * @v vers ONC RPC rogram version number + * @v proto Protocol (TCP or UDP) + * @ret rc Return status code + */ +int portmap_getport ( struct interface *intf, struct oncrpc_session *session, + uint32_t prog, uint32_t vers, uint32_t proto ) { + struct oncrpc_field fields[] = { + ONCRPC_FIELD ( int32, prog ), + ONCRPC_FIELD ( int32, vers ), + ONCRPC_FIELD ( int32, proto ), + ONCRPC_FIELD ( int32, 0 ), /* The port field is only meaningful + in GETPORT reply */ + ONCRPC_FIELD_END, + }; + + return oncrpc_call ( intf, session, PORTMAP_GETPORT, fields ); +} + +/** + * Parse a GETPORT reply + * + * @v getport_reply A structure where the data will be saved + * @v reply The ONC RPC reply to get data from + * @ret rc Return status code + */ +int portmap_get_getport_reply ( struct portmap_getport_reply *getport_reply, + struct oncrpc_reply *reply ) { + if ( ! getport_reply || ! reply ) + return -EINVAL; + + getport_reply->port = oncrpc_iob_get_int ( reply->data ); + if ( getport_reply == 0 || getport_reply->port >= 65536 ) + return -EINVAL; + + return 0; +} diff --git a/roms/ipxe/src/net/ping.c b/roms/ipxe/src/net/ping.c new file mode 100644 index 000000000..d9da87ade --- /dev/null +++ b/roms/ipxe/src/net/ping.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/refcnt.h> +#include <ipxe/list.h> +#include <ipxe/iobuf.h> +#include <ipxe/tcpip.h> +#include <ipxe/icmp.h> +#include <ipxe/interface.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/netdevice.h> +#include <ipxe/ping.h> + +/** @file + * + * ICMP ping protocol + * + */ + +/** + * A ping connection + * + */ +struct ping_connection { + /** Reference counter */ + struct refcnt refcnt; + /** List of ping connections */ + struct list_head list; + + /** Remote socket address */ + struct sockaddr_tcpip peer; + /** Local port number */ + uint16_t port; + + /** Data transfer interface */ + struct interface xfer; +}; + +/** List of registered ping connections */ +static LIST_HEAD ( ping_conns ); + +/** + * Identify ping connection by local port number + * + * @v port Local port number + * @ret ping Ping connection, or NULL + */ +static struct ping_connection * ping_demux ( unsigned int port ) { + struct ping_connection *ping; + + list_for_each_entry ( ping, &ping_conns, list ) { + if ( ping->port == port ) + return ping; + } + return NULL; +} + +/** + * Check if local port number is available + * + * @v port Local port number + * @ret port Local port number, or negative error + */ +static int ping_port_available ( int port ) { + + return ( ping_demux ( port ) ? -EADDRINUSE : port ); +} + +/** + * Process ICMP ping reply + * + * @v iobuf I/O buffer + * @v st_src Source address + * @ret rc Return status code + */ +int ping_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src ) { + struct icmp_echo *echo = iobuf->data; + struct ping_connection *ping; + struct xfer_metadata meta; + int rc; + + /* Sanity check: should already have been checked by ICMP layer */ + assert ( iob_len ( iobuf ) >= sizeof ( *echo ) ); + + /* Identify connection */ + ping = ping_demux ( ntohs ( echo->ident ) ); + DBGC ( ping, "PING %p reply id %#04x seq %#04x\n", + ping, ntohs ( echo->ident ), ntohs ( echo->sequence ) ); + if ( ! ping ) { + rc = -ENOTCONN; + goto discard; + } + + /* Strip header, construct metadata, and pass data to upper layer */ + iob_pull ( iobuf, sizeof ( *echo ) ); + memset ( &meta, 0, sizeof ( meta ) ); + meta.src = ( ( struct sockaddr * ) st_src ); + meta.flags = XFER_FL_ABS_OFFSET; + meta.offset = ntohs ( echo->sequence ); + return xfer_deliver ( &ping->xfer, iob_disown ( iobuf ), &meta ); + + discard: + free_iob ( iobuf ); + return rc; +} + +/** + * Allocate I/O buffer for ping + * + * @v ping Ping connection + * @v len Payload size + * @ret iobuf I/O buffer, or NULL + */ +static struct io_buffer * +ping_alloc_iob ( struct ping_connection *ping __unused, size_t len ) { + size_t header_len; + struct io_buffer *iobuf; + + header_len = ( MAX_LL_NET_HEADER_LEN + sizeof ( struct icmp_echo ) ); + iobuf = alloc_iob ( header_len + len ); + if ( iobuf ) + iob_reserve ( iobuf, header_len ); + return iobuf; +} + +/** + * Deliver datagram as I/O buffer + * + * @v ping Ping connection + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int ping_deliver ( struct ping_connection *ping, struct io_buffer *iobuf, + struct xfer_metadata *meta ) { + struct icmp_echo *echo = iob_push ( iobuf, sizeof ( *echo ) ); + int rc; + + /* Construct header */ + memset ( echo, 0, sizeof ( *echo ) ); + echo->ident = htons ( ping->port ); + echo->sequence = htons ( meta->offset ); + + /* Transmit echo request */ + if ( ( rc = icmp_tx_echo_request ( iob_disown ( iobuf ), + &ping->peer ) ) != 0 ) { + DBGC ( ping, "PING %p could not transmit: %s\n", + ping, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Close ping connection + * + * @v ping Ping connection + * @v rc Reason for close + */ +static void ping_close ( struct ping_connection *ping, int rc ) { + + /* Close data transfer interface */ + intf_shutdown ( &ping->xfer, rc ); + + /* Remove from list of connections and drop list's reference */ + list_del ( &ping->list ); + ref_put ( &ping->refcnt ); + + DBGC ( ping, "PING %p closed\n", ping ); +} + +/** Ping data transfer interface operations */ +static struct interface_operation ping_xfer_operations[] = { + INTF_OP ( xfer_deliver, struct ping_connection *, ping_deliver ), + INTF_OP ( xfer_alloc_iob, struct ping_connection *, ping_alloc_iob ), + INTF_OP ( intf_close, struct ping_connection *, ping_close ), +}; + +/** Ping data transfer interface descriptor */ +static struct interface_descriptor ping_xfer_desc = + INTF_DESC ( struct ping_connection, xfer, ping_xfer_operations ); + +/** + * Open a ping connection + * + * @v xfer Data transfer interface + * @v peer Peer socket address + * @v local Local socket address, or NULL + * @ret rc Return status code + */ +static int ping_open ( struct interface *xfer, struct sockaddr *peer, + struct sockaddr *local ) { + struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer; + struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local; + struct ping_connection *ping; + int port; + int rc; + + /* Allocate and initialise structure */ + ping = zalloc ( sizeof ( *ping ) ); + if ( ! ping ) { + rc = -ENOMEM; + goto err_alloc; + } + DBGC ( ping, "PING %p allocated\n", ping ); + ref_init ( &ping->refcnt, NULL ); + intf_init ( &ping->xfer, &ping_xfer_desc, &ping->refcnt ); + memcpy ( &ping->peer, st_peer, sizeof ( ping->peer ) ); + + /* Bind to local port */ + port = tcpip_bind ( st_local, ping_port_available ); + if ( port < 0 ) { + rc = port; + DBGC ( ping, "PING %p could not bind: %s\n", + ping, strerror ( rc ) ); + goto err_bind; + } + ping->port = port; + DBGC ( ping, "PING %p bound to id %#04x\n", ping, port ); + + /* Attach parent interface, transfer reference to connection + * list, and return + */ + intf_plug_plug ( &ping->xfer, xfer ); + list_add ( &ping->list, &ping_conns ); + return 0; + + err_bind: + ref_put ( &ping->refcnt ); + err_alloc: + return rc; +} + +/** Ping IPv4 socket opener */ +struct socket_opener ping_ipv4_socket_opener __socket_opener = { + .semantics = PING_SOCK_ECHO, + .family = AF_INET, + .open = ping_open, +}; + +/** Ping IPv6 socket opener */ +struct socket_opener ping_ipv6_socket_opener __socket_opener = { + .semantics = PING_SOCK_ECHO, + .family = AF_INET6, + .open = ping_open, +}; + +/** Linkage hack */ +int ping_sock_echo = PING_SOCK_ECHO; diff --git a/roms/ipxe/src/net/socket.c b/roms/ipxe/src/net/socket.c new file mode 100644 index 000000000..24f6a0892 --- /dev/null +++ b/roms/ipxe/src/net/socket.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stddef.h> +#include <errno.h> +#include <ipxe/socket.h> + +/** @file + * + * Sockets + * + */ + +/** + * Transcribe socket address + * + * @v sa Socket address + * @ret string Socket address string + */ +const char * sock_ntoa ( struct sockaddr *sa ) { + struct sockaddr_converter *converter; + + for_each_table_entry ( converter, SOCKADDR_CONVERTERS ) { + if ( converter->family == sa->sa_family ) + return converter->ntoa ( sa ); + } + return NULL; +} + +/** + * Parse socket address + * + * @v string Socket address string + * @v sa Socket address to fill in + * @ret rc Return status code + */ +int sock_aton ( const char *string, struct sockaddr *sa ) { + struct sockaddr_converter *converter; + + for_each_table_entry ( converter, SOCKADDR_CONVERTERS ) { + if ( converter->aton ( string, sa ) == 0 ) { + sa->sa_family = converter->family; + return 0; + } + } + return -EINVAL; +} diff --git a/roms/ipxe/src/net/tcp.c b/roms/ipxe/src/net/tcp.c index 938edd577..1c48769ac 100644 --- a/roms/ipxe/src/net/tcp.c +++ b/roms/ipxe/src/net/tcp.c @@ -15,6 +15,7 @@ #include <ipxe/open.h> #include <ipxe/uri.h> #include <ipxe/netdevice.h> +#include <ipxe/profile.h> #include <ipxe/tcpip.h> #include <ipxe/tcp.h> @@ -43,6 +44,8 @@ struct tcp_connection { struct sockaddr_tcpip peer; /** Local port */ unsigned int local_port; + /** Maximum segment size */ + size_t mss; /** Current TCP state */ unsigned int tcp_state; @@ -153,10 +156,20 @@ struct tcp_rx_queued_header { */ static LIST_HEAD ( tcp_conns ); +/** Transmit profiler */ +static struct profiler tcp_tx_profiler __profiler = { .name = "tcp.tx" }; + +/** Receive profiler */ +static struct profiler tcp_rx_profiler __profiler = { .name = "tcp.rx" }; + +/** Data transfer profiler */ +static struct profiler tcp_xfer_profiler __profiler = { .name = "tcp.xfer" }; + /* Forward declarations */ static struct interface_descriptor tcp_xfer_desc; static void tcp_expired ( struct retry_timer *timer, int over ); static void tcp_wait_expired ( struct retry_timer *timer, int over ); +static struct tcp_connection * tcp_demux ( unsigned int local_port ); static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, uint32_t win ); @@ -226,46 +239,14 @@ tcp_dump_flags ( struct tcp_connection *tcp, unsigned int flags ) { */ /** - * Bind TCP connection to local port + * Check if local TCP port is available * - * @v tcp TCP connection * @v port Local port number - * @ret rc Return status code - * - * If the port is 0, the connection is assigned an available port - * between 1024 and 65535. + * @ret port Local port number, or negative error */ -static int tcp_bind ( struct tcp_connection *tcp, unsigned int port ) { - struct tcp_connection *existing; - uint16_t try_port; - unsigned int i; - - /* If no port is specified, find an available port */ - if ( ! port ) { - try_port = random(); - for ( i = 0 ; i < 65536 ; i++ ) { - try_port++; - if ( try_port < 1024 ) - continue; - if ( tcp_bind ( tcp, try_port ) == 0 ) - return 0; - } - DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp ); - return -EADDRINUSE; - } +static int tcp_port_available ( int port ) { - /* Attempt bind to local port */ - list_for_each_entry ( existing, &tcp_conns, list ) { - if ( existing->local_port == port ) { - DBGC ( tcp, "TCP %p could not bind: port %d in use\n", - tcp, port ); - return -EADDRINUSE; - } - } - tcp->local_port = port; - - DBGC ( tcp, "TCP %p bound to port %d\n", tcp, port ); - return 0; + return ( tcp_demux ( port ) ? -EADDRINUSE : port ); } /** @@ -281,7 +262,8 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer, struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer; struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local; struct tcp_connection *tcp; - unsigned int bind_port; + size_t mtu; + int port; int rc; /* Allocate and initialise structure */ @@ -302,10 +284,26 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer, INIT_LIST_HEAD ( &tcp->rx_queue ); memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) ); + /* Calculate MSS */ + mtu = tcpip_mtu ( &tcp->peer ); + if ( ! mtu ) { + DBGC ( tcp, "TCP %p has no route to %s\n", + tcp, sock_ntoa ( peer ) ); + rc = -ENETUNREACH; + goto err; + } + tcp->mss = ( mtu - sizeof ( struct tcp_header ) ); + /* Bind to local port */ - bind_port = ( st_local ? ntohs ( st_local->st_port ) : 0 ); - if ( ( rc = tcp_bind ( tcp, bind_port ) ) != 0 ) + port = tcpip_bind ( st_local, tcp_port_available ); + if ( port < 0 ) { + rc = port; + DBGC ( tcp, "TCP %p could not bind: %s\n", + tcp, strerror ( rc ) ); goto err; + } + tcp->local_port = port; + DBGC ( tcp, "TCP %p bound to port %d\n", tcp, tcp->local_port ); /* Start timer to initiate SYN */ start_timer_nodelay ( &tcp->timer ); @@ -514,6 +512,9 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { uint32_t max_representable_win; int rc; + /* Start profiling */ + profile_start ( &tcp_tx_profiler ); + /* If retransmission timer is already running, do nothing */ if ( timer_running ( &tcp->timer ) ) return 0; @@ -577,7 +578,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { mssopt = iob_push ( iobuf, sizeof ( *mssopt ) ); mssopt->kind = TCP_OPTION_MSS; mssopt->length = sizeof ( *mssopt ); - mssopt->mss = htons ( TCP_MSS ); + mssopt->mss = htons ( tcp->mss ); wsopt = iob_push ( iobuf, sizeof ( *wsopt ) ); wsopt->nop = TCP_OPTION_NOP; wsopt->wsopt.kind = TCP_OPTION_WS; @@ -625,6 +626,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) { /* Clear ACK-pending flag */ tcp->flags &= ~TCP_ACK_PENDING; + profile_stop ( &tcp_tx_profiler ); return 0; } @@ -902,6 +904,9 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, } } + /* Update window size */ + tcp->snd_win = win; + /* Ignore ACKs that don't actually acknowledge any new data. * (In particular, do not stop the retransmission timer; this * avoids creating a sorceror's apprentice syndrome when a @@ -923,10 +928,9 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, pending_put ( &tcp->pending_flags ); } - /* Update SEQ and sent counters, and window size */ + /* Update SEQ and sent counters */ tcp->snd_seq = ack; tcp->snd_sent = 0; - tcp->snd_win = win; /* Remove any acknowledged data from transmit queue */ tcp_process_tx_queue ( tcp, len, NULL, 1 ); @@ -976,11 +980,13 @@ static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, tcp_rx_seq ( tcp, len ); /* Deliver data to application */ + profile_start ( &tcp_xfer_profiler ); if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) { DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n", tcp, seq, ( seq + len ), strerror ( rc ) ); return rc; } + profile_stop ( &tcp_xfer_profiler ); return 0; } @@ -1140,12 +1146,14 @@ static void tcp_process_rx_queue ( struct tcp_connection *tcp ) { * Process received packet * * @v iobuf I/O buffer + * @v netdev Network device * @v st_src Partially-filled source address * @v st_dest Partially-filled destination address * @v pshdr_csum Pseudo-header checksum * @ret rc Return status code */ static int tcp_rx ( struct io_buffer *iobuf, + struct net_device *netdev __unused, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest __unused, uint16_t pshdr_csum ) { @@ -1164,6 +1172,9 @@ static int tcp_rx ( struct io_buffer *iobuf, size_t old_xfer_window; int rc; + /* Start profiling */ + profile_start ( &tcp_rx_profiler ); + /* Sanity check packet */ if ( iob_len ( iobuf ) < sizeof ( *tcphdr ) ) { DBG ( "TCP packet too short at %zd bytes (min %zd bytes)\n", @@ -1216,9 +1227,8 @@ static int tcp_rx ( struct io_buffer *iobuf, tcp_dump_flags ( tcp, tcphdr->flags ); DBGC2 ( tcp, "\n" ); - /* If no connection was found, send RST */ + /* If no connection was found, silently drop packet */ if ( ! tcp ) { - tcp_xmit_reset ( tcp, st_src, tcphdr ); rc = -ENOTCONN; goto discard; } @@ -1277,6 +1287,7 @@ static int tcp_rx ( struct io_buffer *iobuf, if ( tcp_xfer_window ( tcp ) != old_xfer_window ) xfer_window_changed ( &tcp->xfer ); + profile_stop ( &tcp_rx_profiler ); return 0; discard: @@ -1420,13 +1431,20 @@ static struct interface_descriptor tcp_xfer_desc = *************************************************************************** */ -/** TCP socket opener */ -struct socket_opener tcp_socket_opener __socket_opener = { +/** TCP IPv4 socket opener */ +struct socket_opener tcp_ipv4_socket_opener __socket_opener = { .semantics = TCP_SOCK_STREAM, .family = AF_INET, .open = tcp_open, }; +/** TCP IPv6 socket opener */ +struct socket_opener tcp_ipv6_socket_opener __socket_opener = { + .semantics = TCP_SOCK_STREAM, + .family = AF_INET6, + .open = tcp_open, +}; + /** Linkage hack */ int tcp_sock_stream = TCP_SOCK_STREAM; diff --git a/roms/ipxe/src/net/tcp/ftp.c b/roms/ipxe/src/net/tcp/ftp.c index 9f93fb66f..be7a7c3b5 100644 --- a/roms/ipxe/src/net/tcp/ftp.c +++ b/roms/ipxe/src/net/tcp/ftp.c @@ -23,6 +23,7 @@ #include <string.h> #include <assert.h> #include <errno.h> +#include <ctype.h> #include <byteswap.h> #include <ipxe/socket.h> #include <ipxe/tcpip.h> @@ -460,6 +461,25 @@ static struct interface_descriptor ftp_xfer_desc = */ /** + * Check validity of FTP control channel string + * + * @v string String + * @ret rc Return status code + */ +static int ftp_check_string ( const char *string ) { + char c; + + /* The FTP control channel is line-based. Check for invalid + * non-printable characters (e.g. newlines). + */ + while ( ( c = *(string++) ) ) { + if ( ! isprint ( c ) ) + return -EINVAL; + } + return 0; +} + +/** * Initiate an FTP connection * * @v xfer Data transfer interface @@ -472,10 +492,17 @@ static int ftp_open ( struct interface *xfer, struct uri *uri ) { int rc; /* Sanity checks */ - if ( ! uri->path ) - return -EINVAL; if ( ! uri->host ) return -EINVAL; + if ( ! uri->path ) + return -EINVAL; + if ( ( rc = ftp_check_string ( uri->path ) ) != 0 ) + return rc; + if ( uri->user && ( ( rc = ftp_check_string ( uri->user ) ) != 0 ) ) + return rc; + if ( uri->password && + ( ( rc = ftp_check_string ( uri->password ) ) != 0 ) ) + return rc; /* Allocate and populate structure */ ftp = zalloc ( sizeof ( *ftp ) ); diff --git a/roms/ipxe/src/net/tcp/httpcore.c b/roms/ipxe/src/net/tcp/httpcore.c index bccb35f5f..1d1953e61 100644 --- a/roms/ipxe/src/net/tcp/httpcore.c +++ b/roms/ipxe/src/net/tcp/httpcore.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <strings.h> #include <byteswap.h> #include <errno.h> +#include <ctype.h> #include <assert.h> #include <ipxe/uri.h> #include <ipxe/refcnt.h> @@ -42,6 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/socket.h> #include <ipxe/tcpip.h> #include <ipxe/process.h> +#include <ipxe/retry.h> +#include <ipxe/timer.h> #include <ipxe/linebuf.h> #include <ipxe/base64.h> #include <ipxe/base16.h> @@ -49,6 +52,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/blockdev.h> #include <ipxe/acpi.h> #include <ipxe/version.h> +#include <ipxe/params.h> +#include <ipxe/profile.h> #include <ipxe/http.h> /* Disambiguate the various error causes */ @@ -86,6 +91,15 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Block size used for HTTP block device request */ #define HTTP_BLKSIZE 512 +/** Retry delay used when we cannot understand the Retry-After header */ +#define HTTP_RETRY_SECONDS 5 + +/** Receive profiler */ +static struct profiler http_rx_profiler __profiler = { .name = "http.rx" }; + +/** Data transfer profiler */ +static struct profiler http_xfer_profiler __profiler = { .name = "http.xfer" }; + /** HTTP flags */ enum http_flags { /** Request is waiting to be transmitted */ @@ -102,6 +116,8 @@ enum http_flags { HTTP_BASIC_AUTH = 0x0020, /** Provide Digest authentication details */ HTTP_DIGEST_AUTH = 0x0040, + /** Socket must be reopened */ + HTTP_REOPEN_SOCKET = 0x0080, }; /** HTTP receive state */ @@ -178,6 +194,11 @@ struct http_request { char *auth_nonce; /** Authentication opaque string (if any) */ char *auth_opaque; + + /** Request retry timer */ + struct retry_timer timer; + /** Retry delay (in timer ticks) */ + unsigned long retry_delay; }; /** @@ -249,12 +270,42 @@ static int http_socket_open ( struct http_request *http ) { } /** + * Retry HTTP request + * + * @v timer Retry timer + * @v fail Failure indicator + */ +static void http_retry ( struct retry_timer *timer, int fail __unused ) { + struct http_request *http = + container_of ( timer, struct http_request, timer ); + int rc; + + /* Reopen socket if required */ + if ( http->flags & HTTP_REOPEN_SOCKET ) { + http->flags &= ~HTTP_REOPEN_SOCKET; + DBGC ( http, "HTTP %p reopening connection\n", http ); + if ( ( rc = http_socket_open ( http ) ) != 0 ) { + http_close ( http, rc ); + return; + } + } + + /* Retry the request if applicable */ + if ( http->flags & HTTP_TRY_AGAIN ) { + http->flags &= ~HTTP_TRY_AGAIN; + DBGC ( http, "HTTP %p retrying request\n", http ); + http->flags |= HTTP_TX_PENDING; + http->rx_state = HTTP_RX_RESPONSE; + process_add ( &http->process ); + } +} + +/** * Mark HTTP request as completed successfully * * @v http HTTP request */ static void http_done ( struct http_request *http ) { - int rc; /* If we are not at an appropriate stage of the protocol * (including being in the middle of a chunked transfer), @@ -295,25 +346,18 @@ static void http_done ( struct http_request *http ) { } /* If the server is not intending to keep the connection - * alive, then reopen the socket. + * alive, then close the socket and mark it as requiring + * reopening. */ if ( ! ( http->flags & HTTP_SERVER_KEEPALIVE ) ) { - DBGC ( http, "HTTP %p reopening connection\n", http ); intf_restart ( &http->socket, 0 ); - if ( ( rc = http_socket_open ( http ) ) != 0 ) { - http_close ( http, rc ); - return; - } + http->flags &= ~HTTP_SERVER_KEEPALIVE; + http->flags |= HTTP_REOPEN_SOCKET; } - http->flags &= ~HTTP_SERVER_KEEPALIVE; - /* Retry the request if applicable */ - if ( http->flags & HTTP_TRY_AGAIN ) { - http->flags &= ~HTTP_TRY_AGAIN; - http->flags |= HTTP_TX_PENDING; - http->rx_state = HTTP_RX_RESPONSE; - process_add ( &http->process ); - } + /* Start request retry timer */ + start_timer_fixed ( &http->timer, http->retry_delay ); + http->retry_delay = 0; } /** @@ -405,7 +449,7 @@ static int http_rx_content_length ( struct http_request *http, char *value ) { /* Parse content length */ content_len = strtoul ( value, &endp, 10 ); - if ( *endp != '\0' ) { + if ( ! ( ( *endp == '\0' ) || isspace ( *endp ) ) ) { DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n", http, value ); return -EINVAL_CONTENT_LENGTH; @@ -635,6 +679,39 @@ static int http_rx_www_authenticate ( struct http_request *http, char *value ) { return 0; } +/** + * Handle HTTP Retry-After header + * + * @v http HTTP request + * @v value HTTP header value + * @ret rc Return status code + */ +static int http_rx_retry_after ( struct http_request *http, char *value ) { + unsigned long seconds; + char *endp; + + DBGC ( http, "HTTP %p retry requested (%s)\n", http, value ); + + /* If we received a 503 Service Unavailable response, then + * retry after the specified number of seconds. If the value + * is not a simple number of seconds (e.g. a full HTTP date), + * then retry after a fixed delay, since we don't have code + * able to parse full HTTP dates. + */ + if ( http->code == 503 ) { + seconds = strtoul ( value, &endp, 10 ); + if ( *endp != '\0' ) { + seconds = HTTP_RETRY_SECONDS; + DBGC ( http, "HTTP %p cannot understand \"%s\"; " + "using %ld seconds\n", http, value, seconds ); + } + http->flags |= HTTP_TRY_AGAIN; + http->retry_delay = ( seconds * TICKS_PER_SEC ); + } + + return 0; +} + /** An HTTP header handler */ struct http_header_handler { /** Name (e.g. "Content-Length") */ @@ -672,6 +749,10 @@ static struct http_header_handler http_header_handlers[] = { .header = "WWW-Authenticate", .rx = http_rx_www_authenticate, }, + { + .header = "Retry-After", + .rx = http_rx_retry_after, + }, { NULL, NULL } }; @@ -818,6 +899,7 @@ static int http_socket_deliver ( struct http_request *http, ssize_t line_len; int rc = 0; + profile_start ( &http_rx_profiler ); while ( iobuf && iob_len ( iobuf ) ) { switch ( http->rx_state ) { @@ -853,16 +935,20 @@ static int http_socket_deliver ( struct http_request *http, iob_pull ( iobuf, data_len ); } else if ( data_len < iob_len ( iobuf ) ) { /* Deliver partial buffer as raw data */ + profile_start ( &http_xfer_profiler ); rc = xfer_deliver_raw ( &http->xfer, iobuf->data, data_len ); iob_pull ( iobuf, data_len ); if ( rc != 0 ) goto done; + profile_stop ( &http_xfer_profiler ); } else { /* Deliver whole I/O buffer */ + profile_start ( &http_xfer_profiler ); if ( ( rc = xfer_deliver_iob ( &http->xfer, iob_disown ( iobuf ) ) ) != 0 ) goto done; + profile_stop ( &http_xfer_profiler ); } http->rx_len += data_len; if ( http->chunk_remaining ) { @@ -911,6 +997,7 @@ static int http_socket_deliver ( struct http_request *http, if ( rc ) http_close ( http, rc ); free_iob ( iobuf ); + profile_stop ( &http_rx_profiler ); return rc; } @@ -957,8 +1044,8 @@ static void http_socket_close ( struct http_request *http, int rc ) { */ static char * http_basic_auth ( struct http_request *http ) { const char *user = http->uri->user; - const char *password = - ( http->uri->password ? http->uri->password : "" ); + const char *password = ( http->uri->password ? + http->uri->password : "" ); size_t user_pw_len = ( strlen ( user ) + 1 /* ":" */ + strlen ( password ) ); char user_pw[ user_pw_len + 1 /* NUL */ ]; @@ -999,8 +1086,8 @@ static char * http_basic_auth ( struct http_request *http ) { static char * http_digest_auth ( struct http_request *http, const char *method, const char *uri ) { const char *user = http->uri->user; - const char *password = - ( http->uri->password ? http->uri->password : "" ); + const char *password = ( http->uri->password ? + http->uri->password : "" ); const char *realm = http->auth_realm; const char *nonce = http->auth_nonce; const char *opaque = http->auth_opaque; @@ -1060,16 +1147,102 @@ static char * http_digest_auth ( struct http_request *http, } /** + * Generate HTTP POST parameter list + * + * @v http HTTP request + * @v buf Buffer to contain HTTP POST parameters + * @v len Length of buffer + * @ret len Length of parameter list (excluding terminating NUL) + */ +static size_t http_post_params ( struct http_request *http, + char *buf, size_t len ) { + struct parameter *param; + ssize_t remaining = len; + size_t frag_len; + + /* Add each parameter in the form "key=value", joined with "&" */ + len = 0; + for_each_param ( param, http->uri->params ) { + + /* Add the "&", if applicable */ + if ( len ) { + if ( remaining > 0 ) + *buf = '&'; + buf++; + len++; + remaining--; + } + + /* URI-encode the key */ + frag_len = uri_encode ( param->key, 0, buf, remaining ); + buf += frag_len; + len += frag_len; + remaining -= frag_len; + + /* Add the "=" */ + if ( remaining > 0 ) + *buf = '='; + buf++; + len++; + remaining--; + + /* URI-encode the value */ + frag_len = uri_encode ( param->value, 0, buf, remaining ); + buf += frag_len; + len += frag_len; + remaining -= frag_len; + } + + /* Ensure string is NUL-terminated even if no parameters are present */ + if ( remaining > 0 ) + *buf = '\0'; + + return len; +} + +/** + * Generate HTTP POST body + * + * @v http HTTP request + * @ret post I/O buffer containing POST body, or NULL on error + */ +static struct io_buffer * http_post ( struct http_request *http ) { + struct io_buffer *post; + size_t len; + size_t check_len; + + /* Calculate length of parameter list */ + len = http_post_params ( http, NULL, 0 ); + + /* Allocate parameter list */ + post = alloc_iob ( len + 1 /* NUL */ ); + if ( ! post ) + return NULL; + + /* Fill parameter list */ + check_len = http_post_params ( http, iob_put ( post, len ), + ( len + 1 /* NUL */ ) ); + assert ( len == check_len ); + DBGC ( http, "HTTP %p POST %s\n", http, ( ( char * ) post->data ) ); + + return post; +} + +/** * HTTP process * * @v http HTTP request */ static void http_step ( struct http_request *http ) { - size_t uri_len; + struct io_buffer *post; + struct uri host_uri; + struct uri path_uri; + char *host_uri_string; + char *path_uri_string; char *method; - char *uri; char *range; char *auth; + char *content; int len; int rc; @@ -1088,21 +1261,27 @@ static void http_step ( struct http_request *http ) { } /* Determine method */ - method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" : "GET" ); - - /* Construct path?query request */ - uri_len = ( unparse_uri ( NULL, 0, http->uri, - URI_PATH_BIT | URI_QUERY_BIT ) - + 1 /* possible "/" */ + 1 /* NUL */ ); - uri = malloc ( uri_len ); - if ( ! uri ) { + method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" : + ( http->uri->params ? "POST" : "GET" ) ); + + /* Construct host URI */ + memset ( &host_uri, 0, sizeof ( host_uri ) ); + host_uri.host = http->uri->host; + host_uri.port = http->uri->port; + host_uri_string = format_uri_alloc ( &host_uri ); + if ( ! host_uri_string ) { rc = -ENOMEM; - goto err_uri; + goto err_host_uri; } - unparse_uri ( uri, uri_len, http->uri, URI_PATH_BIT | URI_QUERY_BIT ); - if ( ! uri[0] ) { - uri[0] = '/'; - uri[1] = '\0'; + + /* Construct path URI */ + memset ( &path_uri, 0, sizeof ( path_uri ) ); + path_uri.path = ( http->uri->path ? http->uri->path : "/" ); + path_uri.query = http->uri->query; + path_uri_string = format_uri_alloc ( &path_uri ); + if ( ! path_uri_string ) { + rc = -ENOMEM; + goto err_path_uri; } /* Calculate range request parameters if applicable */ @@ -1127,7 +1306,7 @@ static void http_step ( struct http_request *http ) { goto err_auth; } } else if ( http->flags & HTTP_DIGEST_AUTH ) { - auth = http_digest_auth ( http, method, uri ); + auth = http_digest_auth ( http, method, path_uri_string ); if ( ! auth ) { rc = -ENOMEM; goto err_auth; @@ -1136,6 +1315,25 @@ static void http_step ( struct http_request *http ) { auth = NULL; } + /* Construct POST content, if applicable */ + if ( http->uri->params ) { + post = http_post ( http ); + if ( ! post ) { + rc = -ENOMEM; + goto err_post; + } + len = asprintf ( &content, "Content-Type: " + "application/x-www-form-urlencoded\r\n" + "Content-Length: %zd\r\n", iob_len ( post ) ); + if ( len < 0 ) { + rc = len; + goto err_content; + } + } else { + post = NULL; + content = NULL; + } + /* Mark request as transmitted */ http->flags &= ~HTTP_TX_PENDING; @@ -1143,28 +1341,40 @@ static void http_step ( struct http_request *http ) { if ( ( rc = xfer_printf ( &http->socket, "%s %s HTTP/1.1\r\n" "User-Agent: iPXE/%s\r\n" - "Host: %s%s%s\r\n" - "%s%s%s" + "Host: %s\r\n" + "%s%s%s%s" "\r\n", - method, uri, product_version, http->uri->host, - ( http->uri->port ? - ":" : "" ), - ( http->uri->port ? - http->uri->port : "" ), + method, path_uri_string, product_version, + host_uri_string, ( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ? "Connection: keep-alive\r\n" : "" ), ( range ? range : "" ), - ( auth ? auth : "" ) ) ) != 0 ) { + ( auth ? auth : "" ), + ( content ? content : "" ) ) ) != 0 ) { goto err_xfer; } + /* Send POST content, if applicable */ + if ( post ) { + if ( ( rc = xfer_deliver_iob ( &http->socket, + iob_disown ( post ) ) ) != 0 ) + goto err_xfer_post; + } + + err_xfer_post: err_xfer: + free ( content ); + err_content: + free ( post ); + err_post: free ( auth ); err_auth: free ( range ); err_range: - free ( uri ); - err_uri: + free ( path_uri_string ); + err_path_uri: + free ( host_uri_string ); + err_host_uri: if ( rc != 0 ) http_close ( http, rc ); } @@ -1343,6 +1553,7 @@ int http_open_filter ( struct interface *xfer, struct uri *uri, http->filter = filter; intf_init ( &http->socket, &http_socket_desc, &http->refcnt ); process_init ( &http->process, &http_process_desc, &http->refcnt ); + timer_init ( &http->timer, http_retry, &http->refcnt ); http->flags = HTTP_TX_PENDING; /* Open socket */ diff --git a/roms/ipxe/src/net/tcp/iscsi.c b/roms/ipxe/src/net/tcp/iscsi.c index c9daf1ff4..a6fcd251b 100644 --- a/roms/ipxe/src/net/tcp/iscsi.c +++ b/roms/ipxe/src/net/tcp/iscsi.c @@ -1860,7 +1860,8 @@ enum iscsi_root_path_component { }; /** iSCSI initiator IQN setting */ -struct setting initiator_iqn_setting __setting ( SETTING_SANBOOT_EXTRA ) = { +const struct setting initiator_iqn_setting __setting ( SETTING_SANBOOT_EXTRA, + initiator-iqn ) = { .name = "initiator-iqn", .description = "iSCSI initiator name", .tag = DHCP_ISCSI_INITIATOR_IQN, @@ -1868,7 +1869,8 @@ struct setting initiator_iqn_setting __setting ( SETTING_SANBOOT_EXTRA ) = { }; /** iSCSI reverse username setting */ -struct setting reverse_username_setting __setting ( SETTING_AUTH_EXTRA ) = { +const struct setting reverse_username_setting __setting ( SETTING_AUTH_EXTRA, + reverse-username ) = { .name = "reverse-username", .description = "Reverse user name", .tag = DHCP_EB_REVERSE_USERNAME, @@ -1876,7 +1878,8 @@ struct setting reverse_username_setting __setting ( SETTING_AUTH_EXTRA ) = { }; /** iSCSI reverse password setting */ -struct setting reverse_password_setting __setting ( SETTING_AUTH_EXTRA ) = { +const struct setting reverse_password_setting __setting ( SETTING_AUTH_EXTRA, + reverse-password ) = { .name = "reverse-password", .description = "Reverse password", .tag = DHCP_EB_REVERSE_PASSWORD, @@ -1947,46 +1950,23 @@ static int iscsi_fetch_settings ( struct iscsi_session *iscsi ) { /* Fetch relevant settings. Don't worry about freeing on * error, since iscsi_free() will take care of that anyway. */ - if ( ( len = fetch_string_setting_copy ( NULL, &username_setting, - &iscsi->initiator_username ) ) < 0 ) { - DBGC ( iscsi, "iSCSI %p could not fetch username: %s\n", - iscsi, strerror ( len ) ); - return len; - } - if ( ( len = fetch_string_setting_copy ( NULL, &password_setting, - &iscsi->initiator_password ) ) < 0 ) { - DBGC ( iscsi, "iSCSI %p could not fetch password: %s\n", - iscsi, strerror ( len ) ); - return len; - } - if ( ( len = fetch_string_setting_copy( NULL, &reverse_username_setting, - &iscsi->target_username ) ) < 0 ) { - DBGC ( iscsi, "iSCSI %p could not fetch reverse username: %s\n", - iscsi, strerror ( len ) ); - return len; - } - if ( ( len = fetch_string_setting_copy( NULL, &reverse_password_setting, - &iscsi->target_password ) ) < 0 ) { - DBGC ( iscsi, "iSCSI %p could not fetch reverse password: %s\n", - iscsi, strerror ( len ) ); - return len; - } - - /* Find a suitable initiator name */ - if ( ( len = fetch_string_setting_copy ( NULL, &initiator_iqn_setting, - &iscsi->initiator_iqn ) ) < 0 ) { - DBGC ( iscsi, "iSCSI %p could not fetch initiator IQN: %s\n", - iscsi, strerror ( len ) ); - return len; - } + fetch_string_setting_copy ( NULL, &username_setting, + &iscsi->initiator_username ); + fetch_string_setting_copy ( NULL, &password_setting, + &iscsi->initiator_password ); + fetch_string_setting_copy ( NULL, &reverse_username_setting, + &iscsi->target_username ); + fetch_string_setting_copy ( NULL, &reverse_password_setting, + &iscsi->target_password ); + + /* Use explicit initiator IQN if provided */ + fetch_string_setting_copy ( NULL, &initiator_iqn_setting, + &iscsi->initiator_iqn ); if ( iscsi->initiator_iqn ) return 0; - if ( ( len = fetch_string_setting_copy ( NULL, &hostname_setting, - &hostname ) ) < 0 ) { - DBGC ( iscsi, "iSCSI %p could not fetch hostname: %s\n", - iscsi, strerror ( len ) ); - return len; - } + + /* Otherwise, try to construct an initiator IQN from the hostname */ + fetch_string_setting_copy ( NULL, &hostname_setting, &hostname ); if ( hostname ) { len = asprintf ( &iscsi->initiator_iqn, ISCSI_DEFAULT_IQN_PREFIX ":%s", hostname ); @@ -1999,6 +1979,8 @@ static int iscsi_fetch_settings ( struct iscsi_session *iscsi ) { assert ( iscsi->initiator_iqn ); return 0; } + + /* Otherwise, try to construct an initiator IQN from the UUID */ if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) { DBGC ( iscsi, "iSCSI %p has no suitable initiator IQN\n", iscsi ); diff --git a/roms/ipxe/src/net/tcp/oncrpc.c b/roms/ipxe/src/net/tcp/oncrpc.c new file mode 100644 index 000000000..cd33ece02 --- /dev/null +++ b/roms/ipxe/src/net/tcp/oncrpc.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/socket.h> +#include <ipxe/tcpip.h> +#include <ipxe/in.h> +#include <ipxe/iobuf.h> +#include <ipxe/dhcp.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/uri.h> +#include <ipxe/features.h> +#include <ipxe/oncrpc.h> +#include <ipxe/oncrpc_iob.h> +#include <ipxe/init.h> +#include <ipxe/settings.h> +#include <config/general.h> + +/** @file + * + * SUN ONC RPC protocol + * + */ + +/** Set most significant bit to 1. */ +#define SET_LAST_FRAME( x ) ( (x) | 1 << 31 ) +#define GET_FRAME_SIZE( x ) ( (x) & ~( 1 << 31 ) ) + +#define ONCRPC_CALL 0 +#define ONCRPC_REPLY 1 + +/** AUTH NONE authentication flavor */ +struct oncrpc_cred oncrpc_auth_none = { + .flavor = ONCRPC_AUTH_NONE, + .length = 0 +}; + +const struct setting uid_setting __setting ( SETTING_AUTH, uid ) = { + .name = "uid", + .description = "User ID", + .tag = DHCP_EB_UID, + .type = &setting_type_uint32 +}; + +const struct setting gid_setting __setting ( SETTING_AUTH, gid ) = { + .name = "gid", + .description = "Group ID", + .tag = DHCP_EB_GID, + .type = &setting_type_uint32 +}; + +/** + * Initialize an ONC RPC AUTH SYS credential structure + * + * @v auth_sys The structure to initialize + * + * The hostname field is filled with the value of the hostname setting, if the + * hostname setting is empty, PRODUCT_SHORT_NAME (usually "iPXE") is used + * instead. + */ +int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys ) { + if ( ! auth_sys ) + return -EINVAL; + + fetch_string_setting_copy ( NULL, &hostname_setting, + &auth_sys->hostname ); + if ( ! auth_sys->hostname ) + if ( ! ( auth_sys->hostname = strdup ( PRODUCT_SHORT_NAME ) ) ) + return -ENOMEM; + + auth_sys->uid = fetch_uintz_setting ( NULL, &uid_setting ); + auth_sys->gid = fetch_uintz_setting ( NULL, &uid_setting ); + auth_sys->aux_gid_len = 0; + auth_sys->stamp = 0; + + auth_sys->credential.flavor = ONCRPC_AUTH_SYS; + auth_sys->credential.length = 16 + + oncrpc_strlen ( auth_sys->hostname ); + + return 0; +} + +/** + * Prepare an ONC RPC session structure to be used by the ONC RPC layer + * + * @v session ONC RPC session + * @v credential Credential structure pointer + * @v verifier Verifier structure pointer + * @v prog_name ONC RPC program number + * @v prog_vers ONC RPC program version number + */ +void oncrpc_init_session ( struct oncrpc_session *session, + struct oncrpc_cred *credential, + struct oncrpc_cred *verifier, uint32_t prog_name, + uint32_t prog_vers ) { + if ( ! session ) + return; + + session->rpc_id = rand(); + session->credential = credential; + session->verifier = verifier; + session->prog_name = prog_name; + session->prog_vers = prog_vers; +} + +int oncrpc_call ( struct interface *intf, struct oncrpc_session *session, + uint32_t proc_name, const struct oncrpc_field fields[] ) { + int rc; + size_t frame_size; + struct io_buffer *io_buf; + + if ( ! session ) + return -EINVAL; + + struct oncrpc_field header[] = { + ONCRPC_FIELD ( int32, 0 ), + ONCRPC_FIELD ( int32, ++session->rpc_id ), + ONCRPC_FIELD ( int32, ONCRPC_CALL ), + ONCRPC_FIELD ( int32, ONCRPC_VERS ), + ONCRPC_FIELD ( int32, session->prog_name ), + ONCRPC_FIELD ( int32, session->prog_vers ), + ONCRPC_FIELD ( int32, proc_name ), + ONCRPC_FIELD ( cred, session->credential ), + ONCRPC_FIELD ( cred, session->verifier ), + ONCRPC_FIELD_END, + }; + + frame_size = oncrpc_compute_size ( header ); + frame_size += oncrpc_compute_size ( fields ); + + io_buf = alloc_iob ( frame_size ); + if ( ! io_buf ) + return -ENOBUFS; + + header[0].value.int32 = SET_LAST_FRAME ( frame_size - + sizeof ( uint32_t ) ); + + oncrpc_iob_add_fields ( io_buf, header ); + oncrpc_iob_add_fields ( io_buf, fields ); + + rc = xfer_deliver_iob ( intf, io_buf ); + if ( rc != 0 ) + free_iob ( io_buf ); + + return rc; +} + +size_t oncrpc_compute_size ( const struct oncrpc_field fields[] ) { + + size_t i; + size_t size = 0; + + for ( i = 0; fields[i].type != oncrpc_none; i++ ) { + switch ( fields[i].type ) { + case oncrpc_int32: + size += sizeof ( uint32_t ); + break; + + case oncrpc_int64: + size += sizeof ( uint64_t ); + break; + + case oncrpc_str: + size += oncrpc_strlen ( fields[i].value.str ); + break; + + case oncrpc_array: + size += oncrpc_align ( fields[i].value.array.length ); + size += sizeof ( uint32_t ); + break; + + case oncrpc_intarray: + size += sizeof ( uint32_t ) * + fields[i].value.intarray.length; + size += sizeof ( uint32_t ); + break; + + case oncrpc_cred: + size += fields[i].value.cred->length; + size += 2 * sizeof ( uint32_t ); + break; + + default: + return size; + } + } + + return size; +} + +/** + * Parse an I/O buffer to extract a ONC RPC REPLY + * @v session ONC RPC session + * @v reply Reply structure where data will be saved + * @v io_buf I/O buffer + */ +int oncrpc_get_reply ( struct oncrpc_session *session __unused, + struct oncrpc_reply *reply, struct io_buffer *io_buf ) { + if ( ! reply || ! io_buf ) + return -EINVAL; + + reply->frame_size = GET_FRAME_SIZE ( oncrpc_iob_get_int ( io_buf ) ); + reply->rpc_id = oncrpc_iob_get_int ( io_buf ); + + /* iPXE has no support for handling ONC RPC call */ + if ( oncrpc_iob_get_int ( io_buf ) != ONCRPC_REPLY ) + return -ENOSYS; + + reply->reply_state = oncrpc_iob_get_int ( io_buf ); + + if ( reply->reply_state == 0 ) + { + /* verifier.flavor */ + oncrpc_iob_get_int ( io_buf ); + /* verifier.length */ + iob_pull ( io_buf, oncrpc_iob_get_int ( io_buf )); + + /* We don't use the verifier in iPXE, let it be an empty + verifier. */ + reply->verifier = &oncrpc_auth_none; + } + + reply->accept_state = oncrpc_iob_get_int ( io_buf ); + reply->data = io_buf; + + return 0; +} diff --git a/roms/ipxe/src/net/tcp/syslogs.c b/roms/ipxe/src/net/tcp/syslogs.c index dae6ba18b..095afc543 100644 --- a/roms/ipxe/src/net/tcp/syslogs.c +++ b/roms/ipxe/src/net/tcp/syslogs.c @@ -49,7 +49,6 @@ struct console_driver syslogs_console __console_driver; /** The encrypted syslog server */ static struct sockaddr_tcpip logserver = { - .st_family = AF_INET, .st_port = htons ( SYSLOG_PORT ), }; @@ -113,10 +112,12 @@ static unsigned int syslogs_severity = SYSLOG_DEFAULT_SEVERITY; /** * Handle ANSI set encrypted syslog priority (private sequence) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params List of graphic rendition aspects */ -static void syslogs_handle_priority ( unsigned int count __unused, +static void syslogs_handle_priority ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, int params[] ) { if ( params[0] >= 0 ) { syslogs_severity = params[0]; @@ -176,7 +177,7 @@ static void syslogs_putchar ( int character ) { /** Encrypted syslog console driver */ struct console_driver syslogs_console __console_driver = { .putchar = syslogs_putchar, - .disabled = 1, + .disabled = CONSOLE_DISABLED, .usage = CONSOLE_SYSLOGS, }; @@ -188,7 +189,7 @@ struct console_driver syslogs_console __console_driver = { */ /** Encrypted syslog server setting */ -struct setting syslogs_setting __setting ( SETTING_MISC ) = { +const struct setting syslogs_setting __setting ( SETTING_MISC, syslogs ) = { .name = "syslogs", .description = "Encrypted syslog server", .tag = DHCP_EB_SYSLOGS_SERVER, @@ -204,15 +205,10 @@ static int apply_syslogs_settings ( void ) { static char *old_server; char *server; struct interface *socket; - int len; int rc; /* Fetch log server */ - len = fetch_string_setting_copy ( NULL, &syslogs_setting, &server ); - if ( len < 0 ) { - rc = len; - goto err_fetch_server; - } + fetch_string_setting_copy ( NULL, &syslogs_setting, &server ); /* Do nothing unless log server has changed */ if ( ( ( server == NULL ) && ( old_server == NULL ) ) || @@ -225,7 +221,7 @@ static int apply_syslogs_settings ( void ) { old_server = NULL; /* Reset encrypted syslog connection */ - syslogs_console.disabled = 1; + syslogs_console.disabled = CONSOLE_DISABLED; intf_restart ( &syslogs, 0 ); /* Do nothing unless we have a log server */ @@ -264,7 +260,6 @@ static int apply_syslogs_settings ( void ) { out_no_server: out_no_change: free ( server ); - err_fetch_server: return rc; } diff --git a/roms/ipxe/src/net/tcpip.c b/roms/ipxe/src/net/tcpip.c index 8e187f7ec..4bcbe64bb 100644 --- a/roms/ipxe/src/net/tcpip.c +++ b/roms/ipxe/src/net/tcpip.c @@ -1,9 +1,12 @@ #include <stdint.h> +#include <stdlib.h> #include <string.h> #include <errno.h> #include <byteswap.h> #include <ipxe/iobuf.h> #include <ipxe/tables.h> +#include <ipxe/ipstat.h> +#include <ipxe/netdevice.h> #include <ipxe/tcpip.h> /** @file @@ -16,13 +19,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); -/** Process a received TCP/IP packet +/** + * Process a received TCP/IP packet * * @v iobuf I/O buffer + * @v netdev Network device * @v tcpip_proto Transport-layer protocol number * @v st_src Partially-filled source address * @v st_dest Partially-filled destination address * @v pshdr_csum Pseudo-header checksum + * @v stats IP statistics * @ret rc Return status code * * This function expects a transport-layer segment from the network @@ -31,26 +37,49 @@ FILE_LICENCE ( GPL2_OR_LATER ); * address family and the network-layer addresses, but leave the ports * and the rest of the structures as zero). */ -int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto, - struct sockaddr_tcpip *st_src, - struct sockaddr_tcpip *st_dest, - uint16_t pshdr_csum ) { +int tcpip_rx ( struct io_buffer *iobuf, struct net_device *netdev, + uint8_t tcpip_proto, struct sockaddr_tcpip *st_src, + struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum, + struct ip_statistics *stats ) { struct tcpip_protocol *tcpip; /* Hand off packet to the appropriate transport-layer protocol */ for_each_table_entry ( tcpip, TCPIP_PROTOCOLS ) { if ( tcpip->tcpip_proto == tcpip_proto ) { DBG ( "TCP/IP received %s packet\n", tcpip->name ); - return tcpip->rx ( iobuf, st_src, st_dest, pshdr_csum ); + stats->in_delivers++; + return tcpip->rx ( iobuf, netdev, st_src, st_dest, + pshdr_csum ); } } DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto ); + stats->in_unknown_protos++; free_iob ( iobuf ); return -EPROTONOSUPPORT; } -/** Transmit a TCP/IP packet +/** + * Find TCP/IP network-layer protocol + * + * @v st_dest Destination address + * @ret tcpip_net TCP/IP network-layer protocol, or NULL if not found + */ +static struct tcpip_net_protocol * +tcpip_net_protocol ( struct sockaddr_tcpip *st_dest ) { + struct tcpip_net_protocol *tcpip_net; + + for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) { + if ( tcpip_net->sa_family == st_dest->st_family ) + return tcpip_net; + } + + DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family ); + return NULL; +} + +/** + * Transmit a TCP/IP packet * * @v iobuf I/O buffer * @v tcpip_protocol Transport-layer protocol @@ -66,20 +95,63 @@ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, struct tcpip_net_protocol *tcpip_net; /* Hand off packet to the appropriate network-layer protocol */ - for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) { - if ( tcpip_net->sa_family == st_dest->st_family ) { - DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); - return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, - st_dest, netdev, trans_csum ); - } + tcpip_net = tcpip_net_protocol ( st_dest ); + if ( tcpip_net ) { + DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); + return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, st_dest, + netdev, trans_csum ); } - - DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family ); + free_iob ( iobuf ); return -EAFNOSUPPORT; } /** + * Determine transmitting network device + * + * @v st_dest Destination address + * @ret netdev Network device, or NULL + */ +struct net_device * tcpip_netdev ( struct sockaddr_tcpip *st_dest ) { + struct tcpip_net_protocol *tcpip_net; + + /* Hand off to the appropriate network-layer protocol */ + tcpip_net = tcpip_net_protocol ( st_dest ); + if ( tcpip_net ) + return tcpip_net->netdev ( st_dest ); + + return NULL; +} + +/** + * Determine maximum transmission unit + * + * @v st_dest Destination address + * @ret mtu Maximum transmission unit + */ +size_t tcpip_mtu ( struct sockaddr_tcpip *st_dest ) { + struct tcpip_net_protocol *tcpip_net; + struct net_device *netdev; + size_t mtu; + + /* Find appropriate network-layer protocol */ + tcpip_net = tcpip_net_protocol ( st_dest ); + if ( ! tcpip_net ) + return 0; + + /* Find transmitting network device */ + netdev = tcpip_net->netdev ( st_dest ); + if ( ! netdev ) + return 0; + + /* Calculate MTU */ + mtu = ( netdev->max_pkt_len - netdev->ll_protocol->ll_header_len - + tcpip_net->header_len ); + + return mtu; +} + +/** * Calculate continued TCP/IP checkum * * @v partial Checksum of already-summed data, in network byte order @@ -133,3 +205,46 @@ uint16_t generic_tcpip_continue_chksum ( uint16_t partial, uint16_t tcpip_chksum ( const void *data, size_t len ) { return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len ); } + +/** + * Bind to local TCP/IP port + * + * @v st_local Local TCP/IP socket address, or NULL + * @v available Function to check port availability + * @ret port Local port number, or negative error + */ +int tcpip_bind ( struct sockaddr_tcpip *st_local, + int ( * available ) ( int port ) ) { + uint16_t flags = 0; + uint16_t try_port = 0; + uint16_t min_port; + uint16_t max_port; + unsigned int offset; + unsigned int i; + + /* Extract parameters from local socket address */ + if ( st_local ) { + flags = st_local->st_flags; + try_port = ntohs ( st_local->st_port ); + } + + /* If an explicit port is specified, check its availability */ + if ( try_port ) + return available ( try_port ); + + /* Otherwise, find an available port in the range [1,1023] or + * [1025,65535] as appropriate. + */ + min_port = ( ( ( ! flags ) & TCPIP_BIND_PRIVILEGED ) + 1 ); + max_port = ( ( flags & TCPIP_BIND_PRIVILEGED ) - 1 ); + offset = random(); + for ( i = 0 ; i <= max_port ; i++ ) { + try_port = ( ( i + offset ) & max_port ); + if ( try_port < min_port ) + continue; + if ( available ( try_port ) < 0 ) + continue; + return try_port; + } + return -EADDRINUSE; +} diff --git a/roms/ipxe/src/net/tls.c b/roms/ipxe/src/net/tls.c index 5e18f7266..30ccc932e 100644 --- a/roms/ipxe/src/net/tls.c +++ b/roms/ipxe/src/net/tls.c @@ -43,16 +43,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/xfer.h> #include <ipxe/open.h> #include <ipxe/x509.h> -#include <ipxe/clientcert.h> +#include <ipxe/privkey.h> +#include <ipxe/certstore.h> #include <ipxe/rbg.h> #include <ipxe/validator.h> #include <ipxe/tls.h> /* Disambiguate the various error causes */ -#define EACCES_WRONG_NAME __einfo_error ( EINFO_EACCES_WRONG_NAME ) -#define EINFO_EACCES_WRONG_NAME \ - __einfo_uniqify ( EINFO_EACCES, 0x02, \ - "Incorrect server name" ) #define EINVAL_CHANGE_CIPHER __einfo_error ( EINFO_EINVAL_CHANGE_CIPHER ) #define EINFO_EINVAL_CHANGE_CIPHER \ __einfo_uniqify ( EINFO_EINVAL, 0x01, \ @@ -161,6 +158,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define EINFO_EPERM_VERIFY \ __einfo_uniqify ( EINFO_EPERM, 0x02, \ "Handshake verification failed" ) +#define EPERM_CLIENT_CERT __einfo_error ( EINFO_EPERM_CLIENT_CERT ) +#define EINFO_EPERM_CLIENT_CERT \ + __einfo_uniqify ( EINFO_EPERM, 0x03, \ + "No suitable client certificate available" ) #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION ) #define EINFO_EPROTO_VERSION \ __einfo_uniqify ( EINFO_EPROTO, 0x01, \ @@ -311,6 +312,7 @@ static void free_tls ( struct refcnt *refcnt ) { list_del ( &iobuf->list ); free_iob ( iobuf ); } + x509_put ( tls->cert ); x509_chain_put ( tls->chain ); /* Free TLS structure itself */ @@ -1034,41 +1036,16 @@ static int tls_send_client_hello ( struct tls_session *tls ) { * @ret rc Return status code */ static int tls_send_certificate ( struct tls_session *tls ) { - int num_certificates = ( have_client_certificate() ? 1 : 0 ); struct { uint32_t type_length; uint8_t length[3]; struct { uint8_t length[3]; - uint8_t data[ client_certificate.len ]; - } __attribute__ (( packed )) certificates[num_certificates]; + uint8_t data[ tls->cert->raw.len ]; + } __attribute__ (( packed )) certificates[1]; } __attribute__ (( packed )) *certificate; - struct x509_certificate *cert; int rc; - /* If we have a certificate to send, determine the applicable - * public-key algorithm and schedule transmission of - * CertificateVerify. - */ - if ( num_certificates ) { - - /* Parse certificate to determine public-key algorithm */ - if ( ( rc = x509_certificate ( client_certificate.data, - client_certificate.len, - &cert ) ) != 0 ) { - DBGC ( tls, "TLS %p could not parse client " - "certificate: %s\n", tls, strerror ( rc ) ); - return rc; - } - tls->verify_pubkey = cert->signature_algorithm->pubkey; - x509_put ( cert ); - cert = NULL; - - /* Schedule CertificateVerify transmission */ - tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY; - tls_tx_resume ( tls ); - } - /* Allocate storage for Certificate record (which may be too * large for the stack). */ @@ -1083,13 +1060,11 @@ static int tls_send_certificate ( struct tls_session *tls ) { sizeof ( certificate->type_length ) ) ); tls_set_uint24 ( certificate->length, sizeof ( certificate->certificates ) ); - if ( num_certificates ) { - tls_set_uint24 ( certificate->certificates[0].length, - sizeof ( certificate->certificates[0].data ) ); - memcpy ( certificate->certificates[0].data, - client_certificate.data, + tls_set_uint24 ( certificate->certificates[0].length, sizeof ( certificate->certificates[0].data ) ); - } + memcpy ( certificate->certificates[0].data, + tls->cert->raw.data, + sizeof ( certificate->certificates[0].data ) ); /* Transmit record */ rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) ); @@ -1152,7 +1127,8 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) { */ static int tls_send_certificate_verify ( struct tls_session *tls ) { struct digest_algorithm *digest = tls->handshake_digest; - struct pubkey_algorithm *pubkey = tls->verify_pubkey; + struct x509_certificate *cert = tls->cert; + struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey; uint8_t digest_out[ digest->digestsize ]; uint8_t ctx[ pubkey->ctxsize ]; struct tls_signature_hash_algorithm *sig_hash = NULL; @@ -1162,8 +1138,8 @@ static int tls_send_certificate_verify ( struct tls_session *tls ) { tls_verify_handshake ( tls, digest_out ); /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, client_private_key.data, - client_private_key.len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data, + private_key.len ) ) != 0 ) { DBGC ( tls, "TLS %p could not initialise %s client private " "key: %s\n", tls, pubkey->name, strerror ( rc ) ); goto err_pubkey_init; @@ -1479,7 +1455,7 @@ static int tls_parse_chain ( struct tls_session *tls, } cert = x509_last ( tls->chain ); DBGC ( tls, "TLS %p found certificate %s\n", - tls, cert->subject.name ); + tls, x509_name ( cert ) ); /* Move to next certificate in list */ data = next; @@ -1545,9 +1521,19 @@ static int tls_new_certificate_request ( struct tls_session *tls, * in parsing the Certificate Request. */ - /* Schedule Certificate transmission */ - tls->tx_pending |= TLS_TX_CERTIFICATE; - tls_tx_resume ( tls ); + /* Free any existing client certificate */ + x509_put ( tls->cert ); + + /* Determine client certificate to be sent */ + tls->cert = certstore_find_key ( &private_key ); + if ( ! tls->cert ) { + DBGC ( tls, "TLS %p could not find certificate corresponding " + "to private key\n", tls ); + return -EPERM_CLIENT_CERT; + } + x509_get ( tls->cert ); + DBGC ( tls, "TLS %p sending client certificate %s\n", + tls, x509_name ( tls->cert ) ); return 0; } @@ -2454,11 +2440,9 @@ static void tls_validator_done ( struct tls_session *tls, int rc ) { assert ( cert != NULL ); /* Verify server name */ - if ( ( cert->subject.name == NULL ) || - ( strcmp ( cert->subject.name, tls->name ) != 0 ) ) { - DBGC ( tls, "TLS %p server name incorrect (expected %s, got " - "%s)\n", tls, tls->name, cert->subject.name ); - rc = -EACCES_WRONG_NAME; + if ( ( rc = x509_check_name ( cert, tls->name ) ) != 0 ) { + DBGC ( tls, "TLS %p server certificate does not match %s: %s\n", + tls, tls->name, strerror ( rc ) ); goto err; } @@ -2475,6 +2459,10 @@ static void tls_validator_done ( struct tls_session *tls, int rc ) { tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED ); + if ( tls->cert ) { + tls->tx_pending |= ( TLS_TX_CERTIFICATE | + TLS_TX_CERTIFICATE_VERIFY ); + } tls_tx_resume ( tls ); return; diff --git a/roms/ipxe/src/net/udp.c b/roms/ipxe/src/net/udp.c index 20badb7f0..76da67ecf 100644 --- a/roms/ipxe/src/net/udp.c +++ b/roms/ipxe/src/net/udp.c @@ -48,45 +48,19 @@ static struct interface_descriptor udp_xfer_desc; struct tcpip_protocol udp_protocol __tcpip_protocol; /** - * Bind UDP connection to local port + * Check if local UDP port is available * - * @v udp UDP connection - * @ret rc Return status code - * - * Opens the UDP connection and binds to the specified local port. If - * no local port is specified, the first available port will be used. + * @v port Local port number + * @ret port Local port number, or negative error */ -static int udp_bind ( struct udp_connection *udp ) { - struct udp_connection *existing; - static uint16_t try_port = 1023; - - /* If no port specified, find the first available port */ - if ( ! udp->local.st_port ) { - while ( try_port ) { - try_port++; - if ( try_port < 1024 ) - continue; - udp->local.st_port = htons ( try_port ); - if ( udp_bind ( udp ) == 0 ) - return 0; - } - return -EADDRINUSE; - } +static int udp_port_available ( int port ) { + struct udp_connection *udp; - /* Attempt bind to local port */ - list_for_each_entry ( existing, &udp_conns, list ) { - if ( existing->local.st_port == udp->local.st_port ) { - DBGC ( udp, "UDP %p could not bind: port %d in use\n", - udp, ntohs ( udp->local.st_port ) ); + list_for_each_entry ( udp, &udp_conns, list ) { + if ( udp->local.st_port == htons ( port ) ) return -EADDRINUSE; - } } - - /* Add to UDP connection list */ - DBGC ( udp, "UDP %p bound to port %d\n", - udp, ntohs ( udp->local.st_port ) ); - - return 0; + return port; } /** @@ -104,6 +78,7 @@ static int udp_open_common ( struct interface *xfer, struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer; struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local; struct udp_connection *udp; + int port; int rc; /* Allocate and initialise structure */ @@ -120,8 +95,16 @@ static int udp_open_common ( struct interface *xfer, /* Bind to local port */ if ( ! promisc ) { - if ( ( rc = udp_bind ( udp ) ) != 0 ) + port = tcpip_bind ( st_local, udp_port_available ); + if ( port < 0 ) { + rc = port; + DBGC ( udp, "UDP %p could not bind: %s\n", + udp, strerror ( rc ) ); goto err; + } + udp->local.st_port = htons ( port ); + DBGC ( udp, "UDP %p bound to port %d\n", + udp, ntohs ( udp->local.st_port ) ); } /* Attach parent interface, transfer reference to connection @@ -220,9 +203,9 @@ static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf, udphdr->chksum = tcpip_chksum ( udphdr, len ); /* Dump debugging information */ - DBGC ( udp, "UDP %p TX %d->%d len %d\n", udp, - ntohs ( udphdr->src ), ntohs ( udphdr->dest ), - ntohs ( udphdr->len ) ); + DBGC2 ( udp, "UDP %p TX %d->%d len %d\n", udp, + ntohs ( udphdr->src ), ntohs ( udphdr->dest ), + ntohs ( udphdr->len ) ); /* Send it to the next layer for processing */ if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev, @@ -264,12 +247,15 @@ static struct udp_connection * udp_demux ( struct sockaddr_tcpip *local ) { * Process a received packet * * @v iobuf I/O buffer + * @v netdev Network device * @v st_src Partially-filled source address * @v st_dest Partially-filled destination address * @v pshdr_csum Pseudo-header checksum * @ret rc Return status code */ -static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, +static int udp_rx ( struct io_buffer *iobuf, + struct net_device *netdev __unused, + struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) { struct udp_header *udphdr = iobuf->data; struct udp_connection *udp; @@ -317,8 +303,8 @@ static int udp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, iob_pull ( iobuf, sizeof ( *udphdr ) ); /* Dump debugging information */ - DBGC ( udp, "UDP %p RX %d<-%d len %zd\n", udp, - ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen ); + DBGC2 ( udp, "UDP %p RX %d<-%d len %zd\n", udp, + ntohs ( udphdr->dest ), ntohs ( udphdr->src ), ulen ); /* Ignore if no matching connection found */ if ( ! udp ) { @@ -409,13 +395,20 @@ static struct interface_descriptor udp_xfer_desc = *************************************************************************** */ -/** UDP socket opener */ -struct socket_opener udp_socket_opener __socket_opener = { +/** UDP IPv4 socket opener */ +struct socket_opener udp_ipv4_socket_opener __socket_opener = { .semantics = UDP_SOCK_DGRAM, .family = AF_INET, .open = udp_open, }; +/** UDP IPv6 socket opener */ +struct socket_opener udp_ipv6_socket_opener __socket_opener = { + .semantics = UDP_SOCK_DGRAM, + .family = AF_INET6, + .open = udp_open, +}; + /** Linkage hack */ int udp_sock_dgram = UDP_SOCK_DGRAM; diff --git a/roms/ipxe/src/net/udp/dhcp.c b/roms/ipxe/src/net/udp/dhcp.c index e63c3e422..e6d3eddff 100644 --- a/roms/ipxe/src/net/udp/dhcp.c +++ b/roms/ipxe/src/net/udp/dhcp.c @@ -86,35 +86,21 @@ static uint8_t dhcp_request_options_data[] = { DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME, DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID, DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME, + DHCP_DOMAIN_SEARCH, 128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */ DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ), DHCP_END }; /** DHCP server address setting */ -struct setting dhcp_server_setting __setting ( SETTING_MISC ) = { +const struct setting dhcp_server_setting __setting ( SETTING_MISC, + dhcp-server ) = { .name = "dhcp-server", .description = "DHCP server", .tag = DHCP_SERVER_IDENTIFIER, .type = &setting_type_ipv4, }; -/** DHCP user class setting */ -struct setting user_class_setting __setting ( SETTING_HOST_EXTRA ) = { - .name = "user-class", - .description = "DHCP user class", - .tag = DHCP_USER_CLASS_ID, - .type = &setting_type_string, -}; - -/** Use cached network settings */ -struct setting use_cached_setting __setting ( SETTING_MISC ) = { - .name = "use-cached", - .description = "Use cached settings", - .tag = DHCP_EB_USE_CACHED, - .type = &setting_type_uint8, -}; - /** * Most recent DHCP transaction ID * @@ -991,6 +977,7 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, uint8_t *dhcp_features; size_t dhcp_features_len; size_t ll_addr_len; + void *user_class; ssize_t len; int rc; @@ -1001,7 +988,7 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, data, max_len ) ) != 0 ) { DBG ( "DHCP could not create DHCP packet: %s\n", strerror ( rc ) ); - return rc; + goto err_create_packet; } /* Set client IP address */ @@ -1014,17 +1001,17 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, dhcp_features_len ) ) != 0 ) { DBG ( "DHCP could not set features list option: %s\n", strerror ( rc ) ); - return rc; + goto err_store_features; } /* Add options to identify the network device */ - fetch_setting ( &netdev->settings.settings, &busid_setting, &dhcp_desc, - sizeof ( dhcp_desc ) ); + fetch_raw_setting ( netdev_settings ( netdev ), &busid_setting, + &dhcp_desc, sizeof ( dhcp_desc ) ); if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc, sizeof ( dhcp_desc ) ) ) != 0 ) { DBG ( "DHCP could not set bus ID option: %s\n", strerror ( rc ) ); - return rc; + goto err_store_busid; } /* Add DHCP client identifier. Required for Infiniband, and @@ -1038,37 +1025,46 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt, ( ll_addr_len + 1 ) ) ) != 0 ) { DBG ( "DHCP could not set client ID: %s\n", strerror ( rc ) ); - return rc; + goto err_store_client_id; } - /* Add client UUID, if we have one. Required for PXE. */ + /* Add client UUID, if we have one. Required for PXE. The + * PXE spec does not specify a byte ordering for UUIDs, but + * RFC4578 suggests that it follows the EFI spec, in which the + * first three fields are little-endian. + */ client_uuid.type = DHCP_CLIENT_UUID_TYPE; if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &client_uuid.uuid ) ) >= 0 ) { + uuid_mangle ( &client_uuid.uuid ); if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID, &client_uuid, sizeof ( client_uuid ) ) ) != 0 ) { DBG ( "DHCP could not set client UUID: %s\n", strerror ( rc ) ); - return rc; + goto err_store_client_uuid; } } /* Add user class, if we have one. */ - if ( ( len = fetch_setting_len ( NULL, &user_class_setting ) ) >= 0 ) { - char user_class[len]; - fetch_setting ( NULL, &user_class_setting, user_class, - sizeof ( user_class ) ); + if ( ( len = fetch_raw_setting_copy ( NULL, &user_class_setting, + &user_class ) ) >= 0 ) { if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID, - &user_class, - sizeof ( user_class ) ) ) != 0 ) { + user_class, len ) ) != 0 ) { DBG ( "DHCP could not set user class: %s\n", strerror ( rc ) ); - return rc; + goto err_store_user_class; } } - return 0; + err_store_user_class: + free ( user_class ); + err_store_client_uuid: + err_store_client_id: + err_store_busid: + err_store_features: + err_create_packet: + return rc; } /**************************************************************************** @@ -1280,37 +1276,20 @@ static struct sockaddr dhcp_peer = { }; /** - * Get cached DHCPACK where none exists - */ -__weak void get_cached_dhcpack ( void ) { __keepme } - -/** * Start DHCP state machine on a network device * * @v job Job control interface * @v netdev Network device - * @ret rc Return status code, or positive if cached + * @ret rc Return status code * * Starts DHCP on the specified network device. If successful, the * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as * option sources. - * - * On a return of 0, a background job has been started to perform the - * DHCP request. Any nonzero return means the job has not been - * started; a positive return value indicates the success condition of - * having fetched the appropriate data from cached information. */ int start_dhcp ( struct interface *job, struct net_device *netdev ) { struct dhcp_session *dhcp; int rc; - /* Check for cached DHCP information */ - get_cached_dhcpack(); - if ( fetch_uintz_setting ( NULL, &use_cached_setting ) ) { - DBG ( "DHCP using cached network settings\n" ); - return 1; - } - /* Allocate and initialise structure */ dhcp = zalloc ( sizeof ( *dhcp ) ); if ( ! dhcp ) @@ -1412,7 +1391,8 @@ int start_pxebs ( struct interface *job, struct net_device *netdev, int rc; /* Get upper bound for PXE boot server IP address list */ - pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting ); + pxebs_list_len = fetch_raw_setting ( NULL, &pxe_boot_servers_setting, + NULL, 0 ); if ( pxebs_list_len < 0 ) pxebs_list_len = 0; @@ -1450,8 +1430,8 @@ int start_pxebs ( struct interface *job, struct net_device *netdev, if ( pxebs_list_len ) { uint8_t buf[pxebs_list_len]; - fetch_setting ( NULL, &pxe_boot_servers_setting, - buf, sizeof ( buf ) ); + fetch_raw_setting ( NULL, &pxe_boot_servers_setting, + buf, sizeof ( buf ) ); pxebs_list ( dhcp, buf, sizeof ( buf ), ip ); } if ( ! dhcp->pxe_attempt->s_addr ) { @@ -1491,3 +1471,9 @@ int start_pxebs ( struct interface *job, struct net_device *netdev, ref_put ( &dhcp->refcnt ); return rc; } + +/** DHCP network device configurator */ +struct net_device_configurator dhcp_configurator __net_device_configurator = { + .name = "dhcp", + .start = start_dhcp, +}; diff --git a/roms/ipxe/src/net/udp/dhcpv6.c b/roms/ipxe/src/net/udp/dhcpv6.c new file mode 100644 index 000000000..cbc8d794a --- /dev/null +++ b/roms/ipxe/src/net/udp/dhcpv6.c @@ -0,0 +1,990 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <byteswap.h> +#include <ipxe/interface.h> +#include <ipxe/xfer.h> +#include <ipxe/iobuf.h> +#include <ipxe/open.h> +#include <ipxe/netdevice.h> +#include <ipxe/settings.h> +#include <ipxe/retry.h> +#include <ipxe/timer.h> +#include <ipxe/in.h> +#include <ipxe/crc32.h> +#include <ipxe/errortab.h> +#include <ipxe/ipv6.h> +#include <ipxe/dhcpv6.h> + +/** @file + * + * Dynamic Host Configuration Protocol for IPv6 + * + */ + +/* Disambiguate the various error causes */ +#define EPROTO_UNSPECFAIL __einfo_error ( EINFO_EPROTO_UNSPECFAIL ) +#define EINFO_EPROTO_UNSPECFAIL \ + __einfo_uniqify ( EINFO_EPROTO, 1, "Unspecified server failure" ) +#define EPROTO_NOADDRSAVAIL __einfo_error ( EINFO_EPROTO_NOADDRSAVAIL ) +#define EINFO_EPROTO_NOADDRSAVAIL \ + __einfo_uniqify ( EINFO_EPROTO, 2, "No addresses available" ) +#define EPROTO_NOBINDING __einfo_error ( EINFO_EPROTO_NOBINDING ) +#define EINFO_EPROTO_NOBINDING \ + __einfo_uniqify ( EINFO_EPROTO, 3, "Client record unavailable" ) +#define EPROTO_NOTONLINK __einfo_error ( EINFO_EPROTO_NOTONLINK ) +#define EINFO_EPROTO_NOTONLINK \ + __einfo_uniqify ( EINFO_EPROTO, 4, "Prefix not on link" ) +#define EPROTO_USEMULTICAST __einfo_error ( EINFO_EPROTO_USEMULTICAST ) +#define EINFO_EPROTO_USEMULTICAST \ + __einfo_uniqify ( EINFO_EPROTO, 5, "Use multicast address" ) +#define EPROTO_STATUS( status ) \ + EUNIQ ( EINFO_EPROTO, ( (status) & 0x0f ), EPROTO_UNSPECFAIL, \ + EPROTO_NOADDRSAVAIL, EPROTO_NOBINDING, \ + EPROTO_NOTONLINK, EPROTO_USEMULTICAST ) + +/** Human-readable error messages */ +struct errortab dhcpv6_errors[] __errortab = { + __einfo_errortab ( EINFO_EPROTO_NOADDRSAVAIL ), +}; + +/**************************************************************************** + * + * DHCPv6 option lists + * + */ + +/** A DHCPv6 option list */ +struct dhcpv6_option_list { + /** Data buffer */ + const void *data; + /** Length of data buffer */ + size_t len; +}; + +/** + * Find DHCPv6 option + * + * @v options DHCPv6 option list + * @v code Option code + * @ret option DHCPv6 option, or NULL if not found + */ +static const union dhcpv6_any_option * +dhcpv6_option ( struct dhcpv6_option_list *options, unsigned int code ) { + const union dhcpv6_any_option *option = options->data; + size_t remaining = options->len; + size_t data_len; + + /* Scan through list of options */ + while ( remaining >= sizeof ( option->header ) ) { + + /* Calculate and validate option length */ + remaining -= sizeof ( option->header ); + data_len = ntohs ( option->header.len ); + if ( data_len > remaining ) { + /* Malformed option list */ + return NULL; + } + + /* Return if we have found the specified option */ + if ( option->header.code == htons ( code ) ) + return option; + + /* Otherwise, move to the next option */ + option = ( ( ( void * ) option->header.data ) + data_len ); + remaining -= data_len; + } + + return NULL; +} + +/** + * Check DHCPv6 client or server identifier + * + * @v options DHCPv6 option list + * @v code Option code + * @v expected Expected value + * @v len Length of expected value + * @ret rc Return status code + */ +static int dhcpv6_check_duid ( struct dhcpv6_option_list *options, + unsigned int code, const void *expected, + size_t len ) { + const union dhcpv6_any_option *option; + const struct dhcpv6_duid_option *duid; + + /* Find option */ + option = dhcpv6_option ( options, code ); + if ( ! option ) + return -ENOENT; + duid = &option->duid; + + /* Check option length */ + if ( ntohs ( duid->header.len ) != len ) + return -EINVAL; + + /* Compare option value */ + if ( memcmp ( duid->duid, expected, len ) != 0 ) + return -EINVAL; + + return 0; +} + +/** + * Get DHCPv6 status code + * + * @v options DHCPv6 option list + * @ret rc Return status code + */ +static int dhcpv6_status_code ( struct dhcpv6_option_list *options ) { + const union dhcpv6_any_option *option; + const struct dhcpv6_status_code_option *status_code; + unsigned int status; + + /* Find status code option, if present */ + option = dhcpv6_option ( options, DHCPV6_STATUS_CODE ); + if ( ! option ) { + /* Omitted status code should be treated as "success" */ + return 0; + } + status_code = &option->status_code; + + /* Sanity check */ + if ( ntohs ( status_code->header.len ) < + ( sizeof ( *status_code ) - sizeof ( status_code->header ) ) ) { + return -EINVAL; + } + + /* Calculate iPXE error code from DHCPv6 status code */ + status = ntohs ( status_code->status ); + return ( status ? -EPROTO_STATUS ( status ) : 0 ); +} + +/** + * Get DHCPv6 identity association address + * + * @v options DHCPv6 option list + * @v iaid Identity association ID + * @v address IPv6 address to fill in + * @ret rc Return status code + */ +static int dhcpv6_iaaddr ( struct dhcpv6_option_list *options, uint32_t iaid, + struct in6_addr *address ) { + const union dhcpv6_any_option *option; + const struct dhcpv6_ia_na_option *ia_na; + const struct dhcpv6_iaaddr_option *iaaddr; + struct dhcpv6_option_list suboptions; + size_t len; + int rc; + + /* Find identity association option, if present */ + option = dhcpv6_option ( options, DHCPV6_IA_NA ); + if ( ! option ) + return -ENOENT; + ia_na = &option->ia_na; + + /* Sanity check */ + len = ntohs ( ia_na->header.len ); + if ( len < ( sizeof ( *ia_na ) - sizeof ( ia_na->header ) ) ) + return -EINVAL; + + /* Check identity association ID */ + if ( ia_na->iaid != htonl ( iaid ) ) + return -EINVAL; + + /* Construct IA_NA sub-options list */ + suboptions.data = ia_na->options; + suboptions.len = ( len + sizeof ( ia_na->header ) - + offsetof ( typeof ( *ia_na ), options ) ); + + /* Check IA_NA status code */ + if ( ( rc = dhcpv6_status_code ( &suboptions ) ) != 0 ) + return rc; + + /* Find identity association address, if present */ + option = dhcpv6_option ( &suboptions, DHCPV6_IAADDR ); + if ( ! option ) + return -ENOENT; + iaaddr = &option->iaaddr; + + /* Sanity check */ + len = ntohs ( iaaddr->header.len ); + if ( len < ( sizeof ( *iaaddr ) - sizeof ( iaaddr->header ) ) ) + return -EINVAL; + + /* Construct IAADDR sub-options list */ + suboptions.data = iaaddr->options; + suboptions.len = ( len + sizeof ( iaaddr->header ) - + offsetof ( typeof ( *iaaddr ), options ) ); + + /* Check IAADDR status code */ + if ( ( rc = dhcpv6_status_code ( &suboptions ) ) != 0 ) + return rc; + + /* Extract IPv6 address */ + memcpy ( address, &iaaddr->address, sizeof ( *address ) ); + + return 0; +} + +/**************************************************************************** + * + * DHCPv6 settings blocks + * + */ + +/** A DHCPv6 settings block */ +struct dhcpv6_settings { + /** Reference count */ + struct refcnt refcnt; + /** Settings block */ + struct settings settings; + /** Option list */ + struct dhcpv6_option_list options; +}; + +/** + * Check applicability of DHCPv6 setting + * + * @v settings Settings block + * @v setting Setting + * @ret applies Setting applies within this settings block + */ +static int dhcpv6_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &ipv6_scope ); +} + +/** + * Fetch value of DHCPv6 setting + * + * @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 + */ +static int dhcpv6_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct dhcpv6_settings *dhcpv6set = + container_of ( settings, struct dhcpv6_settings, settings ); + const union dhcpv6_any_option *option; + size_t option_len; + + /* Find option */ + option = dhcpv6_option ( &dhcpv6set->options, setting->tag ); + if ( ! option ) + return -ENOENT; + + /* Copy option to data buffer */ + option_len = ntohs ( option->header.len ); + if ( len > option_len ) + len = option_len; + memcpy ( data, option->header.data, len ); + return option_len; +} + +/** DHCPv6 settings operations */ +static struct settings_operations dhcpv6_settings_operations = { + .applies = dhcpv6_applies, + .fetch = dhcpv6_fetch, +}; + +/** + * Register DHCPv6 options as network device settings + * + * @v options DHCPv6 option list + * @v parent Parent settings block + * @ret rc Return status code + */ +static int dhcpv6_register ( struct dhcpv6_option_list *options, + struct settings *parent ) { + struct dhcpv6_settings *dhcpv6set; + void *data; + size_t len; + int rc; + + /* Allocate and initialise structure */ + dhcpv6set = zalloc ( sizeof ( *dhcpv6set ) + options->len ); + if ( ! dhcpv6set ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &dhcpv6set->refcnt, NULL ); + settings_init ( &dhcpv6set->settings, &dhcpv6_settings_operations, + &dhcpv6set->refcnt, &ipv6_scope ); + data = ( ( ( void * ) dhcpv6set ) + sizeof ( *dhcpv6set ) ); + len = options->len; + memcpy ( data, options->data, len ); + dhcpv6set->options.data = data; + dhcpv6set->options.len = len; + + /* Register settings */ + if ( ( rc = register_settings ( &dhcpv6set->settings, parent, + DHCPV6_SETTINGS_NAME ) ) != 0 ) + goto err_register; + + err_register: + ref_put ( &dhcpv6set->refcnt ); + err_alloc: + return rc; +} + +/**************************************************************************** + * + * DHCPv6 protocol + * + */ + +/** Options to be requested */ +static uint16_t dhcpv6_requested_options[] = { + htons ( DHCPV6_DNS_SERVERS ), htons ( DHCPV6_DOMAIN_LIST ), + htons ( DHCPV6_BOOTFILE_URL ), htons ( DHCPV6_BOOTFILE_PARAM ), +}; + +/** + * Name a DHCPv6 packet type + * + * @v type DHCPv6 packet type + * @ret name DHCPv6 packet type name + */ +static __attribute__ (( unused )) const char * +dhcpv6_type_name ( unsigned int type ) { + static char buf[ 12 /* "UNKNOWN-xxx" + NUL */ ]; + + switch ( type ) { + case DHCPV6_SOLICIT: return "SOLICIT"; + case DHCPV6_ADVERTISE: return "ADVERTISE"; + case DHCPV6_REQUEST: return "REQUEST"; + case DHCPV6_REPLY: return "REPLY"; + case DHCPV6_INFORMATION_REQUEST: return "INFORMATION-REQUEST"; + default: + snprintf ( buf, sizeof ( buf ), "UNKNOWN-%d", type ); + return buf; + } +} + +/** A DHCPv6 session state */ +struct dhcpv6_session_state { + /** Current transmitted packet type */ + uint8_t tx_type; + /** Current expected received packet type */ + uint8_t rx_type; + /** Flags */ + uint8_t flags; + /** Next state (or NULL to terminate) */ + struct dhcpv6_session_state *next; +}; + +/** DHCPv6 session state flags */ +enum dhcpv6_session_state_flags { + /** Include identity association within request */ + DHCPV6_TX_IA_NA = 0x01, + /** Include leased IPv6 address within request */ + DHCPV6_TX_IAADDR = 0x02, + /** Record received server ID */ + DHCPV6_RX_RECORD_SERVER_ID = 0x04, + /** Record received IPv6 address */ + DHCPV6_RX_RECORD_IAADDR = 0x08, + /** Apply received IPv6 address */ + DHCPV6_RX_APPLY_IAADDR = 0x10, +}; + +/** DHCPv6 request state */ +static struct dhcpv6_session_state dhcpv6_request = { + .tx_type = DHCPV6_REQUEST, + .rx_type = DHCPV6_REPLY, + .flags = ( DHCPV6_TX_IA_NA | DHCPV6_TX_IAADDR | + DHCPV6_RX_RECORD_IAADDR | DHCPV6_RX_APPLY_IAADDR ), + .next = NULL, +}; + +/** DHCPv6 solicitation state */ +static struct dhcpv6_session_state dhcpv6_solicit = { + .tx_type = DHCPV6_SOLICIT, + .rx_type = DHCPV6_ADVERTISE, + .flags = ( DHCPV6_TX_IA_NA | DHCPV6_RX_RECORD_SERVER_ID | + DHCPV6_RX_RECORD_IAADDR ), + .next = &dhcpv6_request, +}; + +/** DHCPv6 information request state */ +static struct dhcpv6_session_state dhcpv6_information_request = { + .tx_type = DHCPV6_INFORMATION_REQUEST, + .rx_type = DHCPV6_REPLY, + .flags = 0, + .next = NULL, +}; + +/** A DHCPv6 session */ +struct dhcpv6_session { + /** Reference counter */ + struct refcnt refcnt; + /** Job control interface */ + struct interface job; + /** Data transfer interface */ + struct interface xfer; + + /** Network device being configured */ + struct net_device *netdev; + /** Transaction ID */ + uint8_t xid[3]; + /** Identity association ID */ + uint32_t iaid; + /** Start time (in ticks) */ + unsigned long start; + /** Client DUID */ + struct dhcpv6_duid_uuid client_duid; + /** Server DUID, if known */ + void *server_duid; + /** Server DUID length */ + size_t server_duid_len; + /** Leased IPv6 address */ + struct in6_addr lease; + + /** Retransmission timer */ + struct retry_timer timer; + + /** Current session state */ + struct dhcpv6_session_state *state; + /** Current timeout status code */ + int rc; +}; + +/** + * Free DHCPv6 session + * + * @v refcnt Reference count + */ +static void dhcpv6_free ( struct refcnt *refcnt ) { + struct dhcpv6_session *dhcpv6 = + container_of ( refcnt, struct dhcpv6_session, refcnt ); + + netdev_put ( dhcpv6->netdev ); + free ( dhcpv6->server_duid ); + free ( dhcpv6 ); +} + +/** + * Terminate DHCPv6 session + * + * @v dhcpv6 DHCPv6 session + * @v rc Reason for close + */ +static void dhcpv6_finished ( struct dhcpv6_session *dhcpv6, int rc ) { + + /* Stop timer */ + stop_timer ( &dhcpv6->timer ); + + /* Shut down interfaces */ + intf_shutdown ( &dhcpv6->xfer, rc ); + intf_shutdown ( &dhcpv6->job, rc ); +} + +/** + * Transition to new DHCPv6 session state + * + * @v dhcpv6 DHCPv6 session + * @v state New session state + */ +static void dhcpv6_set_state ( struct dhcpv6_session *dhcpv6, + struct dhcpv6_session_state *state ) { + + DBGC ( dhcpv6, "DHCPv6 %s entering %s state\n", dhcpv6->netdev->name, + dhcpv6_type_name ( state->tx_type ) ); + + /* Record state */ + dhcpv6->state = state; + + /* Default to -ETIMEDOUT if no more specific error is recorded */ + dhcpv6->rc = -ETIMEDOUT; + + /* Start timer to trigger transmission */ + start_timer_nodelay ( &dhcpv6->timer ); +} + +/** + * Get DHCPv6 user class + * + * @v data Data buffer + * @v len Length of data buffer + * @ret len Length of user class + */ +static size_t dhcpv6_user_class ( void *data, size_t len ) { + static const char default_user_class[4] = { 'i', 'P', 'X', 'E' }; + int actual_len; + + /* Fetch user-class setting, if defined */ + actual_len = fetch_raw_setting ( NULL, &user_class_setting, data, len ); + if ( actual_len >= 0 ) + return actual_len; + + /* Otherwise, use the default user class ("iPXE") */ + if ( len > sizeof ( default_user_class ) ) + len = sizeof ( default_user_class ); + memcpy ( data, default_user_class, len ); + return sizeof ( default_user_class ); +} + +/** + * Transmit current request + * + * @v dhcpv6 DHCPv6 session + * @ret rc Return status code + */ +static int dhcpv6_tx ( struct dhcpv6_session *dhcpv6 ) { + struct dhcpv6_duid_option *client_id; + struct dhcpv6_duid_option *server_id; + struct dhcpv6_ia_na_option *ia_na; + struct dhcpv6_iaaddr_option *iaaddr; + struct dhcpv6_option_request_option *option_request; + struct dhcpv6_user_class_option *user_class; + struct dhcpv6_elapsed_time_option *elapsed; + struct dhcpv6_header *dhcphdr; + struct io_buffer *iobuf; + size_t client_id_len; + size_t server_id_len; + size_t ia_na_len; + size_t option_request_len; + size_t user_class_string_len; + size_t user_class_len; + size_t elapsed_len; + size_t total_len; + int rc; + + /* Calculate lengths */ + client_id_len = ( sizeof ( *client_id ) + + sizeof ( dhcpv6->client_duid ) ); + server_id_len = ( dhcpv6->server_duid ? ( sizeof ( *server_id ) + + dhcpv6->server_duid_len ) :0); + if ( dhcpv6->state->flags & DHCPV6_TX_IA_NA ) { + ia_na_len = sizeof ( *ia_na ); + if ( dhcpv6->state->flags & DHCPV6_TX_IAADDR ) + ia_na_len += sizeof ( *iaaddr ); + } else { + ia_na_len = 0; + } + option_request_len = ( sizeof ( *option_request ) + + sizeof ( dhcpv6_requested_options ) ); + user_class_string_len = dhcpv6_user_class ( NULL, 0 ); + user_class_len = ( sizeof ( *user_class ) + + sizeof ( user_class->user_class[0] ) + + user_class_string_len ); + elapsed_len = sizeof ( *elapsed ); + total_len = ( sizeof ( *dhcphdr ) + client_id_len + server_id_len + + ia_na_len + option_request_len + user_class_len + + elapsed_len ); + + /* Allocate packet */ + iobuf = xfer_alloc_iob ( &dhcpv6->xfer, total_len ); + if ( ! iobuf ) + return -ENOMEM; + + /* Construct header */ + dhcphdr = iob_put ( iobuf, sizeof ( *dhcphdr ) ); + dhcphdr->type = dhcpv6->state->tx_type; + memcpy ( dhcphdr->xid, dhcpv6->xid, sizeof ( dhcphdr->xid ) ); + + /* Construct client identifier */ + client_id = iob_put ( iobuf, client_id_len ); + client_id->header.code = htons ( DHCPV6_CLIENT_ID ); + client_id->header.len = htons ( client_id_len - + sizeof ( client_id->header ) ); + memcpy ( client_id->duid, &dhcpv6->client_duid, + sizeof ( dhcpv6->client_duid ) ); + + /* Construct server identifier, if applicable */ + if ( server_id_len ) { + server_id = iob_put ( iobuf, server_id_len ); + server_id->header.code = htons ( DHCPV6_SERVER_ID ); + server_id->header.len = htons ( server_id_len - + sizeof ( server_id->header ) ); + memcpy ( server_id->duid, dhcpv6->server_duid, + dhcpv6->server_duid_len ); + } + + /* Construct identity association, if applicable */ + if ( ia_na_len ) { + ia_na = iob_put ( iobuf, ia_na_len ); + ia_na->header.code = htons ( DHCPV6_IA_NA ); + ia_na->header.len = htons ( ia_na_len - + sizeof ( ia_na->header ) ); + ia_na->iaid = htonl ( dhcpv6->iaid ); + ia_na->renew = htonl ( 0 ); + ia_na->rebind = htonl ( 0 ); + if ( dhcpv6->state->flags & DHCPV6_TX_IAADDR ) { + iaaddr = ( ( void * ) ia_na->options ); + iaaddr->header.code = htons ( DHCPV6_IAADDR ); + iaaddr->header.len = htons ( sizeof ( *iaaddr ) - + sizeof ( iaaddr->header )); + memcpy ( &iaaddr->address, &dhcpv6->lease, + sizeof ( iaaddr->address ) ); + iaaddr->preferred = htonl ( 0 ); + iaaddr->valid = htonl ( 0 ); + } + } + + /* Construct option request */ + option_request = iob_put ( iobuf, option_request_len ); + option_request->header.code = htons ( DHCPV6_OPTION_REQUEST ); + option_request->header.len = htons ( option_request_len - + sizeof ( option_request->header )); + memcpy ( option_request->requested, dhcpv6_requested_options, + sizeof ( dhcpv6_requested_options ) ); + + /* Construct user class */ + user_class = iob_put ( iobuf, user_class_len ); + user_class->header.code = htons ( DHCPV6_USER_CLASS ); + user_class->header.len = htons ( user_class_len - + sizeof ( user_class->header ) ); + user_class->user_class[0].len = htons ( user_class_string_len ); + dhcpv6_user_class ( user_class->user_class[0].string, + user_class_string_len ); + + /* Construct elapsed time */ + elapsed = iob_put ( iobuf, elapsed_len ); + elapsed->header.code = htons ( DHCPV6_ELAPSED_TIME ); + elapsed->header.len = htons ( elapsed_len - + sizeof ( elapsed->header ) ); + elapsed->elapsed = htons ( ( ( currticks() - dhcpv6->start ) * 100 ) / + TICKS_PER_SEC ); + + /* Sanity check */ + assert ( iob_len ( iobuf ) == total_len ); + + /* Transmit packet */ + if ( ( rc = xfer_deliver_iob ( &dhcpv6->xfer, iobuf ) ) != 0 ) { + DBGC ( dhcpv6, "DHCPv6 %s could not transmit: %s\n", + dhcpv6->netdev->name, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Handle timer expiry + * + * @v timer Retransmission timer + * @v fail Failure indicator + */ +static void dhcpv6_timer_expired ( struct retry_timer *timer, int fail ) { + struct dhcpv6_session *dhcpv6 = + container_of ( timer, struct dhcpv6_session, timer ); + + /* If we have failed, terminate DHCPv6 */ + if ( fail ) { + dhcpv6_finished ( dhcpv6, dhcpv6->rc ); + return; + } + + /* Restart timer */ + start_timer ( &dhcpv6->timer ); + + /* (Re)transmit current request */ + dhcpv6_tx ( dhcpv6 ); +} + +/** + * Receive new data + * + * @v dhcpv6 DHCPv6 session + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6, + struct io_buffer *iobuf, + struct xfer_metadata *meta ) { + struct settings *parent = netdev_settings ( dhcpv6->netdev ); + struct sockaddr_in6 *src = ( ( struct sockaddr_in6 * ) meta->src ); + struct dhcpv6_header *dhcphdr = iobuf->data; + struct dhcpv6_option_list options; + const union dhcpv6_any_option *option; + int rc; + + /* Sanity checks */ + if ( iob_len ( iobuf ) < sizeof ( *dhcphdr ) ) { + DBGC ( dhcpv6, "DHCPv6 %s received packet too short (%zd " + "bytes, min %zd bytes)\n", dhcpv6->netdev->name, + iob_len ( iobuf ), sizeof ( *dhcphdr ) ); + rc = -EINVAL; + goto done; + } + assert ( src != NULL ); + assert ( src->sin6_family == AF_INET6 ); + DBGC ( dhcpv6, "DHCPv6 %s received %s from %s\n", + dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ), + inet6_ntoa ( &src->sin6_addr ) ); + + /* Construct option list */ + options.data = dhcphdr->options; + options.len = ( iob_len ( iobuf ) - + offsetof ( typeof ( *dhcphdr ), options ) ); + + /* Verify client identifier */ + if ( ( rc = dhcpv6_check_duid ( &options, DHCPV6_CLIENT_ID, + &dhcpv6->client_duid, + sizeof ( dhcpv6->client_duid ) ) ) !=0){ + DBGC ( dhcpv6, "DHCPv6 %s received %s without correct client " + "ID: %s\n", dhcpv6->netdev->name, + dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) ); + goto done; + } + + /* Verify server identifier, if applicable */ + if ( dhcpv6->server_duid && + ( ( rc = dhcpv6_check_duid ( &options, DHCPV6_SERVER_ID, + dhcpv6->server_duid, + dhcpv6->server_duid_len ) ) != 0 ) ) { + DBGC ( dhcpv6, "DHCPv6 %s received %s without correct server " + "ID: %s\n", dhcpv6->netdev->name, + dhcpv6_type_name ( dhcphdr->type ), strerror ( rc ) ); + goto done; + } + + /* Check message type */ + if ( dhcphdr->type != dhcpv6->state->rx_type ) { + DBGC ( dhcpv6, "DHCPv6 %s received %s while expecting %s\n", + dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ), + dhcpv6_type_name ( dhcpv6->state->rx_type ) ); + rc = -ENOTTY; + goto done; + } + + /* Fetch status code, if present */ + if ( ( rc = dhcpv6_status_code ( &options ) ) != 0 ) { + DBGC ( dhcpv6, "DHCPv6 %s received %s with error status: %s\n", + dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ), + strerror ( rc ) ); + /* This is plausibly the error we want to return */ + dhcpv6->rc = rc; + goto done; + } + + /* Record identity association address, if applicable */ + if ( dhcpv6->state->flags & DHCPV6_RX_RECORD_IAADDR ) { + if ( ( rc = dhcpv6_iaaddr ( &options, dhcpv6->iaid, + &dhcpv6->lease ) ) != 0 ) { + DBGC ( dhcpv6, "DHCPv6 %s received %s with unusable " + "IAADDR: %s\n", dhcpv6->netdev->name, + dhcpv6_type_name ( dhcphdr->type ), + strerror ( rc ) ); + /* This is plausibly the error we want to return */ + dhcpv6->rc = rc; + goto done; + } + DBGC ( dhcpv6, "DHCPv6 %s received %s is for %s\n", + dhcpv6->netdev->name, dhcpv6_type_name ( dhcphdr->type ), + inet6_ntoa ( &dhcpv6->lease ) ); + } + + /* Record server ID, if applicable */ + if ( dhcpv6->state->flags & DHCPV6_RX_RECORD_SERVER_ID ) { + assert ( dhcpv6->server_duid == NULL ); + option = dhcpv6_option ( &options, DHCPV6_SERVER_ID ); + if ( ! option ) { + DBGC ( dhcpv6, "DHCPv6 %s received %s missing server " + "ID\n", dhcpv6->netdev->name, + dhcpv6_type_name ( dhcphdr->type ) ); + rc = -EINVAL; + goto done; + } + dhcpv6->server_duid_len = ntohs ( option->duid.header.len ); + dhcpv6->server_duid = malloc ( dhcpv6->server_duid_len ); + if ( ! dhcpv6->server_duid ) { + rc = -ENOMEM; + goto done; + } + memcpy ( dhcpv6->server_duid, option->duid.duid, + dhcpv6->server_duid_len ); + } + + /* Apply identity association address, if applicable */ + if ( dhcpv6->state->flags & DHCPV6_RX_APPLY_IAADDR ) { + if ( ( rc = ipv6_set_address ( dhcpv6->netdev, + &dhcpv6->lease ) ) != 0 ) { + DBGC ( dhcpv6, "DHCPv6 %s could not apply %s: %s\n", + dhcpv6->netdev->name, + inet6_ntoa ( &dhcpv6->lease ), strerror ( rc ) ); + /* This is plausibly the error we want to return */ + dhcpv6->rc = rc; + goto done; + } + } + + /* Transition to next state or complete DHCPv6, as applicable */ + if ( dhcpv6->state->next ) { + + /* Transition to next state */ + dhcpv6_set_state ( dhcpv6, dhcpv6->state->next ); + rc = 0; + + } else { + + /* Register settings */ + if ( ( rc = dhcpv6_register ( &options, parent ) ) != 0 ) { + DBGC ( dhcpv6, "DHCPv6 %s could not register " + "settings: %s\n", dhcpv6->netdev->name, + strerror ( rc ) ); + goto done; + } + + /* Mark as complete */ + dhcpv6_finished ( dhcpv6, 0 ); + DBGC ( dhcpv6, "DHCPv6 %s complete\n", dhcpv6->netdev->name ); + } + + done: + free_iob ( iobuf ); + return rc; +} + +/** DHCPv6 job control interface operations */ +static struct interface_operation dhcpv6_job_op[] = { + INTF_OP ( intf_close, struct dhcpv6_session *, dhcpv6_finished ), +}; + +/** DHCPv6 job control interface descriptor */ +static struct interface_descriptor dhcpv6_job_desc = + INTF_DESC ( struct dhcpv6_session, job, dhcpv6_job_op ); + +/** DHCPv6 data transfer interface operations */ +static struct interface_operation dhcpv6_xfer_op[] = { + INTF_OP ( xfer_deliver, struct dhcpv6_session *, dhcpv6_rx ), +}; + +/** DHCPv6 data transfer interface descriptor */ +static struct interface_descriptor dhcpv6_xfer_desc = + INTF_DESC ( struct dhcpv6_session, xfer, dhcpv6_xfer_op ); + +/** + * Start DHCPv6 + * + * @v job Job control interface + * @v netdev Network device + * @v stateful Perform stateful address autoconfiguration + * @ret rc Return status code + */ +int start_dhcpv6 ( struct interface *job, struct net_device *netdev, + int stateful ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + struct dhcpv6_session *dhcpv6; + struct { + union { + struct sockaddr_in6 sin6; + struct sockaddr sa; + } client; + union { + struct sockaddr_in6 sin6; + struct sockaddr sa; + } server; + } addresses; + uint32_t xid; + int len; + int rc; + + /* Allocate and initialise structure */ + dhcpv6 = zalloc ( sizeof ( *dhcpv6 ) ); + if ( ! dhcpv6 ) + return -ENOMEM; + ref_init ( &dhcpv6->refcnt, dhcpv6_free ); + intf_init ( &dhcpv6->job, &dhcpv6_job_desc, &dhcpv6->refcnt ); + intf_init ( &dhcpv6->xfer, &dhcpv6_xfer_desc, &dhcpv6->refcnt ); + dhcpv6->netdev = netdev_get ( netdev ); + xid = random(); + memcpy ( dhcpv6->xid, &xid, sizeof ( dhcpv6->xid ) ); + dhcpv6->start = currticks(); + timer_init ( &dhcpv6->timer, dhcpv6_timer_expired, &dhcpv6->refcnt ); + + /* Construct client and server addresses */ + memset ( &addresses, 0, sizeof ( addresses ) ); + addresses.client.sin6.sin6_family = AF_INET6; + addresses.client.sin6.sin6_scope_id = netdev->index; + addresses.client.sin6.sin6_port = htons ( DHCPV6_CLIENT_PORT ); + addresses.server.sin6.sin6_family = AF_INET6; + ipv6_all_dhcp_relay_and_servers ( &addresses.server.sin6.sin6_addr ); + addresses.server.sin6.sin6_scope_id = netdev->index; + addresses.server.sin6.sin6_port = htons ( DHCPV6_SERVER_PORT ); + + /* Construct client DUID from system UUID */ + dhcpv6->client_duid.type = htons ( DHCPV6_DUID_UUID ); + if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, + &dhcpv6->client_duid.uuid ) ) < 0 ) { + rc = len; + DBGC ( dhcpv6, "DHCPv6 %s could not create DUID-UUID: %s\n", + dhcpv6->netdev->name, strerror ( rc ) ); + goto err_client_duid; + } + + /* Construct IAID from link-layer address */ + dhcpv6->iaid = crc32_le ( 0, netdev->ll_addr, ll_protocol->ll_addr_len); + DBGC ( dhcpv6, "DHCPv6 %s has XID %02x%02x%02x\n", dhcpv6->netdev->name, + dhcpv6->xid[0], dhcpv6->xid[1], dhcpv6->xid[2] ); + + /* Enter initial state */ + dhcpv6_set_state ( dhcpv6, ( stateful ? &dhcpv6_solicit : + &dhcpv6_information_request ) ); + + /* Open socket */ + if ( ( rc = xfer_open_socket ( &dhcpv6->xfer, SOCK_DGRAM, + &addresses.server.sa, + &addresses.client.sa ) ) != 0 ) { + DBGC ( dhcpv6, "DHCPv6 %s could not open socket: %s\n", + dhcpv6->netdev->name, strerror ( rc ) ); + goto err_open_socket; + } + + /* Attach parent interface, mortalise self, and return */ + intf_plug_plug ( &dhcpv6->job, job ); + ref_put ( &dhcpv6->refcnt ); + return 0; + + err_open_socket: + dhcpv6_finished ( dhcpv6, rc ); + err_client_duid: + ref_put ( &dhcpv6->refcnt ); + return rc; +} + +/** Boot filename setting */ +const struct setting filename6_setting __setting ( SETTING_BOOT, filename ) = { + .name = "filename", + .description = "Boot filename", + .tag = DHCPV6_BOOTFILE_URL, + .type = &setting_type_string, + .scope = &ipv6_scope, +}; + +/** DNS search list setting */ +const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = { + .name = "dnssl", + .description = "DNS search list", + .tag = DHCPV6_DOMAIN_LIST, + .type = &setting_type_dnssl, + .scope = &ipv6_scope, +}; diff --git a/roms/ipxe/src/net/udp/dns.c b/roms/ipxe/src/net/udp/dns.c index 613541f5a..fffe6e697 100644 --- a/roms/ipxe/src/net/udp/dns.c +++ b/roms/ipxe/src/net/udp/dns.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <ctype.h> #include <errno.h> #include <byteswap.h> #include <ipxe/refcnt.h> @@ -37,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/tcpip.h> #include <ipxe/settings.h> #include <ipxe/features.h> +#include <ipxe/dhcp.h> +#include <ipxe/dhcpv6.h> #include <ipxe/dns.h> /** @file @@ -56,263 +59,525 @@ FEATURE ( FEATURE_PROTOCOL, "DNS", DHCP_EB_FEATURE_DNS, 1 ); __einfo_uniqify ( EINFO_ENXIO, 0x02, "No DNS servers available" ) /** The DNS server */ -static struct sockaddr_tcpip nameserver = { - .st_port = htons ( DNS_PORT ), -}; - -/** The local domain */ -static char *localdomain; - -/** A DNS request */ -struct dns_request { - /** Reference counter */ - struct refcnt refcnt; - /** Name resolution interface */ - struct interface resolv; - /** Data transfer interface */ - struct interface socket; - /** Retry timer */ - struct retry_timer timer; - - /** Socket address to fill in with resolved address */ +static union { struct sockaddr sa; - /** Current query packet */ - struct dns_query query; - /** Location of query info structure within current packet - * - * The query info structure is located immediately after the - * compressed name. - */ - struct dns_query_info *qinfo; - /** Recursion counter */ - unsigned int recursion; + struct sockaddr_tcpip st; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +} nameserver = { + .st = { + .st_port = htons ( DNS_PORT ), + }, }; +/** The DNS search list */ +static struct dns_name dns_search; + /** - * Mark DNS request as complete + * Encode a DNS name using RFC1035 encoding * - * @v dns DNS request - * @v rc Return status code + * @v string DNS name as a string + * @v name DNS name to fill in + * @ret len Length of DNS name, or negative error */ -static void dns_done ( struct dns_request *dns, int rc ) { +int dns_encode ( const char *string, struct dns_name *name ) { + uint8_t *start = ( name->data + name->offset ); + uint8_t *end = ( name->data + name->len ); + uint8_t *dst = start; + size_t len = 0; + char c; - /* Stop the retry timer */ - stop_timer ( &dns->timer ); + /* Encode name */ + while ( ( c = *(string++) ) ) { - /* Shut down interfaces */ - intf_shutdown ( &dns->socket, rc ); - intf_shutdown ( &dns->resolv, rc ); + /* Handle '.' separators */ + if ( c == '.' ) { + + /* Reject consecutive '.' */ + if ( ( len == 0 ) && ( dst != start ) ) + return -EINVAL; + + /* Terminate if this is the trailing '.' */ + if ( *string == '\0' ) + break; + + /* Reject initial non-terminating '.' */ + if ( len == 0 ) + return -EINVAL; + + /* Reset length */ + len = 0; + + } else { + + /* Increment length */ + len++; + + /* Check for overflow */ + if ( len > DNS_MAX_LABEL_LEN ) + return -EINVAL; + } + + /* Copy byte, update length */ + if ( ++dst < end ) { + *dst = c; + dst[-len] = len; + } + } + + /* Add terminating root marker */ + if ( len ) + dst++; + if ( dst < end ) + *dst = '\0'; + dst++; + + return ( dst - start ); } /** - * Compare DNS reply name against the query name from the original request + * Find start of valid label within an RFC1035-encoded DNS name * - * @v dns DNS request - * @v reply DNS reply - * @v rname Reply name - * @ret zero Names match - * @ret non-zero Names do not match + * @v name DNS name + * @v offset Current offset + * @ret offset Offset of label, or negative error */ -static int dns_name_cmp ( struct dns_request *dns, - const struct dns_header *reply, - const char *rname ) { - const char *qname = dns->query.payload; - int i; +static int dns_label ( struct dns_name *name, size_t offset ) { + const uint8_t *byte; + const uint16_t *word; + size_t len; + size_t ptr; while ( 1 ) { - /* Obtain next section of rname */ - while ( ( *rname ) & 0xc0 ) { - rname = ( ( ( char * ) reply ) + - ( ntohs( *((uint16_t *)rname) ) & ~0xc000 )); - } - /* Check that lengths match */ - if ( *rname != *qname ) - return -1; - /* If length is zero, we have reached the end */ - if ( ! *qname ) - return 0; - /* Check that data matches */ - for ( i = *qname + 1; i > 0 ; i-- ) { - if ( *(rname++) != *(qname++) ) - return -1; + + /* Fail if we have overrun the DNS name */ + if ( ( offset + sizeof ( *byte) ) > name->len ) + return -EINVAL; + byte = ( name->data + offset ); + + /* Follow compression pointer, if applicable */ + if ( DNS_IS_COMPRESSED ( *byte ) ) { + + /* Fail if we have overrun the DNS name */ + if ( ( offset + sizeof ( *word ) ) > name->len ) + return -EINVAL; + word = ( name->data + offset ); + + /* Extract pointer to new offset */ + ptr = DNS_COMPRESSED_OFFSET ( ntohs ( *word ) ); + + /* Fail if pointer does not point backwards. + * (This guarantees termination of the + * function.) + */ + if ( ptr >= offset ) + return -EINVAL; + + /* Continue from new offset */ + offset = ptr; + continue; } + + /* Fail if we have overrun the DNS name */ + len = *byte; + if ( ( offset + sizeof ( *byte ) + len ) > name->len ) + return -EINVAL; + + /* We have a valid label */ + return offset; } } /** - * Skip over a (possibly compressed) DNS name + * Decode RFC1035-encoded DNS name * * @v name DNS name - * @ret name Next DNS name + * @v data Output buffer + * @v len Length of output buffer + * @ret len Length of decoded DNS name, or negative error */ -static const char * dns_skip_name ( const char *name ) { - while ( 1 ) { - if ( ! *name ) { - /* End of name */ - return ( name + 1); +int dns_decode ( struct dns_name *name, char *data, size_t len ) { + unsigned int recursion_limit = name->len; /* Generous upper bound */ + int offset = name->offset; + const uint8_t *label; + size_t decoded_len = 0; + size_t label_len; + size_t copy_len; + + while ( recursion_limit-- ) { + + /* Find valid DNS label */ + offset = dns_label ( name, offset ); + if ( offset < 0 ) + return offset; + + /* Terminate if we have reached the root */ + label = ( name->data + offset ); + label_len = *(label++); + if ( label_len == 0 ) { + if ( decoded_len < len ) + *data = '\0'; + return decoded_len; } - if ( *name & 0xc0 ) { - /* Start of a compressed name */ - return ( name + 2 ); - } - /* Uncompressed name portion */ - name += *name + 1; + + /* Prepend '.' if applicable */ + if ( decoded_len && ( decoded_len++ < len ) ) + *(data++) = '.'; + + /* Copy label to output buffer */ + copy_len = ( ( decoded_len < len ) ? ( len - decoded_len ) : 0); + if ( copy_len > label_len ) + copy_len = label_len; + memcpy ( data, label, copy_len ); + data += copy_len; + decoded_len += label_len; + + /* Move to next label */ + offset += ( sizeof ( *label ) + label_len ); } + + /* Recursion limit exceeded */ + return -EINVAL; } /** - * Find an RR in a reply packet corresponding to our query + * Compare DNS names for equality * - * @v dns DNS request - * @v reply DNS reply - * @ret rr DNS RR, or NULL if not found + * @v first First DNS name + * @v second Second DNS name + * @ret rc Return status code */ -static union dns_rr_info * dns_find_rr ( struct dns_request *dns, - const struct dns_header *reply ) { - int i, cmp; - const char *p = ( ( char * ) reply ) + sizeof ( struct dns_header ); - union dns_rr_info *rr_info; - - /* Skip over the questions section */ - for ( i = ntohs ( reply->qdcount ) ; i > 0 ; i-- ) { - p = dns_skip_name ( p ) + sizeof ( struct dns_query_info ); - } +int dns_compare ( struct dns_name *first, struct dns_name *second ) { + unsigned int recursion_limit = first->len; /* Generous upper bound */ + int first_offset = first->offset; + int second_offset = second->offset; + const uint8_t *first_label; + const uint8_t *second_label; + size_t label_len; + size_t len; + + while ( recursion_limit-- ) { + + /* Find valid DNS labels */ + first_offset = dns_label ( first, first_offset ); + if ( first_offset < 0 ) + return first_offset; + second_offset = dns_label ( second, second_offset ); + if ( second_offset < 0 ) + return second_offset; + + /* Compare label lengths */ + first_label = ( first->data + first_offset ); + second_label = ( second->data + second_offset ); + label_len = *(first_label++); + if ( label_len != *(second_label++) ) + return -ENOENT; + len = ( sizeof ( *first_label ) + label_len ); + + /* Terminate if we have reached the root */ + if ( label_len == 0 ) + return 0; + + /* Compare label contents (case-insensitively) */ + while ( label_len-- ) { + if ( tolower ( *(first_label++) ) != + tolower ( *(second_label++) ) ) + return -ENOENT; + } - /* Process the answers section */ - for ( i = ntohs ( reply->ancount ) ; i > 0 ; i-- ) { - cmp = dns_name_cmp ( dns, reply, p ); - p = dns_skip_name ( p ); - rr_info = ( ( union dns_rr_info * ) p ); - if ( cmp == 0 ) - return rr_info; - p += ( sizeof ( rr_info->common ) + - ntohs ( rr_info->common.rdlength ) ); + /* Move to next labels */ + first_offset += len; + second_offset += len; } - return NULL; + /* Recursion limit exceeded */ + return -EINVAL; } /** - * Append DHCP domain name if available and name is not fully qualified + * Copy a DNS name * - * @v string Name as a NUL-terminated string - * @ret fqdn Fully-qualified domain name, malloc'd copy - * - * The caller must free fqdn which is allocated even if the name is already - * fully qualified. + * @v src Source DNS name + * @v dst Destination DNS name + * @ret len Length of copied DNS name, or negative error */ -static char * dns_qualify_name ( const char *string ) { - char *fqdn; - - /* Leave unchanged if already fully-qualified or no local domain */ - if ( ( ! localdomain ) || ( strchr ( string, '.' ) != 0 ) ) - return strdup ( string ); +int dns_copy ( struct dns_name *src, struct dns_name *dst ) { + unsigned int recursion_limit = src->len; /* Generous upper bound */ + int src_offset = src->offset; + size_t dst_offset = dst->offset; + const uint8_t *label; + size_t label_len; + size_t copy_len; + size_t len; + + while ( recursion_limit-- ) { + + /* Find valid DNS label */ + src_offset = dns_label ( src, src_offset ); + if ( src_offset < 0 ) + return src_offset; + + /* Copy as an uncompressed label */ + label = ( src->data + src_offset ); + label_len = *label; + len = ( sizeof ( *label ) + label_len ); + copy_len = ( ( dst_offset < dst->len ) ? + ( dst->len - dst_offset ) : 0 ); + if ( copy_len > len ) + copy_len = len; + memcpy ( ( dst->data + dst_offset ), label, copy_len ); + src_offset += len; + dst_offset += len; + + /* Terminate if we have reached the root */ + if ( label_len == 0 ) + return ( dst_offset - dst->offset ); + } - /* Append local domain to name */ - asprintf ( &fqdn, "%s.%s", string, localdomain ); - return fqdn; + /* Recursion limit exceeded */ + return -EINVAL; } /** - * Convert a standard NUL-terminated string to a DNS name + * Skip RFC1035-encoded DNS name * - * @v string Name as a NUL-terminated string - * @v buf Buffer in which to place DNS name - * @ret next Byte following constructed DNS name + * @v name DNS name + * @ret offset Offset to next name, or negative error + */ +int dns_skip ( struct dns_name *name ) { + unsigned int recursion_limit = name->len; /* Generous upper bound */ + int offset = name->offset; + int prev_offset; + const uint8_t *label; + size_t label_len; + + while ( recursion_limit-- ) { + + /* Find valid DNS label */ + prev_offset = offset; + offset = dns_label ( name, prev_offset ); + if ( offset < 0 ) + return offset; + + /* Terminate if we have reached a compression pointer */ + if ( offset != prev_offset ) + return ( prev_offset + sizeof ( uint16_t ) ); + + /* Skip this label */ + label = ( name->data + offset ); + label_len = *label; + offset += ( sizeof ( *label ) + label_len ); + + /* Terminate if we have reached the root */ + if ( label_len == 0 ) + return offset; + } + + /* Recursion limit exceeded */ + return -EINVAL; +} + +/** + * Skip RFC1035-encoded DNS name in search list * - * DNS names consist of "<length>element" pairs. + * @v name DNS name + * @ret offset Offset to next non-empty name, or negative error */ -static char * dns_make_name ( const char *string, char *buf ) { - char *length_byte; - char c; +static int dns_skip_search ( struct dns_name *name ) { + int offset; - length_byte = buf++; - *length_byte = 0; - do { - c = *(string++); - if ( ( c == '.' ) || ( c == '\0' ) ) { - if ( *length_byte ) { - length_byte = buf++; - *length_byte = 0; - } - } else { - *(buf++) = c; - (*length_byte)++; - } - } while ( c ); + /* Find next name */ + offset = dns_skip ( name ); + if ( offset < 0 ) + return offset; + + /* Skip over any subsequent empty names (e.g. due to padding + * bytes used in the NDP DNSSL option). + */ + while ( ( offset < ( ( int ) name->len ) ) && + ( *( ( uint8_t * ) ( name->data + offset ) ) == 0 ) ) { + offset++; + } - return buf; + return offset; } /** - * Convert an uncompressed DNS name to a NUL-terminated string + * Transcribe DNS name (for debugging) * * @v name DNS name - * @ret string NUL-terminated string + * @ret string Transcribed DNS name + */ +static const char * dns_name ( struct dns_name *name ) { + static char buf[256]; + int len; + + len = dns_decode ( name, buf, sizeof ( buf ) ); + return ( ( len < 0 ) ? "<INVALID>" : buf ); +} + +/** + * Name a DNS query type (for debugging) * - * Produce a printable version of a DNS name. Used only for debugging. + * @v type Query type (in network byte order) + * @ret name Type name */ -static inline char * dns_unmake_name ( char *name ) { - char *p; - unsigned int len; - - p = name; - while ( ( len = *p ) ) { - *(p++) = '.'; - p += len; +static const char * dns_type ( uint16_t type ) { + switch ( type ) { + case htons ( DNS_TYPE_A ): return "A"; + case htons ( DNS_TYPE_AAAA ): return "AAAA"; + case htons ( DNS_TYPE_CNAME ): return "CNAME"; + default: return "<UNKNOWN>"; } +} + +/** A DNS request */ +struct dns_request { + /** Reference counter */ + struct refcnt refcnt; + /** Name resolution interface */ + struct interface resolv; + /** Data transfer interface */ + struct interface socket; + /** Retry timer */ + struct retry_timer timer; + + /** Socket address to fill in with resolved address */ + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } address; + /** Initial query type */ + uint16_t qtype; + /** Buffer for current query */ + struct { + /** Query header */ + struct dns_header query; + /** Name buffer */ + char name[DNS_MAX_NAME_LEN]; + /** Space for question */ + struct dns_question padding; + } __attribute__ (( packed )) buf; + /** Current query name */ + struct dns_name name; + /** Question within current query */ + struct dns_question *question; + /** Length of current query */ + size_t len; + /** Offset of search suffix within current query */ + size_t offset; + /** Search list */ + struct dns_name search; + /** Recursion counter */ + unsigned int recursion; +}; - return name + 1; +/** + * Mark DNS request as complete + * + * @v dns DNS request + * @v rc Return status code + */ +static void dns_done ( struct dns_request *dns, int rc ) { + + /* Stop the retry timer */ + stop_timer ( &dns->timer ); + + /* Shut down interfaces */ + intf_shutdown ( &dns->socket, rc ); + intf_shutdown ( &dns->resolv, rc ); } /** - * Decompress a DNS name + * Mark DNS request as resolved and complete * - * @v reply DNS replay - * @v name DNS name - * @v buf Buffer into which to decompress DNS name - * @ret next Byte following decompressed DNS name + * @v dns DNS request + * @v rc Return status code */ -static char * dns_decompress_name ( const struct dns_header *reply, - const char *name, char *buf ) { - int i, len; - - do { - /* Obtain next section of name */ - while ( ( *name ) & 0xc0 ) { - name = ( ( char * ) reply + - ( ntohs ( *((uint16_t *)name) ) & ~0xc000 ) ); - } - /* Copy data */ - len = *name; - for ( i = len + 1 ; i > 0 ; i-- ) { - *(buf++) = *(name++); - } - } while ( len ); - return buf; +static void dns_resolved ( struct dns_request *dns ) { + + DBGC ( dns, "DNS %p found address %s\n", + dns, sock_ntoa ( &dns->address.sa ) ); + + /* Return resolved address */ + resolv_done ( &dns->resolv, &dns->address.sa ); + + /* Mark operation as complete */ + dns_done ( dns, 0 ); } /** - * Send next packet in DNS request + * Construct DNS question * * @v dns DNS request + * @ret rc Return status code */ -static int dns_send_packet ( struct dns_request *dns ) { - static unsigned int qid = 0; - size_t qlen; +static int dns_question ( struct dns_request *dns ) { + static struct dns_name search_root = { + .data = "", + .len = 1, + }; + struct dns_name *search = &dns->search; + int len; + size_t offset; + + /* Use root suffix if search list is empty */ + if ( search->offset == search->len ) + search = &search_root; + + /* Overwrite current suffix */ + dns->name.offset = dns->offset; + len = dns_copy ( search, &dns->name ); + if ( len < 0 ) + return len; + + /* Sanity check */ + offset = ( dns->name.offset + len ); + if ( offset > dns->name.len ) { + DBGC ( dns, "DNS %p name is too long\n", dns ); + return -EINVAL; + } + + /* Construct question */ + dns->question = ( ( ( void * ) &dns->buf ) + offset ); + dns->question->qtype = dns->qtype; + dns->question->qclass = htons ( DNS_CLASS_IN ); + + /* Store length */ + dns->len = ( offset + sizeof ( *(dns->question) ) ); + + /* Restore name */ + dns->name.offset = offsetof ( typeof ( dns->buf ), name ); - /* Increment query ID */ - dns->query.dns.id = htons ( ++qid ); + DBGC2 ( dns, "DNS %p question is %s type %s\n", dns, + dns_name ( &dns->name ), dns_type ( dns->question->qtype ) ); - DBGC ( dns, "DNS %p sending query ID %d\n", dns, qid ); + return 0; +} + +/** + * Send DNS query + * + * @v dns DNS request + * @ret rc Return status code + */ +static int dns_send_packet ( struct dns_request *dns ) { + struct dns_header *query = &dns->buf.query; /* Start retransmission timer */ start_timer ( &dns->timer ); + /* Generate query identifier */ + query->id = random(); + + /* Send query */ + DBGC ( dns, "DNS %p sending query ID %#04x for %s type %s\n", dns, + ntohs ( query->id ), dns_name ( &dns->name ), + dns_type ( dns->question->qtype ) ); + /* Send the data */ - qlen = ( ( ( void * ) dns->qinfo ) - ( ( void * ) &dns->query ) - + sizeof ( dns->qinfo ) ); - return xfer_deliver_raw ( &dns->socket, &dns->query, qlen ); + return xfer_deliver_raw ( &dns->socket, query, dns->len ); } /** @@ -343,125 +608,238 @@ static void dns_timer_expired ( struct retry_timer *timer, int fail ) { static int dns_xfer_deliver ( struct dns_request *dns, struct io_buffer *iobuf, struct xfer_metadata *meta __unused ) { - const struct dns_header *reply = iobuf->data; - union dns_rr_info *rr_info; - struct sockaddr_in *sin; - unsigned int qtype = dns->qinfo->qtype; + struct dns_header *response = iobuf->data; + struct dns_header *query = &dns->buf.query; + unsigned int qtype = dns->question->qtype; + struct dns_name buf; + union dns_rr *rr; + int offset; + size_t answer_offset; + size_t next_offset; + size_t rdlength; + size_t name_len; int rc; /* Sanity check */ - if ( iob_len ( iobuf ) < sizeof ( *reply ) ) { + if ( iob_len ( iobuf ) < sizeof ( *response ) ) { DBGC ( dns, "DNS %p received underlength packet length %zd\n", dns, iob_len ( iobuf ) ); rc = -EINVAL; goto done; } - /* Check reply ID matches query ID */ - if ( reply->id != dns->query.dns.id ) { - DBGC ( dns, "DNS %p received unexpected reply ID %d " - "(wanted %d)\n", dns, ntohs ( reply->id ), - ntohs ( dns->query.dns.id ) ); + /* Check response ID matches query ID */ + if ( response->id != query->id ) { + DBGC ( dns, "DNS %p received unexpected response ID %#04x " + "(wanted %d)\n", dns, ntohs ( response->id ), + ntohs ( query->id ) ); rc = -EINVAL; goto done; } + DBGC ( dns, "DNS %p received response ID %#04x\n", + dns, ntohs ( response->id ) ); - DBGC ( dns, "DNS %p received reply ID %d\n", dns, ntohs ( reply->id )); + /* Check that we have exactly one question */ + if ( response->qdcount != htons ( 1 ) ) { + DBGC ( dns, "DNS %p received response with %d questions\n", + dns, ntohs ( response->qdcount ) ); + rc = -EINVAL; + goto done; + } - /* Stop the retry timer. After this point, each code path - * must either restart the timer by calling dns_send_packet(), - * or mark the DNS operation as complete by calling - * dns_done() - */ - stop_timer ( &dns->timer ); + /* Skip question section */ + buf.data = iobuf->data; + buf.offset = sizeof ( *response ); + buf.len = iob_len ( iobuf ); + offset = dns_skip ( &buf ); + if ( offset < 0 ) { + rc = offset; + DBGC ( dns, "DNS %p received response with malformed " + "question: %s\n", dns, strerror ( rc ) ); + goto done; + } + answer_offset = ( offset + sizeof ( struct dns_question ) ); /* Search through response for useful answers. Do this * multiple times, to take advantage of useful nameservers * which send us e.g. the CNAME *and* the A record for the * pointed-to name. */ - while ( ( rr_info = dns_find_rr ( dns, reply ) ) ) { - switch ( rr_info->common.type ) { + for ( buf.offset = answer_offset ; buf.offset != buf.len ; + buf.offset = next_offset ) { + + /* Check for valid name */ + offset = dns_skip ( &buf ); + if ( offset < 0 ) { + rc = offset; + DBGC ( dns, "DNS %p received response with malformed " + "answer: %s\n", dns, strerror ( rc ) ); + goto done; + } - case htons ( DNS_TYPE_A ): + /* Check for sufficient space for resource record */ + rr = ( buf.data + offset ); + if ( ( offset + sizeof ( rr->common ) ) > buf.len ) { + DBGC ( dns, "DNS %p received response with underlength " + "RR\n", dns ); + rc = -EINVAL; + goto done; + } + rdlength = ntohs ( rr->common.rdlength ); + next_offset = ( offset + sizeof ( rr->common ) + rdlength ); + if ( next_offset > buf.len ) { + DBGC ( dns, "DNS %p received response with underlength " + "RR\n", dns ); + rc = -EINVAL; + goto done; + } - /* Found the target A record */ - DBGC ( dns, "DNS %p found address %s\n", - dns, inet_ntoa ( rr_info->a.in_addr ) ); - sin = ( struct sockaddr_in * ) &dns->sa; - sin->sin_family = AF_INET; - sin->sin_addr = rr_info->a.in_addr; + /* Skip non-matching names */ + if ( dns_compare ( &buf, &dns->name ) != 0 ) { + DBGC2 ( dns, "DNS %p ignoring response for %s type " + "%s\n", dns, dns_name ( &buf ), + dns_type ( rr->common.type ) ); + continue; + } + + /* Handle answer */ + switch ( rr->common.type ) { - /* Return resolved address */ - resolv_done ( &dns->resolv, &dns->sa ); + case htons ( DNS_TYPE_AAAA ): - /* Mark operation as complete */ - dns_done ( dns, 0 ); + /* Found the target AAAA record */ + if ( rdlength < sizeof ( dns->address.sin6.sin6_addr )){ + DBGC ( dns, "DNS %p received response with " + "underlength AAAA\n", dns ); + rc = -EINVAL; + goto done; + } + dns->address.sin6.sin6_family = AF_INET6; + memcpy ( &dns->address.sin6.sin6_addr, + &rr->aaaa.in6_addr, + sizeof ( dns->address.sin6.sin6_addr ) ); + dns_resolved ( dns ); + rc = 0; + goto done; + + case htons ( DNS_TYPE_A ): + + /* Found the target A record */ + if ( rdlength < sizeof ( dns->address.sin.sin_addr ) ) { + DBGC ( dns, "DNS %p received response with " + "underlength A\n", dns ); + rc = -EINVAL; + goto done; + } + dns->address.sin.sin_family = AF_INET; + dns->address.sin.sin_addr = rr->a.in_addr; + dns_resolved ( dns ); rc = 0; goto done; case htons ( DNS_TYPE_CNAME ): - /* Found a CNAME record; update query and recurse */ - DBGC ( dns, "DNS %p found CNAME\n", dns ); - dns->qinfo = ( void * ) dns_decompress_name ( reply, - rr_info->cname.cname, - dns->query.payload ); - dns->qinfo->qtype = htons ( DNS_TYPE_A ); - dns->qinfo->qclass = htons ( DNS_CLASS_IN ); - /* Terminate the operation if we recurse too far */ if ( ++dns->recursion > DNS_MAX_CNAME_RECURSION ) { DBGC ( dns, "DNS %p recursion exceeded\n", dns ); - dns_done ( dns, -ELOOP ); - rc = 0; + rc = -ELOOP; + dns_done ( dns, rc ); + goto done; + } + + /* Found a CNAME record; update query and recurse */ + buf.offset = ( offset + sizeof ( rr->cname ) ); + DBGC ( dns, "DNS %p found CNAME %s\n", + dns, dns_name ( &buf ) ); + dns->search.offset = dns->search.len; + name_len = dns_copy ( &buf, &dns->name ); + dns->offset = ( offsetof ( typeof ( dns->buf ), name ) + + name_len - 1 /* Strip root label */ ); + if ( ( rc = dns_question ( dns ) ) != 0 ) { + dns_done ( dns, rc ); goto done; } + next_offset = answer_offset; break; default: DBGC ( dns, "DNS %p got unknown record type %d\n", - dns, ntohs ( rr_info->common.type ) ); + dns, ntohs ( rr->common.type ) ); break; } } - + + /* Stop the retry timer. After this point, each code path + * must either restart the timer by calling dns_send_packet(), + * or mark the DNS operation as complete by calling + * dns_done() + */ + stop_timer ( &dns->timer ); + /* Determine what to do next based on the type of query we * issued and the response we received */ switch ( qtype ) { + case htons ( DNS_TYPE_AAAA ): + /* We asked for an AAAA record and got nothing; try + * the A. + */ + DBGC ( dns, "DNS %p found no AAAA record; trying A\n", dns ); + dns->question->qtype = htons ( DNS_TYPE_A ); + dns_send_packet ( dns ); + rc = 0; + goto done; + case htons ( DNS_TYPE_A ): /* We asked for an A record and got nothing; * try the CNAME. */ DBGC ( dns, "DNS %p found no A record; trying CNAME\n", dns ); - dns->qinfo->qtype = htons ( DNS_TYPE_CNAME ); + dns->question->qtype = htons ( DNS_TYPE_CNAME ); dns_send_packet ( dns ); rc = 0; goto done; case htons ( DNS_TYPE_CNAME ): /* We asked for a CNAME record. If we got a response - * (i.e. if the next A query is already set up), then - * issue it, otherwise abort. + * (i.e. if the next AAAA/A query is already set up), + * then issue it. */ - if ( dns->qinfo->qtype == htons ( DNS_TYPE_A ) ) { + if ( qtype == dns->qtype ) { dns_send_packet ( dns ); rc = 0; goto done; - } else { + } + + /* If we have already reached the end of the search list, + * then terminate lookup. + */ + if ( dns->search.offset == dns->search.len ) { DBGC ( dns, "DNS %p found no CNAME record\n", dns ); - dns_done ( dns, -ENXIO_NO_RECORD ); - rc = 0; + rc = -ENXIO_NO_RECORD; + dns_done ( dns, rc ); + goto done; + } + + /* Move to next entry in search list. This can never fail, + * since we have already used this entry. + */ + DBGC ( dns, "DNS %p found no CNAME record; trying next " + "suffix\n", dns ); + dns->search.offset = dns_skip_search ( &dns->search ); + if ( ( rc = dns_question ( dns ) ) != 0 ) { + dns_done ( dns, rc ); goto done; } + dns_send_packet ( dns ); + goto done; default: assert ( 0 ); - dns_done ( dns, -EINVAL ); rc = -EINVAL; + dns_done ( dns, rc ); goto done; } @@ -515,26 +893,24 @@ static struct interface_descriptor dns_resolv_desc = static int dns_resolv ( struct interface *resolv, const char *name, struct sockaddr *sa ) { struct dns_request *dns; - char *fqdn; + struct dns_header *query; + size_t search_len; + int name_len; int rc; /* Fail immediately if no DNS servers */ - if ( ! nameserver.st_family ) { + if ( ! nameserver.sa.sa_family ) { DBG ( "DNS not attempting to resolve \"%s\": " "no DNS servers\n", name ); rc = -ENXIO_NO_NAMESERVER; goto err_no_nameserver; } - /* Ensure fully-qualified domain name if DHCP option was given */ - fqdn = dns_qualify_name ( name ); - if ( ! fqdn ) { - rc = -ENOMEM; - goto err_qualify_name; - } + /* Determine whether or not to use search list */ + search_len = ( strchr ( name, '.' ) ? 0 : dns_search.len ); /* Allocate DNS structure */ - dns = zalloc ( sizeof ( *dns ) ); + dns = zalloc ( sizeof ( *dns ) + search_len ); if ( ! dns ) { rc = -ENOMEM; goto err_alloc_dns; @@ -543,39 +919,63 @@ static int dns_resolv ( struct interface *resolv, intf_init ( &dns->resolv, &dns_resolv_desc, &dns->refcnt ); intf_init ( &dns->socket, &dns_socket_desc, &dns->refcnt ); timer_init ( &dns->timer, dns_timer_expired, &dns->refcnt ); - memcpy ( &dns->sa, sa, sizeof ( dns->sa ) ); + memcpy ( &dns->address.sa, sa, sizeof ( dns->address.sa ) ); + dns->search.data = ( ( ( void * ) dns ) + sizeof ( *dns ) ); + dns->search.len = search_len; + memcpy ( dns->search.data, dns_search.data, search_len ); + + /* Determine initial query type */ + switch ( nameserver.sa.sa_family ) { + case AF_INET: + dns->qtype = htons ( DNS_TYPE_A ); + break; + case AF_INET6: + dns->qtype = htons ( DNS_TYPE_AAAA ); + break; + default: + rc = -ENOTSUP; + goto err_type; + } - /* Create query */ - dns->query.dns.flags = htons ( DNS_FLAG_QUERY | DNS_FLAG_OPCODE_QUERY | - DNS_FLAG_RD ); - dns->query.dns.qdcount = htons ( 1 ); - dns->qinfo = ( void * ) dns_make_name ( fqdn, dns->query.payload ); - dns->qinfo->qtype = htons ( DNS_TYPE_A ); - dns->qinfo->qclass = htons ( DNS_CLASS_IN ); + /* Construct query */ + query = &dns->buf.query; + query->flags = htons ( DNS_FLAG_RD ); + query->qdcount = htons ( 1 ); + dns->name.data = &dns->buf; + dns->name.offset = offsetof ( typeof ( dns->buf ), name ); + dns->name.len = offsetof ( typeof ( dns->buf ), padding ); + name_len = dns_encode ( name, &dns->name ); + if ( name_len < 0 ) { + rc = name_len; + goto err_encode; + } + dns->offset = ( offsetof ( typeof ( dns->buf ), name ) + + name_len - 1 /* Strip root label */ ); + if ( ( rc = dns_question ( dns ) ) != 0 ) + goto err_question; /* Open UDP connection */ if ( ( rc = xfer_open_socket ( &dns->socket, SOCK_DGRAM, - ( struct sockaddr * ) &nameserver, - NULL ) ) != 0 ) { + &nameserver.sa, NULL ) ) != 0 ) { DBGC ( dns, "DNS %p could not open socket: %s\n", dns, strerror ( rc ) ); goto err_open_socket; } - /* Send first DNS packet */ - dns_send_packet ( dns ); + /* Start timer to trigger first packet */ + start_timer_nodelay ( &dns->timer ); /* Attach parent interface, mortalise self, and return */ intf_plug_plug ( &dns->resolv, resolv ); ref_put ( &dns->refcnt ); - free ( fqdn ); return 0; err_open_socket: - err_alloc_dns: + err_question: + err_encode: + err_type: ref_put ( &dns->refcnt ); - err_qualify_name: - free ( fqdn ); + err_alloc_dns: err_no_nameserver: return rc; } @@ -593,42 +993,155 @@ struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = { ****************************************************************************** */ -/** DNS server setting */ -struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = { +/** + * Format DNS search list setting + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int format_dnssl_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, + char *buf, size_t len ) { + struct dns_name name = { + .data = ( ( void * ) raw ), + .len = raw_len, + }; + size_t remaining = len; + size_t total = 0; + int name_len; + + while ( name.offset < raw_len ) { + + /* Decode name */ + remaining = ( ( total < len ) ? ( len - total ) : 0 ); + name_len = dns_decode ( &name, ( buf + total ), remaining ); + if ( name_len < 0 ) + return name_len; + total += name_len; + + /* Move to next name */ + name.offset = dns_skip_search ( &name ); + + /* Add separator if applicable */ + if ( name.offset != raw_len ) { + if ( total < len ) + buf[total] = ' '; + total++; + } + } + + return total; +} + +/** A DNS search list setting type */ +const struct setting_type setting_type_dnssl __setting_type = { + .name = "dnssl", + .format = format_dnssl_setting, +}; + +/** IPv4 DNS server setting */ +const struct setting dns_setting __setting ( SETTING_IP_EXTRA, dns ) = { .name = "dns", .description = "DNS server", .tag = DHCP_DNS_SERVERS, .type = &setting_type_ipv4, }; +/** IPv6 DNS server setting */ +const struct setting dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ) = { + .name = "dns6", + .description = "DNS server", + .tag = DHCPV6_DNS_SERVERS, + .type = &setting_type_ipv6, + .scope = &ipv6_scope, +}; + +/** DNS search list */ +const struct setting dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = { + .name = "dnssl", + .description = "DNS search list", + .tag = DHCP_DOMAIN_SEARCH, + .type = &setting_type_dnssl, +}; + +/** + * Apply DNS search list + * + */ +static void apply_dns_search ( void ) { + char *localdomain; + int len; + + /* Free existing search list */ + free ( dns_search.data ); + memset ( &dns_search, 0, sizeof ( dns_search ) ); + + /* Fetch DNS search list */ + len = fetch_setting_copy ( NULL, &dnssl_setting, NULL, NULL, + &dns_search.data ); + if ( len >= 0 ) { + dns_search.len = len; + return; + } + + /* If no DNS search list exists, try to fetch the local domain */ + fetch_string_setting_copy ( NULL, &domain_setting, &localdomain ); + if ( localdomain ) { + len = dns_encode ( localdomain, &dns_search ); + if ( len >= 0 ) { + dns_search.data = malloc ( len ); + if ( dns_search.data ) { + dns_search.len = len; + dns_encode ( localdomain, &dns_search ); + } + } + free ( localdomain ); + return; + } +} + /** * Apply DNS settings * * @ret rc Return status code */ static int apply_dns_settings ( void ) { - struct sockaddr_in *sin_nameserver = - ( struct sockaddr_in * ) &nameserver; - int len; /* Fetch DNS server address */ - nameserver.st_family = 0; - if ( ( len = fetch_ipv4_setting ( NULL, &dns_setting, - &sin_nameserver->sin_addr ) ) >= 0 ){ - nameserver.st_family = AF_INET; + nameserver.sa.sa_family = 0; + if ( fetch_ipv6_setting ( NULL, &dns6_setting, + &nameserver.sin6.sin6_addr ) >= 0 ) { + nameserver.sin6.sin6_family = AF_INET6; + } else if ( fetch_ipv4_setting ( NULL, &dns_setting, + &nameserver.sin.sin_addr ) >= 0 ) { + nameserver.sin.sin_family = AF_INET; + } + if ( nameserver.sa.sa_family ) { DBG ( "DNS using nameserver %s\n", - inet_ntoa ( sin_nameserver->sin_addr ) ); + sock_ntoa ( &nameserver.sa ) ); } - /* Get local domain DHCP option */ - free ( localdomain ); - if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting, - &localdomain ) ) < 0 ) { - DBG ( "DNS could not fetch local domain: %s\n", - strerror ( len ) ); + /* Fetch DNS search list */ + apply_dns_search(); + if ( DBG_LOG && ( dns_search.len != 0 ) ) { + struct dns_name name; + int offset; + + DBG ( "DNS search list:" ); + memcpy ( &name, &dns_search, sizeof ( name ) ); + while ( name.offset != name.len ) { + DBG ( " %s", dns_name ( &name ) ); + offset = dns_skip_search ( &name ); + if ( offset < 0 ) + break; + name.offset = offset; + } + DBG ( "\n" ); } - if ( localdomain ) - DBG ( "DNS local domain %s\n", localdomain ); return 0; } diff --git a/roms/ipxe/src/net/udp/slam.c b/roms/ipxe/src/net/udp/slam.c index e1b584fec..3cb492d73 100644 --- a/roms/ipxe/src/net/udp/slam.c +++ b/roms/ipxe/src/net/udp/slam.c @@ -723,7 +723,7 @@ static int slam_open ( struct interface *xfer, struct uri *uri ) { /* Open multicast socket */ memcpy ( &multicast, &default_multicast, sizeof ( multicast ) ); - if ( uri->path && + if ( uri->path && ( ( rc = slam_parse_multicast_address ( slam, uri->path, &multicast ) ) != 0 ) ) { goto err; diff --git a/roms/ipxe/src/net/udp/syslog.c b/roms/ipxe/src/net/udp/syslog.c index 00101008b..d51737125 100644 --- a/roms/ipxe/src/net/udp/syslog.c +++ b/roms/ipxe/src/net/udp/syslog.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/open.h> #include <ipxe/tcpip.h> #include <ipxe/dhcp.h> +#include <ipxe/dhcpv6.h> #include <ipxe/settings.h> #include <ipxe/console.h> #include <ipxe/lineconsole.h> @@ -45,9 +46,15 @@ FILE_LICENCE ( GPL2_OR_LATER ); #endif /** The syslog server */ -static struct sockaddr_tcpip logserver = { - .st_family = AF_INET, - .st_port = htons ( SYSLOG_PORT ), +static union { + struct sockaddr sa; + struct sockaddr_tcpip st; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +} logserver = { + .st = { + .st_port = htons ( SYSLOG_PORT ), + }, }; /** Syslog UDP interface operations */ @@ -111,10 +118,12 @@ static unsigned int syslog_severity = SYSLOG_DEFAULT_SEVERITY; /** * Handle ANSI set syslog priority (private sequence) * + * @v ctx ANSI escape sequence context * @v count Parameter count * @v params List of graphic rendition aspects */ -static void syslog_handle_priority ( unsigned int count __unused, +static void syslog_handle_priority ( struct ansiesc_context *ctx __unused, + unsigned int count __unused, int params[] ) { if ( params[0] >= 0 ) { syslog_severity = params[0]; @@ -174,7 +183,7 @@ static void syslog_putchar ( int character ) { /** Syslog console driver */ struct console_driver syslog_console __console_driver = { .putchar = syslog_putchar, - .disabled = 1, + .disabled = CONSOLE_DISABLED, .usage = CONSOLE_SYSLOG, }; @@ -185,50 +194,57 @@ struct console_driver syslog_console __console_driver = { ****************************************************************************** */ -/** Syslog server setting */ -struct setting syslog_setting __setting ( SETTING_MISC ) = { +/** IPv4 syslog server setting */ +const struct setting syslog_setting __setting ( SETTING_MISC, syslog ) = { .name = "syslog", .description = "Syslog server", .tag = DHCP_LOG_SERVERS, .type = &setting_type_ipv4, }; +/** IPv6 syslog server setting */ +const struct setting syslog6_setting __setting ( SETTING_MISC, syslog6 ) = { + .name = "syslog6", + .description = "Syslog server", + .tag = DHCPV6_LOG_SERVERS, + .type = &setting_type_ipv6, + .scope = &ipv6_scope, +}; + /** * Apply syslog settings * * @ret rc Return status code */ static int apply_syslog_settings ( void ) { - struct sockaddr_in *sin_logserver = - ( struct sockaddr_in * ) &logserver; - struct in_addr old_addr; - int len; + struct sockaddr old_logserver; int rc; /* Fetch hostname and domain name */ free ( syslog_hostname ); - if ( ( len = fetch_string_setting_copy ( NULL, &hostname_setting, - &syslog_hostname ) ) < 0 ) { - rc = len; - DBG ( "SYSLOG could not fetch hostname: %s\n", strerror ( rc )); - } + fetch_string_setting_copy ( NULL, &hostname_setting, &syslog_hostname ); free ( syslog_domain ); - if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting, - &syslog_domain ) ) < 0 ) { - rc = len; - DBG ( "SYSLOG could not fetch domain: %s\n", strerror ( rc ) ); - } + fetch_string_setting_copy ( NULL, &domain_setting, &syslog_domain ); /* Fetch log server */ - syslog_console.disabled = 1; - old_addr.s_addr = sin_logserver->sin_addr.s_addr; - if ( ( len = fetch_ipv4_setting ( NULL, &syslog_setting, - &sin_logserver->sin_addr ) ) >= 0 ) { + syslog_console.disabled = CONSOLE_DISABLED; + memcpy ( &old_logserver, &logserver, sizeof ( old_logserver ) ); + logserver.sa.sa_family = 0; + if ( fetch_ipv6_setting ( NULL, &syslog6_setting, + &logserver.sin6.sin6_addr ) >= 0 ) { + logserver.sin6.sin6_family = AF_INET6; + } else if ( fetch_ipv4_setting ( NULL, &syslog_setting, + &logserver.sin.sin_addr ) >= 0 ) { + logserver.sin.sin_family = AF_INET; + } + if ( logserver.sa.sa_family ) { syslog_console.disabled = 0; + DBG ( "SYSLOG using log server %s\n", + sock_ntoa ( &logserver.sa ) ); } /* Do nothing unless log server has changed */ - if ( sin_logserver->sin_addr.s_addr == old_addr.s_addr ) + if ( memcmp ( &logserver, &old_logserver, sizeof ( logserver ) ) == 0 ) return 0; /* Reset syslog connection */ @@ -242,14 +258,11 @@ static int apply_syslog_settings ( void ) { /* Connect to log server */ if ( ( rc = xfer_open_socket ( &syslogger, SOCK_DGRAM, - ( ( struct sockaddr * ) &logserver ), - NULL ) ) != 0 ) { + &logserver.sa, NULL ) ) != 0 ) { DBG ( "SYSLOG cannot connect to log server: %s\n", strerror ( rc ) ); return rc; } - DBG ( "SYSLOG using log server %s\n", - inet_ntoa ( sin_logserver->sin_addr ) ); return 0; } diff --git a/roms/ipxe/src/net/udp/tftp.c b/roms/ipxe/src/net/udp/tftp.c index a6c64b4ab..ee827ae3d 100644 --- a/roms/ipxe/src/net/udp/tftp.c +++ b/roms/ipxe/src/net/udp/tftp.c @@ -288,24 +288,6 @@ static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) { } /** - * TFTP requested blocksize - * - * This is treated as a global configuration parameter. - */ -static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE; - -/** - * Set TFTP request blocksize - * - * @v blksize Requested block size - */ -void tftp_set_request_blksize ( unsigned int blksize ) { - if ( blksize < TFTP_DEFAULT_BLKSIZE ) - blksize = TFTP_DEFAULT_BLKSIZE; - tftp_request_blksize = blksize; -} - -/** * MTFTP multicast receive address * * This is treated as a global configuration parameter. @@ -341,22 +323,11 @@ void tftp_set_mtftp_port ( unsigned int port ) { * @ret rc Return status code */ static int tftp_send_rrq ( struct tftp_request *tftp ) { + const char *path = tftp->uri->path; struct tftp_rrq *rrq; - const char *path; size_t len; struct io_buffer *iobuf; - - /* Strip initial '/' if present. If we were opened via the - * URI interface, then there will be an initial '/', since a - * full tftp:// URI provides no way to specify a non-absolute - * path. However, many TFTP servers (particularly Windows - * TFTP servers) complain about having an initial '/', and it - * violates user expectations to have a '/' silently added to - * the DHCP-specified filename. - */ - path = tftp->uri->path; - if ( *path == '/' ) - path++; + size_t blksize; DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path ); @@ -370,6 +341,11 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) { if ( ! iobuf ) return -ENOMEM; + /* Determine block size */ + blksize = xfer_window ( &tftp->xfer ); + if ( blksize > TFTP_MAX_BLKSIZE ) + blksize = TFTP_MAX_BLKSIZE; + /* Build request */ rrq = iob_put ( iobuf, sizeof ( *rrq ) ); rrq->opcode = htons ( TFTP_RRQ ); @@ -378,8 +354,8 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) { if ( tftp->flags & TFTP_FL_RRQ_SIZES ) { iob_put ( iobuf, snprintf ( iobuf->tail, iob_tailroom ( iobuf ), - "blksize%c%d%ctsize%c0", 0, - tftp_request_blksize, 0, 0 ) + 1 ); + "blksize%c%zd%ctsize%c0", + 0, blksize, 0, 0 ) + 1 ); } if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) { iob_put ( iobuf, snprintf ( iobuf->tail, diff --git a/roms/ipxe/src/net/validator.c b/roms/ipxe/src/net/validator.c index d61cb92f4..74d70e312 100644 --- a/roms/ipxe/src/net/validator.c +++ b/roms/ipxe/src/net/validator.c @@ -121,7 +121,7 @@ static struct interface_descriptor validator_job_desc = */ /** Cross-signed certificate source setting */ -struct setting crosscert_setting __setting ( SETTING_CRYPTO ) = { +const struct setting crosscert_setting __setting ( SETTING_CRYPTO, crosscert )={ .name = "crosscert", .description = "Cross-signed certificate source", .tag = DHCP_EB_CROSS_CERT, @@ -179,7 +179,7 @@ static int validator_append ( struct validator *validator, } cert = x509_last ( certs ); DBGC ( validator, "VALIDATOR %p found certificate %s\n", - validator, cert->subject.name ); + validator, x509_name ( cert ) ); /* Move to next certificate */ asn1_skip_any ( &cursor ); @@ -232,14 +232,7 @@ static int validator_start_download ( struct validator *validator, int rc; /* Determine cross-signed certificate source */ - len = fetch_string_setting_copy ( NULL, &crosscert_setting, - &crosscert_copy ); - if ( len < 0 ) { - rc = len; - DBGC ( validator, "VALIDATOR %p could not fetch crosscert " - "setting: %s\n", validator, strerror ( rc ) ); - goto err_fetch_crosscert; - } + fetch_string_setting_copy ( NULL, &crosscert_setting, &crosscert_copy ); crosscert = ( crosscert_copy ? crosscert_copy : crosscert_default ); /* Allocate URI string */ @@ -279,7 +272,6 @@ static int validator_start_download ( struct validator *validator, free ( uri_string ); err_alloc_uri_string: free ( crosscert_copy ); - err_fetch_crosscert: return rc; } @@ -466,7 +458,7 @@ static void validator_step ( struct validator *validator ) { * previously. */ now = time ( NULL ); - if ( ( rc = x509_validate_chain ( validator->chain, now, + if ( ( rc = x509_validate_chain ( validator->chain, now, NULL, NULL ) ) == 0 ) { validator_finished ( validator, 0 ); return; @@ -485,7 +477,7 @@ static void validator_step ( struct validator *validator ) { /* The issuer is valid, but this certificate is not * yet valid. If OCSP is applicable, start it. */ - if ( cert->extensions.auth_info.ocsp.uri && + if ( cert->extensions.auth_info.ocsp.uri.len && ( ! cert->extensions.auth_info.ocsp.good ) ) { /* Start OCSP */ if ( ( rc = validator_start_ocsp ( validator, cert, diff --git a/roms/ipxe/src/net/vlan.c b/roms/ipxe/src/net/vlan.c index f7281f5d7..b4ddde42d 100644 --- a/roms/ipxe/src/net/vlan.c +++ b/roms/ipxe/src/net/vlan.c @@ -283,6 +283,23 @@ struct net_protocol vlan_protocol __net_protocol = { }; /** + * Get the VLAN tag + * + * @v netdev Network device + * @ret tag VLAN tag, or 0 if device is not a VLAN device + */ +unsigned int vlan_tag ( struct net_device *netdev ) { + struct vlan_device *vlan; + + if ( netdev->op == &vlan_operations ) { + vlan = netdev->priv; + return vlan->tag; + } else { + return 0; + } +} + +/** * Check if network device can be used as a VLAN trunk device * * @v trunk Trunk network device @@ -423,16 +440,6 @@ int vlan_destroy ( struct net_device *netdev ) { } /** - * Do nothing - * - * @v trunk Trunk network device - * @ret rc Return status code - */ -static int vlan_probe ( struct net_device *trunk __unused ) { - return 0; -} - -/** * Handle trunk network device link state change * * @v trunk Trunk network device @@ -488,7 +495,6 @@ static void vlan_remove ( struct net_device *trunk ) { /** VLAN driver */ struct net_driver vlan_driver __net_driver = { .name = "VLAN", - .probe = vlan_probe, .notify = vlan_notify, .remove = vlan_remove, }; diff --git a/roms/ipxe/src/tests/base16_test.c b/roms/ipxe/src/tests/base16_test.c new file mode 100644 index 000000000..9b047b74c --- /dev/null +++ b/roms/ipxe/src/tests/base16_test.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Base16 tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <stdint.h> +#include <string.h> +#include <ipxe/base16.h> +#include <ipxe/test.h> + +/** A Base16 test */ +struct base16_test { + /** Raw data */ + const void *data; + /** Length of raw data */ + size_t len; + /** Base16-encoded data */ + const char *encoded; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define a base16 test */ +#define BASE16( name, DATA, ENCODED ) \ + static const uint8_t name ## _data[] = DATA; \ + static struct base16_test name = { \ + .data = name ## _data, \ + .len = sizeof ( name ## _data ), \ + .encoded = ENCODED, \ + } + +/** Empty data test */ +BASE16 ( empty_test, DATA(), "" ); + +/** "Hello world" test */ +BASE16 ( hw_test, + DATA ( 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ), + "48656c6c6f20776f726c64" ); + +/** Random data test */ +BASE16 ( random_test, + DATA ( 0x8b, 0x1a, 0xa2, 0x6c, 0xa9, 0x38, 0x43, 0xb8, 0x81, 0xf8, + 0x30, 0x44, 0xb2, 0x32, 0x6e, 0x82, 0xfe, 0x0f, 0x84, 0x91 ), + "8b1aa26ca93843b881f83044b2326e82fe0f8491" ); + +/** + * Report a base16 encoding test result + * + * @v test Base16 test + */ +#define base16_encode_ok( test ) do { \ + size_t len = base16_encoded_len ( (test)->len ); \ + char buf[ len + 1 /* NUL */ ]; \ + ok ( len == strlen ( (test)->encoded ) ); \ + base16_encode ( (test)->data, (test)->len, buf ); \ + ok ( strcmp ( (test)->encoded, buf ) == 0 ); \ + } while ( 0 ) + +/** + * Report a base16 decoding test result + * + * @v test Base16 test + */ +#define base16_decode_ok( test ) do { \ + size_t max_len = base16_decoded_max_len ( (test)->encoded ); \ + uint8_t buf[max_len]; \ + int len; \ + len = base16_decode ( (test)->encoded, buf ); \ + ok ( len >= 0 ); \ + ok ( ( size_t ) len <= max_len ); \ + ok ( ( size_t ) len == (test)->len ); \ + ok ( memcmp ( (test)->data, buf, len ) == 0 ); \ + } while ( 0 ) + +/** + * Perform Base16 self-tests + * + */ +static void base16_test_exec ( void ) { + + base16_encode_ok ( &empty_test ); + base16_decode_ok ( &empty_test ); + + base16_encode_ok ( &hw_test ); + base16_decode_ok ( &hw_test ); + + base16_encode_ok ( &random_test ); + base16_decode_ok ( &random_test ); +} + +/** Base16 self-test */ +struct self_test base16_test __self_test = { + .name = "base16", + .exec = base16_test_exec, +}; diff --git a/roms/ipxe/src/tests/cbc_test.c b/roms/ipxe/src/tests/cbc_test.c index ada991b21..cb0f7bdea 100644 --- a/roms/ipxe/src/tests/cbc_test.c +++ b/roms/ipxe/src/tests/cbc_test.c @@ -36,6 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/profile.h> #include "cbc_test.h" +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /** * Test CBC encryption * @@ -115,8 +118,7 @@ static unsigned long cbc_cost ( struct cipher_algorithm *cipher, uint8_t key[key_len]; uint8_t iv[cipher->blocksize]; uint8_t ctx[cipher->ctxsize]; - union profiler profiler; - unsigned long long elapsed; + struct profiler profiler; unsigned long cost; unsigned int i; int rc; @@ -135,13 +137,17 @@ static unsigned long cbc_cost ( struct cipher_algorithm *cipher, assert ( rc == 0 ); cipher_setiv ( cipher, ctx, iv ); - /* Time operation */ - profile ( &profiler ); - op ( cipher, ctx, random, random, sizeof ( random ) ); - elapsed = profile ( &profiler ); + /* Profile cipher operation */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + op ( cipher, ctx, random, random, sizeof ( random ) ); + profile_stop ( &profiler ); + } /* Round to nearest whole number of cycles per byte */ - cost = ( ( elapsed + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) ); + cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) / + sizeof ( random ) ); return cost; } diff --git a/roms/ipxe/src/tests/cms_test.c b/roms/ipxe/src/tests/cms_test.c index 9899b06aa..8767504c0 100644 --- a/roms/ipxe/src/tests/cms_test.c +++ b/roms/ipxe/src/tests/cms_test.c @@ -1305,7 +1305,13 @@ static uint8_t root_crt_fingerprint[] = 0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38, 0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 ); -/** Certificate store containing the iPXE self-test root CA */ +/** Empty certificate store */ +static struct x509_chain empty_store = { + .refcnt = REF_INIT ( ref_no_free ), + .links = LIST_HEAD_INIT ( empty_store.links ), +}; + +/** Root certificate list containing the iPXE self-test root CA */ static struct x509_root test_root = { .digest = &cms_test_algorithm, .count = 1, @@ -1336,11 +1342,17 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ * Report signature parsing test result * * @v sgn Test signature + * @v file Test code file + * @v line Test code line */ -#define cms_signature_ok( sgn ) do { \ - ok ( cms_signature ( (sgn)->data, (sgn)->len, \ - &(sgn)->sig ) == 0 ); \ - } while ( 0 ) +static void cms_signature_okx ( struct cms_test_signature *sgn, + const char *file, unsigned int line ) { + + okx ( cms_signature ( sgn->data, sgn->len, &sgn->sig ) == 0, + file, line ); +} +#define cms_signature_ok( sgn ) \ + cms_signature_okx ( sgn, __FILE__, __LINE__ ) /** * Report signature verification test result @@ -1349,13 +1361,24 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ * @v code Test signed code * @v name Test verification name * @v time Test verification time - * @v root Test root certificate store + * @v store Test certificate store + * @v root Test root certificate list + * @v file Test code file + * @v line Test code line */ -#define cms_verify_ok( sgn, code, name, time, root ) do { \ - x509_invalidate_chain ( (sgn)->sig->certificates ); \ - ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ), \ - (code)->len, name, time, root ) == 0 ); \ - } while ( 0 ) +static void cms_verify_okx ( struct cms_test_signature *sgn, + struct cms_test_code *code, const char *name, + time_t time, struct x509_chain *store, + struct x509_root *root, const char *file, + unsigned int line ) { + + x509_invalidate_chain ( sgn->sig->certificates ); + okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len, + name, time, store, root ) == 0, file, line ); +} +#define cms_verify_ok( sgn, code, name, time, store, root ) \ + cms_verify_okx ( sgn, code, name, time, store, root, \ + __FILE__, __LINE__ ) /** * Report signature verification failure test result @@ -1364,13 +1387,24 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ * @v code Test signed code * @v name Test verification name * @v time Test verification time - * @v root Test root certificate store + * @v store Test certificate store + * @v root Test root certificate list + * @v file Test code file + * @v line Test code line */ -#define cms_verify_fail_ok( sgn, code, name, time, root ) do { \ - x509_invalidate_chain ( (sgn)->sig->certificates ); \ - ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ), \ - (code)->len, name, time, root ) != 0 ); \ - } while ( 0 ) +static void cms_verify_fail_okx ( struct cms_test_signature *sgn, + struct cms_test_code *code, const char *name, + time_t time, struct x509_chain *store, + struct x509_root *root, const char *file, + unsigned int line ) { + + x509_invalidate_chain ( sgn->sig->certificates ); + okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len, + name, time, store, root ) != 0, file, line ); +} +#define cms_verify_fail_ok( sgn, code, name, time, store, root ) \ + cms_verify_fail_okx ( sgn, code, name, time, store, root, \ + __FILE__, __LINE__ ) /** * Perform CMS self-tests @@ -1385,38 +1419,42 @@ static void cms_test_exec ( void ) { cms_signature_ok ( &nonsigned_sig ); /* Check good signature */ + cms_verify_ok ( &codesigned_sig, &test_code, "codesign.test.ipxe.org", + test_time, &empty_store, &test_root ); cms_verify_ok ( &codesigned_sig, &test_code, - "codesign.test.ipxe.org", test_time, &test_root ); - cms_verify_ok ( &codesigned_sig, &test_code, - NULL, test_time, &test_root ); + NULL, test_time, &empty_store, &test_root ); /* Check incorrect signer name */ cms_verify_fail_ok ( &codesigned_sig, &test_code, - "wrongname.test.ipxe.org", test_time, &test_root ); + "wrongname.test.ipxe.org", test_time, + &empty_store, &test_root ); /* Check non-code-signing certificate */ cms_verify_fail_ok ( &genericsigned_sig, &test_code, - NULL, test_time, &test_root ); + NULL, test_time, &empty_store, &test_root ); /* Check non-signing certificate */ cms_verify_fail_ok ( &nonsigned_sig, &test_code, - NULL, test_time, &test_root ); + NULL, test_time, &empty_store, &test_root ); /* Check broken chain */ cms_verify_fail_ok ( &brokenchain_sig, &test_code, - NULL, test_time, &test_root ); + NULL, test_time, &empty_store, &test_root ); /* Check untrusted signature */ cms_verify_fail_ok ( &codesigned_sig, &test_code, - NULL, test_time, &dummy_root ); + NULL, test_time, &empty_store, &dummy_root ); /* Check incorrect signed content */ cms_verify_fail_ok ( &codesigned_sig, &bad_code, - NULL, test_time, &test_root ); + NULL, test_time, &empty_store, &test_root ); /* Check expired signature */ cms_verify_fail_ok ( &codesigned_sig, &test_code, - NULL, test_expired, &test_root ); + NULL, test_expired, &empty_store, &test_root ); + + /* Sanity check */ + assert ( list_empty ( &empty_store.links ) ); /* Drop signature references */ cms_put ( nonsigned_sig.sig ); diff --git a/roms/ipxe/src/tests/deflate_test.c b/roms/ipxe/src/tests/deflate_test.c new file mode 100644 index 000000000..68c1aad96 --- /dev/null +++ b/roms/ipxe/src/tests/deflate_test.c @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * DEFLATE tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <ipxe/deflate.h> +#include <ipxe/test.h> + +/** A DEFLATE test */ +struct deflate_test { + /** Compression format */ + enum deflate_format format; + /** Compressed data */ + const void *compressed; + /** Length of compressed data */ + size_t compressed_len; + /** Expected uncompressed data */ + const void *expected; + /** Length of expected uncompressed data */ + size_t expected_len; +}; + +/** A DEFLATE fragment list */ +struct deflate_test_fragments { + /** Fragment lengths */ + size_t len[8]; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define a DEFLATE test */ +#define DEFLATE( name, FORMAT, COMPRESSED, EXPECTED ) \ + static const uint8_t name ## _compressed[] = COMPRESSED; \ + static const uint8_t name ## _expected[] = EXPECTED; \ + static struct deflate_test name = { \ + .format = FORMAT, \ + .compressed = name ## _compressed, \ + .compressed_len = sizeof ( name ## _compressed ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ + }; + +/* Empty file, no compression */ +DEFLATE ( empty_literal, DEFLATE_RAW, + DATA ( 0x01, 0x00, 0x00, 0xff, 0xff ), DATA() ); + +/* "iPXE" string, no compression */ +DEFLATE ( literal, DEFLATE_RAW, + DATA ( 0x01, 0x04, 0x00, 0xfb, 0xff, 0x69, 0x50, 0x58, 0x45 ), + DATA ( 0x69, 0x50, 0x58, 0x45 ) ); + +/* "iPXE" string, no compression, split into two literals */ +DEFLATE ( split_literal, DEFLATE_RAW, + DATA ( 0x00, 0x02, 0x00, 0xfd, 0xff, 0x69, 0x50, 0x01, 0x02, 0x00, + 0xfd, 0xff, 0x58, 0x45 ), + DATA ( 0x69, 0x50, 0x58, 0x45 ) ); + +/* Empty file */ +DEFLATE ( empty, DEFLATE_RAW, DATA ( 0x03, 0x00 ), DATA() ); + +/* "Hello world" */ +DEFLATE ( hello_world, DEFLATE_RAW, + DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, + 0x49, 0x01, 0x00 ), + DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64 ) ); + +/* "Hello hello world" */ +DEFLATE ( hello_hello_world, DEFLATE_RAW, + DATA ( 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0xc8, 0x00, 0x93, 0xe5, + 0xf9, 0x45, 0x39, 0x29, 0x00 ), + DATA ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x68, 0x65, 0x6c, 0x6c, + 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 ) ); + +/* "This specification defines a lossless compressed data format" */ +DEFLATE ( rfc_sentence, DEFLATE_RAW, + DATA ( 0x0d, 0xc6, 0xdb, 0x09, 0x00, 0x21, 0x0c, 0x04, 0xc0, 0x56, + 0xb6, 0x28, 0x1b, 0x08, 0x79, 0x70, 0x01, 0x35, 0xe2, 0xa6, + 0x7f, 0xce, 0xf9, 0x9a, 0xf1, 0x25, 0xc1, 0xe3, 0x9a, 0x91, + 0x2a, 0x9d, 0xb5, 0x61, 0x1e, 0xb9, 0x9d, 0x10, 0xcc, 0x22, + 0xa7, 0x93, 0xd0, 0x5a, 0xe7, 0xbe, 0xb8, 0xc1, 0xa4, 0x05, + 0x51, 0x77, 0x49, 0xff ), + DATA ( 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x61, 0x20, 0x6c, + 0x6f, 0x73, 0x73, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x63, 0x6f, + 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x64, + 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74 ) ); + +/* "ZLIB Compressed Data Format Specification" */ +DEFLATE ( zlib, DEFLATE_ZLIB, + DATA ( 0x78, 0x01, 0x8b, 0xf2, 0xf1, 0x74, 0x52, 0x70, 0xce, 0xcf, + 0x2d, 0x28, 0x4a, 0x2d, 0x2e, 0x4e, 0x4d, 0x51, 0x70, 0x49, + 0x2c, 0x49, 0x54, 0x70, 0xcb, 0x2f, 0xca, 0x4d, 0x2c, 0x51, + 0x08, 0x2e, 0x48, 0x4d, 0xce, 0x4c, 0xcb, 0x4c, 0x4e, 0x2c, + 0xc9, 0xcc, 0xcf, 0x03, 0x00, 0x2c, 0x0e, 0x0e, 0xeb ), + DATA ( 0x5a, 0x4c, 0x49, 0x42, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x44, 0x61, 0x74, 0x61, + 0x20, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x53, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e ) ); + +/* "ZLIB Compressed Data Format Specification" fragment list */ +static struct deflate_test_fragments zlib_fragments[] = { + { { -1UL, } }, + { { 0, 1, 5, -1UL, } }, + { { 0, 0, 1, 0, 0, 1, -1UL } }, + { { 10, 8, 4, 7, 11, -1UL } }, + { { 45, -1UL } }, + { { 48, -1UL } }, +}; + +/** + * Report DEFLATE test result + * + * @v deflate Decompressor + * @v test Deflate test + * @v frags Fragment list, or NULL + * @v file Test code file + * @v line Test code line + */ +static void deflate_okx ( struct deflate *deflate, + struct deflate_test *test, + struct deflate_test_fragments *frags, + const char *file, unsigned int line ) { + uint8_t data[ test->expected_len ]; + struct deflate_chunk in; + struct deflate_chunk out; + size_t frag_len = -1UL; + size_t offset = 0; + size_t remaining = test->compressed_len; + unsigned int i; + + /* Initialise decompressor */ + deflate_init ( deflate, test->format ); + + /* Initialise output chunk */ + deflate_chunk_init ( &out, virt_to_user ( data ), 0, sizeof ( data ) ); + + /* Process input (in fragments, if applicable) */ + for ( i = 0 ; i < ( sizeof ( frags->len ) / + sizeof ( frags->len[0] ) ) ; i++ ) { + + /* Initialise input chunk */ + if ( frags ) + frag_len = frags->len[i]; + if ( frag_len > remaining ) + frag_len = remaining; + deflate_chunk_init ( &in, virt_to_user ( test->compressed ), + offset, ( offset + frag_len ) ); + + /* Decompress this fragment */ + okx ( deflate_inflate ( deflate, &in, &out ) == 0, file, line ); + okx ( in.len == ( offset + frag_len ), file, line ); + okx ( in.offset == in.len, file, line ); + + /* Move to next fragment */ + offset = in.offset; + remaining -= frag_len; + if ( ! remaining ) + break; + + /* Check that decompression has not terminated early */ + okx ( ! deflate_finished ( deflate ), file, line ); + } + + /* Check decompression has terminated as expected */ + okx ( deflate_finished ( deflate ), file, line ); + okx ( offset == test->compressed_len, file, line ); + okx ( out.offset == test->expected_len, file, line ); + okx ( memcmp ( data, test->expected, test->expected_len ) == 0, + file, line ); +} +#define deflate_ok( deflate, test, frags ) \ + deflate_okx ( deflate, test, frags, __FILE__, __LINE__ ) + +/** + * Perform DEFLATE self-test + * + */ +static void deflate_test_exec ( void ) { + struct deflate *deflate; + unsigned int i; + + /* Allocate shared structure */ + deflate = malloc ( sizeof ( *deflate ) ); + ok ( deflate != NULL ); + + /* Perform self-tests */ + if ( deflate ) { + + /* Test as a single pass */ + deflate_ok ( deflate, &empty_literal, NULL ); + deflate_ok ( deflate, &literal, NULL ); + deflate_ok ( deflate, &split_literal, NULL ); + deflate_ok ( deflate, &empty, NULL ); + deflate_ok ( deflate, &hello_world, NULL ); + deflate_ok ( deflate, &hello_hello_world, NULL ); + deflate_ok ( deflate, &rfc_sentence, NULL ); + deflate_ok ( deflate, &zlib, NULL ); + + /* Test fragmentation */ + for ( i = 0 ; i < ( sizeof ( zlib_fragments ) / + sizeof ( zlib_fragments[0] ) ) ; i++ ) { + deflate_ok ( deflate, &zlib, &zlib_fragments[i] ); + } + } + + /* Free shared structure */ + free ( deflate ); +} + +/** DEFLATE self-test */ +struct self_test deflate_test __self_test = { + .name = "deflate", + .exec = deflate_test_exec, +}; diff --git a/roms/ipxe/src/tests/digest_test.c b/roms/ipxe/src/tests/digest_test.c index 6428cc728..4df26c099 100644 --- a/roms/ipxe/src/tests/digest_test.c +++ b/roms/ipxe/src/tests/digest_test.c @@ -25,12 +25,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Forcibly enable assertions */ +#undef NDEBUG + #include <stdlib.h> #include <string.h> #include <ipxe/crypto.h> #include <ipxe/profile.h> #include "digest_test.h" +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /** * Test digest algorithm * @@ -81,8 +87,7 @@ unsigned long digest_cost ( struct digest_algorithm *digest ) { static uint8_t random[8192]; /* Too large for stack */ uint8_t ctx[digest->ctxsize]; uint8_t out[digest->digestsize]; - union profiler profiler; - unsigned long long elapsed; + struct profiler profiler; unsigned long cost; unsigned int i; @@ -91,15 +96,19 @@ unsigned long digest_cost ( struct digest_algorithm *digest ) { for ( i = 0 ; i < sizeof ( random ) ; i++ ) random[i] = rand(); - /* Time digest calculation */ - profile ( &profiler ); - digest_init ( digest, ctx ); - digest_update ( digest, ctx, random, sizeof ( random ) ); - digest_final ( digest, ctx, out ); - elapsed = profile ( &profiler ); + /* Profile digest calculation */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + digest_init ( digest, ctx ); + digest_update ( digest, ctx, random, sizeof ( random ) ); + digest_final ( digest, ctx, out ); + profile_stop ( &profiler ); + } /* Round to nearest whole number of cycles per byte */ - cost = ( ( elapsed + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) ); + cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) / + sizeof ( random ) ); return cost; } diff --git a/roms/ipxe/src/tests/dns_test.c b/roms/ipxe/src/tests/dns_test.c new file mode 100644 index 000000000..52f5f19f2 --- /dev/null +++ b/roms/ipxe/src/tests/dns_test.c @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * DNS self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <assert.h> +#include <ipxe/dns.h> +#include <ipxe/test.h> + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** A DNS encoding test */ +struct dns_encode_test { + /** String */ + const char *string; + /** Encoded string */ + const void *data; + /** Length of encoded string */ + int len; +}; + +/** + * Define a DNS encoding test + * + * @v _name Test name + * @v _string Test string + * @v _data Expected encoded data + * @ret test DNS encoding test + */ +#define DNS_ENCODE( _name, _string, _data ) \ + static const uint8_t _name ## __data[] = _data; \ + static struct dns_encode_test _name = { \ + .string = _string, \ + .data = _name ## __data, \ + .len = sizeof ( _name ## __data ), \ + } + +/** + * Report DNS encoding test result + * + * @v test DNS encoding test + * @v file Test code file + * @v line Test code line + */ +static void dns_encode_okx ( struct dns_encode_test *test, const char *file, + unsigned int line ) { + uint8_t data[ test->len ]; + struct dns_name name; + int len; + + /* Check ability to determine length with no buffer */ + memset ( &name, 0, sizeof ( name ) ); + len = dns_encode ( test->string, &name ); + okx ( len >= 0, file, line ); + okx ( len == test->len, file, line ); + + /* Check encoded name */ + name.data = data; + name.len = sizeof ( data ); + len = dns_encode ( test->string, &name ); + okx ( len >= 0, file, line ); + if ( len >= 0 ) { + okx ( len == test->len, file, line ); + okx ( memcmp ( data, test->data, test->len ) == 0, file, line ); + DBGC ( test, "DNS encoded \"%s\" to:\n", test->string ); + DBGC_HDA ( test, 0, data, len ); + } +} +#define dns_encode_ok( test ) dns_encode_okx ( test, __FILE__, __LINE__ ) + +/** + * Report DNS encoding failure test result + * + * @v test DNS encoding test + * @v file Test code file + * @v line Test code line + */ +static void dns_encode_fail_okx ( struct dns_encode_test *test, + const char *file, unsigned int line ) { + struct dns_name name = { .data = NULL, .len = 0 }; + int len; + + len = dns_encode ( test->string, &name ); + okx ( len < 0, file, line ); +} +#define dns_encode_fail_ok( test ) \ + dns_encode_fail_okx ( test, __FILE__, __LINE__ ) + +/** A DNS decoding test */ +struct dns_decode_test { + /** Name */ + struct dns_name name; + /** Expected string */ + const char *string; +}; + +/** + * Define a DNS decoding test + * + * @v _name Test name + * @v _data RFC1035-encoded data + * @v _offset Starting offset within encoded data + * @v _string Expected decoded string + * @ret test DNS decoding test + */ +#define DNS_DECODE( _name, _data, _offset, _string ) \ + static uint8_t _name ## __data[] = _data; \ + static struct dns_decode_test _name = { \ + .name = { \ + .data = _name ## __data, \ + .offset = _offset, \ + .len = sizeof ( _name ## __data ), \ + }, \ + .string = _string, \ + } + +/** + * Report DNS decoding test result + * + * @v test DNS decoding test + * @v file Test code file + * @v line Test code line + */ +static void dns_decode_okx ( struct dns_decode_test *test, const char *file, + unsigned int line ) { + char string[ strlen ( test->string ) + 1 /* NUL */ ]; + int len; + + /* Check ability to determine length with no buffer */ + len = dns_decode ( &test->name, NULL, 0 ); + okx ( len >= 0, file, line ); + okx ( len == ( ( int ) strlen ( test->string ) ), file, line ); + + /* Check decoded string */ + len = dns_decode ( &test->name, string, sizeof ( string ) ); + okx ( len >= 0, file, line ); + if ( len >= 0 ) { + okx ( strcmp ( string, test->string ) == 0, file, line ); + DBGC ( test, "DNS decoded \"%s\" from offset %#zx in:\n", + string, test->name.offset ); + DBGC_HDA ( test, 0, test->name.data, test->name.len ); + } +} +#define dns_decode_ok( test ) dns_decode_okx ( test, __FILE__, __LINE__ ) + +/** + * Report DNS decoding failure test result + * + * @v test DNS decoding test + * @v file Test code file + * @v line Test code line + */ +static void dns_decode_fail_okx ( struct dns_decode_test *test, + const char *file, unsigned int line ) { + int len; + + len = dns_decode ( &test->name, NULL, 0 ); + okx ( len < 0, file, line ); +} +#define dns_decode_fail_ok( test ) \ + dns_decode_fail_okx ( test, __FILE__, __LINE__ ) + +/** A DNS comparison test */ +struct dns_compare_test { + /** First name */ + struct dns_name first; + /** Second name */ + struct dns_name second; +}; + +/** + * Define a DNS comparison test + * + * @v _name Test name + * @v _first_data First RFC1035-encoded data + * @v _first_offset Starting offset within first encoded data + * @v _second_data Second RFC1035-encoded data + * @v _second_offset Starting offset within second encoded data + * @ret test DNS comparison test + */ +#define DNS_COMPARE( _name, _first_data, _first_offset, _second_data, \ + _second_offset ) \ + static uint8_t _name ## __first_data[] = _first_data; \ + static uint8_t _name ## __second_data[] = _second_data; \ + static struct dns_compare_test _name = { \ + .first = { \ + .data = _name ## __first_data, \ + .offset = _first_offset, \ + .len = sizeof ( _name ## __first_data ), \ + }, \ + .second = { \ + .data = _name ## __second_data, \ + .offset = _second_offset, \ + .len = sizeof ( _name ## __second_data ), \ + }, \ + } + +/** + * Report DNS comparison test result + * + * @v test DNS comparison test + * @v file Test code file + * @v line Test code line + */ +static void dns_compare_okx ( struct dns_compare_test *test, const char *file, + unsigned int line ) { + + okx ( dns_compare ( &test->first, &test->second ) == 0, file, line ); +} +#define dns_compare_ok( test ) dns_compare_okx ( test, __FILE__, __LINE__ ) + +/** + * Report DNS comparison test failure result + * + * @v test DNS comparison test + * @v file Test code file + * @v line Test code line + */ +static void dns_compare_fail_okx ( struct dns_compare_test *test, + const char *file, unsigned int line ) { + + okx ( dns_compare ( &test->first, &test->second ) != 0, file, line ); +} +#define dns_compare_fail_ok( test ) \ + dns_compare_fail_okx ( test, __FILE__, __LINE__ ) + +/** A DNS copying test */ +struct dns_copy_test { + /** Source name */ + struct dns_name src; + /** Expected copied name */ + struct dns_name dst; +}; + +/** + * Define a DNS copying test + * + * @v _name Test name + * @v _src_data Source RFC1035-encoded data + * @v _src_offset Starting offset within source encoded data + * @v _dst_data Expected copied RFC1035-encoded data + * @v _dst_offset Starting offset withint copied encoded data + * @ret test DNS copying test + */ +#define DNS_COPY( _name, _src_data, _src_offset, _dst_data, \ + _dst_offset ) \ + static uint8_t _name ## __src_data[] = _src_data; \ + static uint8_t _name ## __dst_data[] = _dst_data; \ + static struct dns_copy_test _name = { \ + .src = { \ + .data = _name ## __src_data, \ + .offset = _src_offset, \ + .len = sizeof ( _name ## __src_data ), \ + }, \ + .dst = { \ + .data = _name ## __dst_data, \ + .offset = _dst_offset, \ + .len = sizeof ( _name ## __dst_data ), \ + }, \ + } + +/** + * Report a DNS copying test result + * + * @v test DNS copying test + * @v file Test code file + * @v line Test code line + */ +static void dns_copy_okx ( struct dns_copy_test *test, + const char *file, unsigned int line ) { + uint8_t data[ test->dst.len ]; + struct dns_name dst; + int len; + + /* Check ability to determine length with no buffer */ + memset ( &dst, 0, sizeof ( dst ) ); + len = dns_copy ( &test->src, &dst ); + okx ( len >= 0, file, line ); + okx ( len == ( ( int ) ( test->dst.len - test->dst.offset ) ), + file, line ); + + /* Check copied name */ + dst.data = data; + dst.offset = test->dst.offset; + dst.len = sizeof ( data ); + memcpy ( dst.data, test->dst.data, test->dst.offset ); + len = dns_copy ( &test->src, &dst ); + okx ( len >= 0, file, line ); + okx ( len == ( ( int ) ( test->dst.len - test->dst.offset ) ), + file, line ); + okx ( memcmp ( data, test->dst.data, sizeof ( data ) ) == 0, + file, line ); + DBGC ( test, "DNS copied:\n" ); + DBGC_HDA ( test, 0, test->src.data, test->src.len ); + DBGC_HDA ( test, 0, data, ( test->dst.offset + len ) ); +} +#define dns_copy_ok( test ) dns_copy_okx ( test, __FILE__, __LINE__ ) + +/** + * Report a DNS copying failure test result + * + * @v test DNS copying test + * @v file Test code file + * @v line Test code line + */ +static void dns_copy_fail_okx ( struct dns_copy_test *test, + const char *file, unsigned int line ) { + struct dns_name dst; + int len; + + memset ( &dst, 0, sizeof ( dst ) ); + len = dns_copy ( &test->src, &dst ); + okx ( len < 0, file, line ); +} +#define dns_copy_fail_ok( test ) dns_copy_fail_okx ( test, __FILE__, __LINE__ ) + +/** A DNS search list test */ +struct dns_list_test { + /** Search list */ + struct dns_name list; + /** Expected decoded search list */ + const char **strings; + /** Number of expected decoded string */ + unsigned int count; +}; + +/** + * Define a DNS search list test + * + * @v _name Test name + * @v _list RFC1035-encoded data + * @v _strings Expected decoded strings + * @ret test DNS search list test + */ +#define DNS_LIST( _name, _list, _strings ) \ + static uint8_t _name ## __list[] = _list; \ + static const char * _name ## __strings[] = _strings; \ + static struct dns_list_test _name = { \ + .list = { \ + .data = _name ## __list, \ + .offset = 0, \ + .len = sizeof ( _name ## __list ), \ + }, \ + .strings = _name ## __strings, \ + .count = ( sizeof ( _name ## __strings ) / \ + sizeof ( _name ## __strings[0] ) ), \ + } + +/** + * Report DNS search list test result + * + * @v test DNS search list test + * @v file Test code file + * @v line Test code line + */ +static void dns_list_okx ( struct dns_list_test *test, const char *file, + unsigned int line ) { + struct dns_name name; + unsigned int i; + + DBGC ( test, "DNS search list:\n" ); + DBGC_HDA ( test, 0, test->list.data, test->list.len ); + memcpy ( &name, &test->list, sizeof ( name ) ); + for ( i = 0 ; i < test->count ; i++ ) { + char buf[ strlen ( test->strings[i] ) + 1 /* NUL */ ]; + int len; + int offset; + + /* Decode this name */ + len = dns_decode ( &name, buf, sizeof ( buf ) ); + okx ( len >= 0, file, line ); + if ( len >= 0 ) { + okx ( len == ( ( int ) strlen ( test->strings[i] ) ), + file, line ); + okx ( strcmp ( buf, test->strings[i] ) == 0, + file, line ); + DBGC ( test, "DNS search list found \"%s\" at offset " + "%#zx\n", buf, name.offset ); + } + + /* Skip to next name */ + offset = dns_skip ( &name ); + okx ( offset >= 0, file, line ); + name.offset = offset; + } + + /* Check that we have consumed the whole search list */ + okx ( name.offset == name.len, file, line ); +} +#define dns_list_ok( test ) dns_list_okx ( test, __FILE__, __LINE__ ) + +/* Simple encoding test */ +DNS_ENCODE ( encode_simple, "ipxe.org", + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ) ); + +/* Single-word encoding test */ +DNS_ENCODE ( encode_single, "foo", DATA ( 3, 'f', 'o', 'o', 0 ) ); + +/* Absolute encoding test */ +DNS_ENCODE ( encode_absolute, "git.ipxe.org.", + DATA ( 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', + 0 ) ); + +/* Empty string encoding test */ +DNS_ENCODE ( encode_empty, "", DATA ( 0 ) ); + +/* Root domain encoding test */ +DNS_ENCODE ( encode_root, ".", DATA ( 0 ) ); + +/* Invalid initial dot encoding test */ +DNS_ENCODE ( encode_initial_dot, ".foo", DATA() ); + +/* Invalid double dot encoding test */ +DNS_ENCODE ( encode_double_dot, "ipxe..org", DATA() ); + +/* Invalid solo double dot encoding test */ +DNS_ENCODE ( encode_solo_double_dot, "..", DATA() ); + +/* Invalid trailing double dot encoding test */ +DNS_ENCODE ( encode_trailing_double_dot, "ipxe.org..", DATA() ); + +/* Invalid overlength label encoding test */ +DNS_ENCODE ( encode_overlength, + "this-label-is-maliciously-long-in-an-attempt-to-overflow-the-" + "length-field-and-generate-a-length-which-looks-like-a-" + "compression-pointer", DATA() ); + +/* Simple decoding test */ +DNS_DECODE ( decode_simple, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + "ipxe.org" ); + +/* Compression pointer decoding test */ +DNS_DECODE ( decode_ptr, + DATA ( 3, 'o', 'r', 'g', 0, 3, 'g', 'i', 't', 4, 'i', 'p', 'x', + 'e', 0xc0, 0x00 ), 5, + "git.ipxe.org" ); + +/* Root decoding test */ +DNS_DECODE ( decode_root, + DATA ( 0 ), 0, "" ); + +/* Incomplete name decoding test */ +DNS_DECODE ( decode_incomplete_name, + DATA ( 4, 'i', 'p', 'x', 'e' ), 0, NULL ); + +/* Incomplete label decoding test */ +DNS_DECODE ( decode_incomplete_label, + DATA ( 4, 'i', 'p', 'x' ), 0, NULL ); + +/* Incomplete compression pointer decoding test */ +DNS_DECODE ( decode_incomplete_ptr, + DATA ( 3, 'o', 'r', 'g', 0, 4, 'i', 'p', 'x', 'e', 0xc0 ), 5, + NULL ); + +/* Forward reference decoding test */ +DNS_DECODE ( decode_forward, + DATA ( 0xc0, 0x02, 3, 'f', 'o', 'o', 0 ), 0, NULL ); + +/* Infinite loop decoding test */ +DNS_DECODE ( decode_infinite, + DATA ( 4, 'i', 'p', 'x', 'e', 0xc0, 0x00 ), 0, NULL ); + +/* Empty decoding test */ +DNS_DECODE ( decode_empty, + DATA (), 0, NULL ); + +/* Simple comparison test */ +DNS_COMPARE ( compare_simple, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 ); + +/* Compression pointer comparison test */ +DNS_COMPARE ( compare_ptr, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + DATA ( 3, 'o', 'r', 'g', 0, 4, 'i', 'p', 'x', 'e', + 0xc0, 0x00 ), 5 ); + +/* Case insensitive comparison test */ +DNS_COMPARE ( compare_case, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'O', 'R', 'G', 0 ), 0 ); + +/* Mismatch comparison test */ +DNS_COMPARE ( compare_mismatch, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + DATA ( 4, 'g', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 ); + +/* Infinite loop comparison test */ +DNS_COMPARE ( compare_infinite, + DATA ( 3, 'f', 'o', 'o', 0xc0, 0x00 ), 0, + DATA ( 3, 'f', 'o', 'o', 0xc0, 0x00 ), 0 ); + +/* Simple copying test */ +DNS_COPY ( copy_simple, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 ); + +/* Simple copying test with offset */ +DNS_COPY ( copy_offset, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0, + DATA ( 'f', 'o', 'o', 0, 4, 'i', 'p', 'x', 'e', + 3, 'o', 'r', 'g', 0 ), 4 ); + +/* Compression pointer copying test */ +DNS_COPY ( copy_ptr, + DATA ( 3, 'o', 'r', 'g', 0, 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', + 0xc0, 0x00 ), 5, + DATA ( 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', + 0 ), 0 ); + +/* Infinite loop copying test */ +DNS_COPY ( copy_infinite, + DATA ( 4, 'l', 'o', 'o', 'p', 7, 'f', 'o', 'r', 'e', 'v', 'e', 'r', + 0xc0, 0x05 ), 0, + DATA (), 0 ); + +/* DNS search list test */ +DNS_LIST ( search, + DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0, + 4, 'b', 'o', 'o', 't', 0xc0, 0x00, + 3, 'd', 'e', 'v', 0xc0, 0x0a, + 11, 'n', 'e', 't', 'w', 'o', 'r', 'k', 'b', 'o', 'o', 't', + 0xc0, 0x05 ), + DATA ( "ipxe.org", "boot.ipxe.org", "dev.boot.ipxe.org", + "networkboot.org" ) ); + +/** + * Perform DNS self-test + * + */ +static void dns_test_exec ( void ) { + + /* Encoding tests */ + dns_encode_ok ( &encode_simple ); + dns_encode_ok ( &encode_single ); + dns_encode_ok ( &encode_absolute ); + dns_encode_ok ( &encode_empty ); + dns_encode_ok ( &encode_root ); + dns_encode_fail_ok ( &encode_initial_dot ); + dns_encode_fail_ok ( &encode_double_dot ); + dns_encode_fail_ok ( &encode_solo_double_dot ); + dns_encode_fail_ok ( &encode_trailing_double_dot ); + dns_encode_fail_ok ( &encode_overlength ); + + /* Decoding tests */ + dns_decode_ok ( &decode_simple ); + dns_decode_ok ( &decode_ptr ); + dns_decode_ok ( &decode_root ); + dns_decode_fail_ok ( &decode_incomplete_name ); + dns_decode_fail_ok ( &decode_incomplete_label ); + dns_decode_fail_ok ( &decode_incomplete_ptr ); + dns_decode_fail_ok ( &decode_forward ); + dns_decode_fail_ok ( &decode_infinite ); + dns_decode_fail_ok ( &decode_empty ); + + /* Comparison tests */ + dns_compare_ok ( &compare_simple ); + dns_compare_ok ( &compare_ptr ); + dns_compare_ok ( &compare_case ); + dns_compare_fail_ok ( &compare_mismatch ); + dns_compare_fail_ok ( &compare_infinite ); + + /* Copying tests */ + dns_copy_ok ( ©_simple ); + dns_copy_ok ( ©_offset ); + dns_copy_ok ( ©_ptr ); + dns_copy_fail_ok ( ©_infinite ); + + /* Search list tets */ + dns_list_ok ( &search ); +} + +/** DNS self-test */ +struct self_test dns_test __self_test = { + .name = "dns", + .exec = dns_test_exec, +}; diff --git a/roms/ipxe/src/tests/ipv6_test.c b/roms/ipxe/src/tests/ipv6_test.c new file mode 100644 index 000000000..4de310ab0 --- /dev/null +++ b/roms/ipxe/src/tests/ipv6_test.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * IPv6 tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <stdint.h> +#include <string.h> +#include <byteswap.h> +#include <ipxe/ipv6.h> +#include <ipxe/test.h> + +/** Define inline IPv6 address */ +#define IPV6(...) { __VA_ARGS__ } + +/** + * Report an inet6_ntoa() test result + * + * @v addr IPv6 address + * @v text Expected textual representation + */ +#define inet6_ntoa_ok( addr, text ) do { \ + static const struct in6_addr in = { \ + .s6_addr = addr, \ + }; \ + static const char expected[] = text; \ + char *actual; \ + \ + actual = inet6_ntoa ( &in ); \ + DBG ( "inet6_ntoa ( %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ) " \ + "= %s\n", ntohs ( in.s6_addr16[0] ), \ + ntohs ( in.s6_addr16[1] ), ntohs ( in.s6_addr16[2] ), \ + ntohs ( in.s6_addr16[3] ), ntohs ( in.s6_addr16[4] ), \ + ntohs ( in.s6_addr16[5] ), ntohs ( in.s6_addr16[6] ), \ + ntohs ( in.s6_addr16[7] ), actual ); \ + ok ( strcmp ( actual, expected ) == 0 ); \ + } while ( 0 ) + +/** + * Report an inet6_aton() test result + * + * @v text Textual representation + * @v addr Expected IPv6 address + */ +#define inet6_aton_ok( text, addr ) do { \ + static const char string[] = text; \ + static const struct in6_addr expected = { \ + .s6_addr = addr, \ + }; \ + struct in6_addr actual; \ + \ + ok ( inet6_aton ( string, &actual ) == 0 ); \ + DBG ( "inet6_aton ( \"%s\" ) = %s\n", string, \ + inet6_ntoa ( &actual ) ); \ + ok ( memcmp ( &actual, &expected, sizeof ( actual ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report an inet6_aton() failure test result + * + * @v text Textual representation + */ +#define inet6_aton_fail_ok( text ) do { \ + static const char string[] = text; \ + struct in6_addr dummy; \ + \ + ok ( inet6_aton ( string, &dummy ) != 0 ); \ + } while ( 0 ) + +/** + * Perform IPv6 self-tests + * + */ +static void ipv6_test_exec ( void ) { + + /* inet6_ntoa() tests */ + inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, + 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45 ), + "2001:ba8:0:1d4::6950:5845" ); + /* No zeros */ + inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01 ), + "2001:db8:1:1:1:1:1:1" ); + /* Run of zeros */ + inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + "2001:db8::1" ); + /* No "::" for single zero */ + inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01 ), + "2001:db8:0:1:1:1:1:1" ); + /* Use "::" for longest run of zeros */ + inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + "2001:0:0:1::1" ); + /* Use "::" for leftmost equal-length run of zeros */ + inet6_ntoa_ok ( IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + "2001:db8::1:0:0:1" ); + /* Trailing run of zeros */ + inet6_ntoa_ok ( IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + "fe80::" ); + /* Leading run of zeros */ + inet6_ntoa_ok ( IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + "::1" ); + /* All zeros */ + inet6_ntoa_ok ( IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + "::" ); + /* Maximum length */ + inet6_ntoa_ok ( IPV6 ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" ); + + /* inet6_aton() tests */ + inet6_aton_ok ( "2001:ba8:0:1d4::6950:5845", + IPV6 ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, + 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45)); + /* No zeros */ + inet6_aton_ok ( "2001:db8:1:1:1:1:1:1", + IPV6 ( 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01)); + /* All intervening zeros */ + inet6_aton_ok ( "fe80::1", + IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); + /* Trailing run of zeros */ + inet6_aton_ok ( "fe80::", + IPV6 ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); + /* Leading run of zeros */ + inet6_aton_ok ( "::1", + IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)); + /* All zeros */ + inet6_aton_ok ( "::", + IPV6 ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)); + + /* inet6_aton() failure tests */ + inet6_aton_fail_ok ( "20012:ba8:0:1d4::6950:5845" ); + inet6_aton_fail_ok ( "200z:ba8:0:1d4::6950:5845" ); + inet6_aton_fail_ok ( "2001.ba8:0:1d4::6950:5845" ); + inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1" ); + inet6_aton_fail_ok ( "2001:db8:1:1:1:1:1:1:2" ); + inet6_aton_fail_ok ( "2001:db8::1::2" ); + inet6_aton_fail_ok ( "2001:ba8:0:1d4:::6950:5845" ); + inet6_aton_fail_ok ( ":::" ); +} + +/** IPv6 self-test */ +struct self_test ipv6_test __self_test = { + .name = "ipv6", + .exec = ipv6_test_exec, +}; diff --git a/roms/ipxe/src/tests/math_test.c b/roms/ipxe/src/tests/math_test.c new file mode 100644 index 000000000..e12b7939d --- /dev/null +++ b/roms/ipxe/src/tests/math_test.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Mathematical self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <strings.h> +#include <assert.h> +#include <ipxe/test.h> +#include <ipxe/isqrt.h> + +/** + * Force a call to the non-constant implementation of flsl() + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +__attribute__ (( noinline )) int flsl_var ( long value ) { + return flsl ( value ); +} + +/** + * Force a call to the non-constant implementation of flsll() + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +__attribute__ (( noinline )) int flsll_var ( long long value ) { + return flsll ( value ); +} + +/** + * Check current stack pointer + * + * @ret stack A value at a fixed offset from the current stack pointer + * + * Used by check_divmod() + */ +static __attribute__ (( noinline )) void * stack_check ( void ) { + int a; + void *ret; + + /* Hide the fact that we are returning the address of a local + * variable, to prevent a compiler warning. + */ + __asm__ ( "\n" : "=g" ( ret ) : "0" ( &a ) ); + + return ret; +} + +/** + * Check division/modulus operation + * + * One aspect of the calling convention for the implicit arithmetic + * functions (__udivmoddi4() etc) is whether the caller or the callee + * is expected to pop any stack-based arguments. This distinction can + * be masked if the compiler chooses to uses a frame pointer in the + * caller, since the caller will then reload the stack pointer from + * the frame pointer and so can mask an error in the value of the + * stack pointer. + * + * We run the division operation in a loop, and check that the stack + * pointer does not change value on the second iteration. To prevent + * the compiler from performing various optimisations which might + * invalidate our intended test (such as unrolling the loop, or moving + * the division operation outside the loop), we include some dummy + * inline assembly code. + */ +#define check_divmod( dividend, divisor, OP ) ( { \ + uint64_t result; \ + int count = 2; \ + void *check = NULL; \ + \ + /* Prevent compiler from unrolling the loop */ \ + __asm__ ( "\n" : "=g" ( count ) : "0" ( count ) ); \ + \ + do { \ + /* Check that stack pointer does not change between \ + * loop iterations. \ + */ \ + if ( check ) { \ + assert ( check == stack_check() ); \ + } else { \ + check = stack_check(); \ + } \ + \ + /* Perform division, preventing the compiler from \ + * moving the division out of the loop. \ + */ \ + __asm__ ( "\n" : "=g" ( dividend ), "=g" ( divisor ) \ + : "0" ( dividend ), "1" ( divisor ) ); \ + result = ( dividend OP divisor ); \ + __asm__ ( "\n" : "=g" ( result ) : "0" ( result ) ); \ + \ + } while ( --count ); \ + result; } ) + +/** + * Force a use of runtime 64-bit unsigned integer division + * + * @v dividend Dividend + * @v divisor Divisor + * @ret quotient Quotient + */ +__attribute__ (( noinline )) uint64_t u64div_var ( uint64_t dividend, + uint64_t divisor ) { + + return check_divmod ( dividend, divisor, / ); +} + +/** + * Force a use of runtime 64-bit unsigned integer modulus + * + * @v dividend Dividend + * @v divisor Divisor + * @ret remainder Remainder + */ +__attribute__ (( noinline )) uint64_t u64mod_var ( uint64_t dividend, + uint64_t divisor ) { + + return check_divmod ( dividend, divisor, % ); +} + +/** + * Force a use of runtime 64-bit signed integer division + * + * @v dividend Dividend + * @v divisor Divisor + * @ret quotient Quotient + */ +__attribute__ (( noinline )) int64_t s64div_var ( int64_t dividend, + int64_t divisor ) { + + return check_divmod ( dividend, divisor, / ); +} + +/** + * Force a use of runtime 64-bit unsigned integer modulus + * + * @v dividend Dividend + * @v divisor Divisor + * @ret remainder Remainder + */ +__attribute__ (( noinline )) int64_t s64mod_var ( int64_t dividend, + int64_t divisor ) { + + return check_divmod ( dividend, divisor, % ); +} + +/** + * Report a flsl() test result + * + * @v value Value + * @v msb Expected MSB + * @v file Test code file + * @v line Test code line + */ +static inline __attribute__ (( always_inline )) void +flsl_okx ( long value, int msb, const char *file, unsigned int line ) { + + /* Verify as a constant (requires to be inlined) */ + okx ( flsl ( value ) == msb, file, line ); + + /* Verify as a non-constant */ + okx ( flsl_var ( value ) == msb, file, line ); +} +#define flsl_ok( value, msb ) flsl_okx ( value, msb, __FILE__, __LINE__ ) + +/** + * Report a flsll() test result + * + * @v value Value + * @v msb Expected MSB + * @v file Test code file + * @v line Test code line + */ +static inline __attribute__ (( always_inline )) void +flsll_okx ( long long value, int msb, const char *file, unsigned int line ) { + + /* Verify as a constant (requires to be inlined) */ + okx ( flsll ( value ) == msb, file, line ); + + /* Verify as a non-constant */ + okx ( flsll_var ( value ) == msb, file, line ); +} +#define flsll_ok( value, msb ) flsll_okx ( value, msb, __FILE__, __LINE__ ) + +/** + * Report a 64-bit unsigned integer division test result + * + * @v dividend Dividend + * @v divisor Divisor + * @v quotient Quotient + * @v remainder Remainder + * @v file Test code file + * @v line Test code line + */ +static void u64divmod_okx ( uint64_t dividend, uint64_t divisor, + uint64_t quotient, uint64_t remainder, + const char *file, unsigned int line ) { + + /* Sanity check */ + okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line ); + + /* Check division */ + okx ( u64div_var ( dividend, divisor ) == quotient, file, line ); + + /* Check modulus */ + okx ( u64mod_var ( dividend, divisor ) == remainder, file, line ); +} +#define u64divmod_ok( dividend, divisor, quotient, remainder ) \ + u64divmod_okx ( dividend, divisor, quotient, remainder, \ + __FILE__, __LINE__ ) + +/** + * Report a 64-bit signed integer division test result + * + * @v dividend Dividend + * @v divisor Divisor + * @v quotient Quotient + * @v remainder Remainder + * @v file Test code file + * @v line Test code line + */ +static void s64divmod_okx ( int64_t dividend, int64_t divisor, + int64_t quotient, int64_t remainder, + const char *file, unsigned int line ) { + + /* Sanity check */ + okx ( ( ( divisor * quotient ) + remainder ) == dividend, file, line ); + + /* Check division */ + okx ( s64div_var ( dividend, divisor ) == quotient, file, line ); + + /* Check modulus */ + okx ( s64mod_var ( dividend, divisor ) == remainder, file, line ); +} +#define s64divmod_ok( dividend, divisor, quotient, remainder ) \ + s64divmod_okx ( dividend, divisor, quotient, remainder, \ + __FILE__, __LINE__ ) + +/** + * Perform mathematical self-tests + * + */ +static void math_test_exec ( void ) { + + /* Test flsl() */ + flsl_ok ( 0, 0 ); + flsl_ok ( 1, 1 ); + flsl_ok ( 255, 8 ); + flsl_ok ( 256, 9 ); + flsl_ok ( 257, 9 ); + flsl_ok ( 0x69505845, 31 ); + flsl_ok ( -1U, ( 8 * sizeof ( int ) ) ); + flsl_ok ( -1UL, ( 8 * sizeof ( long ) ) ); + + /* Test flsll() */ + flsll_ok ( 0, 0 ); + flsll_ok ( 1, 1 ); + flsll_ok ( 0x6d63623330ULL, 39 ); + flsll_ok ( -1U, ( 8 * sizeof ( int ) ) ); + flsll_ok ( -1UL, ( 8 * sizeof ( long ) ) ); + flsll_ok ( -1ULL, ( 8 * sizeof ( long long ) ) ); + + /* Test 64-bit arithmetic + * + * On a 64-bit machine, these tests are fairly meaningless. + * + * On a 32-bit machine, these tests verify the correct + * operation of our libgcc functions __udivmoddi4() + * etc. (including checking that the implicit calling + * convention assumed by gcc matches our expectations). + */ + u64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL, + 0x2eef6ab4ULL, 0x0e12f089ULL ); + s64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL, + 0x2eef6ab4ULL, 0x0e12f089ULL ); + u64divmod_ok ( 0xc09e00dcb9e34b54ULL, 0x35968185cdc744f3ULL, + 3, 0x1fda7c4b508d7c7bULL ); + s64divmod_ok ( -0x3f61ff23461cb4acLL, 0x35968185cdc744f3ULL, + -1LL, -0x9cb7d9d78556fb9LL ); + u64divmod_ok ( 0, 0x5b2f2737f4ffULL, 0, 0 ); + s64divmod_ok ( 0, 0xbb00ded72766207fULL, 0, 0 ); + + /* Test integer square root */ + ok ( isqrt ( 0 ) == 0 ); + ok ( isqrt ( 1 ) == 1 ); + ok ( isqrt ( 255 ) == 15 ); + ok ( isqrt ( 256 ) == 16 ); + ok ( isqrt ( 257 ) == 16 ); + ok ( isqrt ( 0xa53df2adUL ) == 52652 ); + ok ( isqrt ( 0x123793c6UL ) == 17482 ); + ok ( isqrt ( -1UL ) == ( -1UL >> ( 8 * sizeof ( unsigned long ) / 2 ))); +} + +/** Mathematical self-tests */ +struct self_test math_test __self_test = { + .name = "math", + .exec = math_test_exec, +}; diff --git a/roms/ipxe/src/tests/memcpy_test.c b/roms/ipxe/src/tests/memcpy_test.c index b405a9f2f..f1e5503a6 100644 --- a/roms/ipxe/src/tests/memcpy_test.c +++ b/roms/ipxe/src/tests/memcpy_test.c @@ -34,6 +34,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/test.h> #include <ipxe/profile.h> +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /* Provide global functions to allow inspection of generated code */ void memcpy_0 ( void *dest, void *src ) { memcpy ( dest, src, 0 ); } @@ -120,10 +123,10 @@ __attribute__ (( noinline )) void * memcpy_var ( void *dest, const void *src, */ static void memcpy_test_speed ( unsigned int dest_offset, unsigned int src_offset, size_t len ) { + struct profiler profiler; uint8_t *dest; uint8_t *src; unsigned int i; - unsigned long elapsed; /* Allocate blocks */ dest = malloc ( len + dest_offset ); @@ -135,21 +138,26 @@ static void memcpy_test_speed ( unsigned int dest_offset, for ( i = 0 ; i < len ; i++ ) src[ src_offset + i ] = random(); - /* Perform memcpy() */ - simple_profile(); + /* Check correctness of copied data */ memcpy ( ( dest + dest_offset ), ( src + src_offset ), len ); - elapsed = simple_profile(); - - /* Check copied data */ ok ( memcmp ( ( dest + dest_offset ), ( src + src_offset ), len ) == 0 ); + /* Profile memcpy() */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + memcpy ( ( dest + dest_offset ), ( src + src_offset ), len ); + profile_stop ( &profiler ); + } + /* Free blocks */ free ( dest ); free ( src ); - DBG ( "MEMCPY copied %zd bytes (+%d => +%d) in %ld ticks\n", - len, src_offset, dest_offset, elapsed ); + DBG ( "MEMCPY copied %zd bytes (+%d => +%d) in %ld +/- %ld ticks\n", + len, src_offset, dest_offset, profile_mean ( &profiler ), + profile_stddev ( &profiler ) ); } /** diff --git a/roms/ipxe/src/tests/pixbuf_test.c b/roms/ipxe/src/tests/pixbuf_test.c new file mode 100644 index 000000000..15cd33dfd --- /dev/null +++ b/roms/ipxe/src/tests/pixbuf_test.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Pixel buffer self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <assert.h> +#include <ipxe/image.h> +#include <ipxe/pixbuf.h> +#include <ipxe/test.h> +#include "pixbuf_test.h" + +/** + * Report pixel buffer test result + * + * @v test Pixel buffer test + * @v file Test code file + * @v line Test code line + */ +void pixbuf_okx ( struct pixel_buffer_test *test, const char *file, + unsigned int line ) { + struct pixel_buffer *pixbuf; + int rc; + + /* Sanity check */ + assert ( ( test->width * test->height * sizeof ( test->data[0] ) ) + == test->len ); + + /* Correct image data pointer */ + test->image->data = virt_to_user ( ( void * ) test->image->data ); + + /* Check that image is detected as PNM */ + okx ( image_probe ( test->image ) == 0, file, line ); + okx ( test->image->type == test->type, file, line ); + + /* Check that a pixel buffer can be created from the image */ + okx ( ( rc = image_pixbuf ( test->image, &pixbuf ) ) == 0, file, line ); + if ( rc == 0 ) { + + /* Check pixel buffer dimensions */ + okx ( pixbuf->width == test->width, file, line ); + okx ( pixbuf->height == test->height, file, line ); + + /* Check pixel buffer data */ + okx ( pixbuf->len == test->len, file, line ); + okx ( memcmp_user ( pixbuf->data, 0, + virt_to_user ( test->data ), 0, + test->len ) == 0, file, line ); + + pixbuf_put ( pixbuf ); + } +} diff --git a/roms/ipxe/src/tests/pixbuf_test.h b/roms/ipxe/src/tests/pixbuf_test.h new file mode 100644 index 000000000..394f7f5fa --- /dev/null +++ b/roms/ipxe/src/tests/pixbuf_test.h @@ -0,0 +1,66 @@ +#ifndef _PIXBUF_TEST_H +#define _PIXBUF_TEST_H + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <ipxe/refcnt.h> +#include <ipxe/image.h> +#include <ipxe/test.h> + +/** A pixel buffer test */ +struct pixel_buffer_test { + /** Image type */ + struct image_type *type; + /** Source image */ + struct image *image; + /** Pixel data */ + const uint32_t *data; + /** Length of pixel data */ + size_t len; + /** Width */ + unsigned int width; + /** Height */ + unsigned int height; +}; + +/** + * Define a pixel buffer test + * + * @v _name Test name + * @v _type Test image file type + * @v _file Test image file data + * @v _width Expected pixel buffer width + * @v _height Expected pixel buffer height + * @v _data Expected pixel buffer data + * @ret test Pixel buffer test + */ +#define PIX( _name, _type, _file, _width, _height, _data ) \ + static const char _name ## __file[] = _file; \ + static const uint32_t _name ## __data[] = _data; \ + static struct image _name ## __image = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .name = #_name, \ + .data = ( userptr_t ) ( _name ## __file ), \ + .len = sizeof ( _name ## __file ), \ + }; \ + static struct pixel_buffer_test _name = { \ + .type = _type, \ + .image = & _name ## __image, \ + .data = _name ## __data, \ + .len = sizeof ( _name ## __data ), \ + .width = _width, \ + .height = _height, \ + }; + +extern void pixbuf_okx ( struct pixel_buffer_test *test, const char *file, + unsigned int line ); + +/** + * Report pixel buffer test result + * + * @v test Pixel buffer test + */ +#define pixbuf_ok( test ) pixbuf_okx ( test, __FILE__, __LINE__ ) + +#endif /* _PIXBUF_TEST_H */ diff --git a/roms/ipxe/src/tests/png_test.c b/roms/ipxe/src/tests/png_test.c new file mode 100644 index 000000000..cf32f2034 --- /dev/null +++ b/roms/ipxe/src/tests/png_test.c @@ -0,0 +1,1993 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * PNG self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <assert.h> +#include <ipxe/pixbuf.h> +#include <ipxe/png.h> +#include <ipxe/test.h> +#include "pixbuf_test.h" + +/** Define inline pixel data */ +#define DATA(...) { __VA_ARGS__ } + +/* Non-opaque alpha channel */ +PIX ( alpha, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x06, 0x00, 0x00, 0x00, 0xf3, 0x1b, 0xaf, 0xbc, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x06, + 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0, + 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, + 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, + 0x9c, 0x18, 0x00, 0x00, 0x01, 0x25, 0x49, 0x44, 0x41, 0x54, 0x18, + 0xd3, 0x05, 0xc1, 0xcb, 0x2e, 0x03, 0x51, 0x00, 0x80, 0xe1, 0x7f, + 0x6e, 0xa9, 0xe9, 0x65, 0x32, 0x53, 0x6d, 0xa5, 0x42, 0xd3, 0x34, + 0x12, 0x0b, 0x0b, 0x1b, 0x04, 0x3b, 0x3b, 0x3b, 0x8f, 0xe1, 0x35, + 0xbc, 0x81, 0x67, 0xf1, 0x10, 0x22, 0x11, 0x0b, 0x42, 0x68, 0x17, + 0x5a, 0x42, 0x94, 0xd0, 0x9e, 0xe9, 0xf4, 0x4c, 0x67, 0x3a, 0x39, + 0x33, 0xc7, 0xf7, 0x19, 0x97, 0xd7, 0xc5, 0x45, 0x7b, 0x3c, 0xc0, + 0xd2, 0x8a, 0xa8, 0xea, 0xa3, 0x6d, 0x87, 0xc2, 0x6f, 0xe2, 0xa9, + 0x39, 0x58, 0x0e, 0x69, 0x6e, 0xa0, 0x55, 0x42, 0xb8, 0xb0, 0x70, + 0xa5, 0x60, 0xa5, 0xa4, 0x31, 0xea, 0x75, 0xec, 0x2c, 0xd7, 0x28, + 0x95, 0x51, 0xff, 0x19, 0xd2, 0x7b, 0xba, 0x25, 0x2b, 0xb9, 0x8c, + 0x8e, 0xcf, 0xf0, 0xc2, 0x2f, 0x6a, 0x71, 0x88, 0xca, 0x73, 0x22, + 0xbf, 0xc9, 0x9a, 0x08, 0xf1, 0x3e, 0x5f, 0x49, 0x82, 0x26, 0x62, + 0x77, 0x1f, 0x33, 0x13, 0x92, 0xd5, 0xc1, 0x3d, 0xe6, 0xf4, 0x8f, + 0x49, 0x63, 0x93, 0xd8, 0xa9, 0xa0, 0xbf, 0xc7, 0xf4, 0xbb, 0x07, + 0xd4, 0x06, 0x0f, 0x68, 0x39, 0xa7, 0xdf, 0xdd, 0xc3, 0x1b, 0x8f, + 0x58, 0x3a, 0x65, 0x26, 0xc1, 0x06, 0x1f, 0xc1, 0x16, 0x26, 0xe1, + 0x0c, 0x33, 0x92, 0x58, 0x51, 0x4c, 0x25, 0x9a, 0x32, 0xa9, 0xae, + 0xf3, 0xdc, 0x39, 0x22, 0xff, 0x15, 0x68, 0x29, 0x11, 0x6e, 0x83, + 0x74, 0xa9, 0x58, 0xa6, 0x19, 0x9f, 0xe5, 0x16, 0x33, 0xa3, 0x44, + 0x94, 0x80, 0x1d, 0xfc, 0xbd, 0x93, 0x2a, 0x13, 0x65, 0x3a, 0xdc, + 0x9c, 0x9c, 0x23, 0xdc, 0x06, 0x85, 0x08, 0xd9, 0xb9, 0xb9, 0xe2, + 0x76, 0xfb, 0x94, 0xe6, 0xd7, 0x90, 0xb6, 0x75, 0x87, 0x23, 0xe7, + 0xa4, 0x75, 0x93, 0xb0, 0x1c, 0x10, 0xe3, 0x60, 0x0b, 0xd7, 0x27, + 0xe9, 0xee, 0xa1, 0x0d, 0x93, 0xa9, 0xe3, 0x43, 0x01, 0x5e, 0x26, + 0x19, 0x74, 0xf6, 0x79, 0xe9, 0x1d, 0xd2, 0x7a, 0x7b, 0xc4, 0x4d, + 0x26, 0x58, 0x9d, 0x1d, 0x72, 0x39, 0x63, 0x11, 0x67, 0x14, 0x96, + 0xcd, 0x3f, 0x0a, 0xd4, 0x8b, 0x0b, 0x4d, 0xd7, 0xb9, 0xb6, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, + 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, + 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, + 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, + 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, + 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, + 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x48637f, 0x54566c, 0x56566a, 0x4f5c72, 0x4e5e74, 0x4d667f, + 0x546478, 0x54657b, 0x50647b, 0x506277, 0x485d78, 0x4c5770, + 0x505a6f, 0x516378, 0x45617f, 0x525469, 0x5d4958, 0x67333d, + 0x643641, 0x535369, 0x5b4b5c, 0x624654, 0x604452, 0x594c5d, + 0x5b4455, 0x623643, 0x5e3e4e, 0x555668, 0x425979, 0x5c4151, + 0x5e404e, 0x5d3d4b, 0x5e3947, 0x53475c, 0x475b77, 0x68323c, + 0x5f3e4c, 0x455c77, 0x623744, 0x5f3848, 0x54475c, 0x475e7a, + 0x425171, 0x5d3a4b, 0x603948, 0x633642, 0x553f54, 0x3e5679, + 0x46516e, 0x682c36, 0x574356, 0x415975, 0x5f3341, 0x513d53, + 0x4d475f, 0x405a7a, 0x4a4762, 0x59384c, 0x5b394b, 0x435676, + 0x3b5b80, 0x3a5278, 0x5b3447, 0x4d405a, 0x573649, 0x4d445b, + 0x612d3b, 0x4d3c54, 0x454c68, 0x3a5a7d, 0x424b6a, 0x464866, + 0x454867, 0x3a597e, 0x3a5a80, 0x414f72, 0x484361, 0x33547d, + 0x3e4467, 0x43405d, 0x4f3c50, 0x4b364d, 0x404765, 0x395b7f ) ); + +/* Colour type 0, bit depth 1 */ +PIX ( ctype_0_1, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x60, 0x92, 0x11, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x01, 0xdd, 0x8a, 0x13, 0xa4, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x0e, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff, 0x87, 0x01, + 0x15, 0x01, 0x00, 0x6b, 0x0d, 0x0b, 0xe3, 0xeb, 0x45, 0x62, 0x80, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, + 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, + 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff ) ); + +/* Colour type 0, bit depth 16 */ +PIX ( ctype_0_16, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x86, 0xe0, 0x2c, 0x23, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0xff, 0xff, 0x14, 0xab, 0x31, 0xcd, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x85, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x1d, 0x8e, 0xc9, 0x0a, 0xc2, + 0x50, 0x0c, 0x45, 0xdf, 0x5f, 0xb9, 0x52, 0xea, 0xac, 0x88, 0xad, + 0x58, 0x41, 0x70, 0x5e, 0x89, 0xb3, 0x82, 0x82, 0xa0, 0x9b, 0xb3, + 0xe9, 0x42, 0x44, 0xc4, 0x3f, 0xf6, 0xb4, 0x84, 0x0c, 0x37, 0xb9, + 0x37, 0x49, 0xc8, 0x38, 0x6b, 0x77, 0x9e, 0x7c, 0xf9, 0xf0, 0xe3, + 0x4d, 0x26, 0x3a, 0x70, 0xe3, 0x45, 0x80, 0x2d, 0x33, 0xda, 0x74, + 0xcc, 0x4b, 0xa6, 0x8c, 0x8d, 0xa9, 0xb8, 0xcf, 0x89, 0x70, 0x24, + 0xd1, 0x7a, 0xc2, 0x94, 0xab, 0x94, 0xb8, 0x88, 0x39, 0x7a, 0x10, + 0xe6, 0x85, 0x2a, 0xf7, 0x35, 0x0b, 0x6a, 0x12, 0x77, 0x54, 0xa9, + 0x33, 0xc8, 0x95, 0xb1, 0x8d, 0x06, 0x1b, 0x2e, 0x8e, 0x22, 0x9a, + 0x54, 0xdc, 0x52, 0xb6, 0x1a, 0x79, 0x37, 0x0c, 0x5d, 0x94, 0xb0, + 0x97, 0x37, 0x51, 0xbd, 0xa2, 0xe5, 0x20, 0xa2, 0x44, 0xd7, 0x37, + 0xff, 0x4c, 0xf2, 0x48, 0x0d, 0x2c, 0x7a, 0x80, 0xe2, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, + 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, + 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, + 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, + 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, + 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, + 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x858585, 0x6f6f6f, 0x6f6f6f, 0x777777, 0x7b7b7b, 0x8f8f8f, + 0x8d8d8d, 0x919191, 0x8b8b8b, 0x858585, 0x777777, 0x6c6c6c, + 0x747474, 0x898989, 0x808080, 0x696969, 0x5c5c5c, 0x474747, + 0x484848, 0x696969, 0x5f5f5f, 0x5b5b5b, 0x575757, 0x5f5f5f, + 0x535353, 0x474747, 0x4d4d4d, 0x6e6e6e, 0x6d6d6d, 0x4f4f4f, + 0x4f4f4f, 0x4b4b4b, 0x474747, 0x535353, 0x737373, 0x484848, + 0x4e4e4e, 0x737373, 0x484848, 0x474747, 0x535353, 0x7a7a7a, + 0x5d5d5d, 0x474747, 0x484848, 0x474747, 0x484848, 0x666666, + 0x5e5e5e, 0x424242, 0x4f4f4f, 0x6a6a6a, 0x414141, 0x434343, + 0x505050, 0x6e6e6e, 0x4e4e4e, 0x424242, 0x444444, 0x686868, + 0x707070, 0x5e5e5e, 0x404040, 0x454545, 0x3e3e3e, 0x4b4b4b, + 0x3d3d3d, 0x404040, 0x545454, 0x6c6c6c, 0x525252, 0x4e4e4e, + 0x4f4f4f, 0x6b6b6b, 0x6e6e6e, 0x5a5a5a, 0x484848, 0x606060, + 0x464646, 0x404040, 0x404040, 0x373737, 0x494949, 0x6f6f6f ) ); + +/* Colour type 0, bit depth 2 */ +PIX ( ctype_0_2, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xc0, 0xe8, 0xc1, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x03, 0x33, 0x84, 0x72, 0x88, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x24, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x08, 0x0d, 0x0d, 0x0d, + 0x60, 0x08, 0x11, 0x0d, 0x11, 0x60, 0x08, 0x10, 0x11, 0x08, 0x60, + 0x70, 0x10, 0x09, 0x08, 0x60, 0x70, 0x0c, 0x00, 0xb2, 0x42, 0x43, + 0x1d, 0x02, 0x00, 0x59, 0xc5, 0x06, 0x00, 0x68, 0xee, 0x01, 0x07, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, + 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, + 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, + 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, + 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, 0x000000, + 0x000000, 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, + 0x555555, 0x000000, 0x000000, 0x555555, 0x555555, 0x555555, + 0x000000, 0x000000, 0x000000, 0x555555, 0x555555, 0x000000, + 0x000000, 0x555555, 0x000000, 0x000000, 0x555555, 0x555555, + 0x555555, 0x000000, 0x000000, 0x000000, 0x000000, 0x555555, + 0x555555, 0x000000, 0x555555, 0x555555, 0x000000, 0x000000, + 0x555555, 0x555555, 0x555555, 0x000000, 0x000000, 0x555555, + 0x555555, 0x555555, 0x000000, 0x000000, 0x000000, 0x555555, + 0x000000, 0x000000, 0x555555, 0x555555, 0x555555, 0x555555, + 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, 0x555555, + 0x555555, 0x000000, 0x000000, 0x000000, 0x555555, 0x555555 ) ); + +/* Colour type 0, bit depth 4 */ +PIX ( ctype_0_4, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80, 0x1d, 0x61, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0x0f, 0x3a, 0x32, 0x3e, 0xa3, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x37, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x68, 0x4f, 0xaf, 0x9c, + 0xd9, 0x5e, 0x56, 0xc1, 0x50, 0x96, 0xe2, 0x96, 0x1a, 0x1a, 0xe2, + 0xc6, 0x90, 0xea, 0xe2, 0x5a, 0xe2, 0xee, 0x12, 0xce, 0x10, 0xe2, + 0xe2, 0x16, 0xec, 0xe6, 0xe2, 0xce, 0xe0, 0xe2, 0x56, 0xe6, 0x62, + 0x62, 0x02, 0xe4, 0xbb, 0x95, 0xba, 0x39, 0x1b, 0xbb, 0x03, 0x00, + 0x7a, 0x4c, 0x0e, 0x45, 0x5a, 0x3c, 0xd1, 0xca, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, + 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, + 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, + 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, + 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x888888, 0x777777, 0x666666, 0x777777, 0x777777, 0x999999, + 0x999999, 0x999999, 0x888888, 0x777777, 0x777777, 0x666666, + 0x777777, 0x888888, 0x777777, 0x666666, 0x666666, 0x444444, + 0x444444, 0x666666, 0x666666, 0x555555, 0x555555, 0x555555, + 0x555555, 0x444444, 0x444444, 0x666666, 0x666666, 0x555555, + 0x444444, 0x444444, 0x444444, 0x555555, 0x777777, 0x444444, + 0x444444, 0x777777, 0x444444, 0x444444, 0x555555, 0x777777, + 0x555555, 0x444444, 0x444444, 0x444444, 0x444444, 0x666666, + 0x555555, 0x333333, 0x444444, 0x666666, 0x444444, 0x444444, + 0x444444, 0x777777, 0x444444, 0x444444, 0x444444, 0x666666, + 0x777777, 0x666666, 0x444444, 0x444444, 0x333333, 0x444444, + 0x333333, 0x444444, 0x555555, 0x777777, 0x555555, 0x444444, + 0x444444, 0x666666, 0x777777, 0x555555, 0x444444, 0x666666, + 0x444444, 0x333333, 0x333333, 0x333333, 0x444444, 0x777777 ) ); + +/* Colour type 0, bit depth 8 */ +PIX ( ctype_0_8, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x70, 0xf0, 0x60, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x62, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x68, 0xcd, 0xcf, 0x2f, + 0xaf, 0xee, 0xef, 0x9d, 0xd8, 0xdd, 0x5a, 0x9e, 0x53, 0xd2, 0xc9, + 0xd0, 0x90, 0x19, 0xe3, 0xe1, 0x91, 0x19, 0x1f, 0x1d, 0x1e, 0x1f, + 0xec, 0xee, 0x97, 0xc7, 0x90, 0xeb, 0x1f, 0xe0, 0xed, 0x1e, 0x5c, + 0xec, 0xe9, 0x57, 0xec, 0xe9, 0x1e, 0x52, 0xc5, 0x10, 0xeb, 0xee, + 0xe9, 0xee, 0x91, 0x16, 0xe7, 0xec, 0x9f, 0xe5, 0xe8, 0x1c, 0x90, + 0xc7, 0xe0, 0xe7, 0xe4, 0x9a, 0x51, 0x10, 0xe7, 0xe0, 0x6a, 0xef, + 0x6d, 0xe7, 0x10, 0x92, 0xc3, 0x10, 0xe4, 0xe7, 0x9f, 0x9d, 0x17, + 0xe5, 0x91, 0xe8, 0xe6, 0xe0, 0x60, 0xee, 0x99, 0x0f, 0x00, 0xb8, + 0xaa, 0x1e, 0x19, 0xe8, 0x28, 0x25, 0xa0, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, + 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, + 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, + 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, + 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x858585, 0x6f6f6f, 0x6f6f6f, 0x777777, 0x7b7b7b, 0x8f8f8f, + 0x8d8d8d, 0x919191, 0x8b8b8b, 0x858585, 0x777777, 0x6c6c6c, + 0x747474, 0x898989, 0x808080, 0x696969, 0x5c5c5c, 0x484848, + 0x484848, 0x696969, 0x5f5f5f, 0x5b5b5b, 0x575757, 0x5f5f5f, + 0x535353, 0x474747, 0x4e4e4e, 0x6e6e6e, 0x6d6d6d, 0x4f4f4f, + 0x505050, 0x4b4b4b, 0x474747, 0x535353, 0x737373, 0x494949, + 0x4e4e4e, 0x737373, 0x494949, 0x474747, 0x545454, 0x7a7a7a, + 0x5d5d5d, 0x474747, 0x494949, 0x474747, 0x484848, 0x666666, + 0x5e5e5e, 0x434343, 0x4f4f4f, 0x6a6a6a, 0x414141, 0x434343, + 0x505050, 0x6e6e6e, 0x4e4e4e, 0x424242, 0x454545, 0x686868, + 0x707070, 0x5e5e5e, 0x404040, 0x454545, 0x3f3f3f, 0x4b4b4b, + 0x3e3e3e, 0x404040, 0x545454, 0x6c6c6c, 0x525252, 0x4e4e4e, + 0x4f4f4f, 0x6b6b6b, 0x6e6e6e, 0x5a5a5a, 0x484848, 0x616161, + 0x464646, 0x404040, 0x404040, 0x373737, 0x494949, 0x6f6f6f ) ); + +/* Colour type 2, bit depth 16 */ +PIX ( ctype_2_16, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x10, 0x02, 0x00, 0x00, 0x00, 0x2c, 0xe9, 0xe4, 0xa8, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x06, + 0x62, 0x4b, 0x47, 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x09, + 0x58, 0xf7, 0xdc, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, + 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, + 0x9c, 0x18, 0x00, 0x00, 0x01, 0x45, 0x49, 0x44, 0x41, 0x54, 0x18, + 0xd3, 0x2d, 0xcb, 0xc1, 0x6e, 0xd2, 0x00, 0x00, 0x00, 0xd0, 0x47, + 0x4b, 0x83, 0xb0, 0x8d, 0x00, 0x8e, 0x99, 0x19, 0x25, 0x64, 0x31, + 0xf1, 0xb0, 0x83, 0x97, 0xcd, 0xa8, 0x37, 0x6f, 0xde, 0xfc, 0x0c, + 0x7f, 0x83, 0x3f, 0xf0, 0x5b, 0xfc, 0x08, 0xb3, 0x64, 0xf1, 0xa0, + 0xd1, 0xe8, 0x38, 0xb8, 0x69, 0x5c, 0x86, 0xc6, 0x41, 0x4b, 0x29, + 0x83, 0x35, 0x2d, 0xf5, 0xe2, 0xbb, 0xbf, 0xda, 0xdb, 0xd1, 0xfb, + 0xd1, 0x66, 0xb4, 0x6f, 0x62, 0x2c, 0x54, 0x29, 0xa4, 0xb6, 0x75, + 0x54, 0xea, 0x22, 0x1b, 0x1d, 0x7d, 0x6d, 0x85, 0x05, 0x42, 0x91, + 0xb5, 0x52, 0x4d, 0xa5, 0xb0, 0x92, 0xb8, 0x11, 0x6a, 0xca, 0xc4, + 0xee, 0x68, 0xa8, 0xd4, 0xf4, 0xf4, 0xd4, 0x73, 0xa5, 0x4a, 0xa1, + 0x90, 0xeb, 0xf9, 0xe3, 0xdc, 0x81, 0x2f, 0x4e, 0xe5, 0x1a, 0x9a, + 0x2e, 0xbc, 0xf0, 0x5a, 0x5b, 0xe2, 0xca, 0x8e, 0xa5, 0x44, 0xa1, + 0x54, 0x4a, 0x75, 0xf4, 0xdd, 0x13, 0x4b, 0xb4, 0x5d, 0xfa, 0x6e, + 0xa5, 0xab, 0x2f, 0xf6, 0xc4, 0xb1, 0x20, 0x17, 0xcb, 0xdc, 0x35, + 0xf6, 0x51, 0x60, 0xe6, 0xda, 0xd4, 0xae, 0x87, 0x96, 0x22, 0x5b, + 0x2a, 0xbf, 0x4d, 0x9c, 0x19, 0x7a, 0x6a, 0xc7, 0xd8, 0x27, 0x95, + 0xcc, 0xc2, 0x99, 0xa1, 0x23, 0x6d, 0x13, 0x17, 0x6e, 0x45, 0x5a, + 0xa6, 0xba, 0x1e, 0xf8, 0xa5, 0xeb, 0x91, 0x80, 0xc4, 0x5c, 0x20, + 0x95, 0x09, 0xa5, 0x96, 0xb6, 0xa4, 0x66, 0xa6, 0xb6, 0xdd, 0xf7, + 0xd5, 0xc0, 0x73, 0xa5, 0xbf, 0x62, 0x95, 0x4c, 0x26, 0xd6, 0xb4, + 0x6b, 0xed, 0x56, 0xe1, 0xd6, 0x5a, 0xee, 0x52, 0xcb, 0x9e, 0xb9, + 0x9a, 0x86, 0xd4, 0x0a, 0xf5, 0xae, 0x6b, 0x3f, 0xad, 0x15, 0x02, + 0x85, 0x40, 0xe4, 0xc4, 0x4b, 0x6f, 0xfe, 0xe7, 0x8d, 0x58, 0xe2, + 0xd0, 0x89, 0x77, 0x4e, 0x3d, 0xf6, 0x4a, 0xdf, 0x95, 0x73, 0xfb, + 0x42, 0x1f, 0x44, 0x32, 0x0b, 0x6b, 0x3d, 0x81, 0x44, 0x4b, 0xd7, + 0x12, 0x91, 0x7a, 0xac, 0xa9, 0x63, 0x65, 0xe8, 0x48, 0xa5, 0x26, + 0x30, 0x13, 0xe9, 0x60, 0x83, 0xb6, 0x5c, 0x66, 0x6c, 0xe0, 0xd8, + 0x37, 0x07, 0x9e, 0xd9, 0xf3, 0xc3, 0x67, 0x4d, 0x2b, 0x53, 0xa1, + 0x81, 0x43, 0xa5, 0xcc, 0xdc, 0x8d, 0xa5, 0xdc, 0x46, 0xa8, 0xee, + 0x1f, 0x17, 0x48, 0x8c, 0x0b, 0x6d, 0x83, 0xc4, 0x70, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, + 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, + 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, + 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, + 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, + 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, + 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Colour type 2, bit depth 8 */ +PIX ( ctype_2_8, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x02, 0x00, 0x00, 0x00, 0x7c, 0x79, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x06, + 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0, + 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, + 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, + 0x9c, 0x18, 0x00, 0x00, 0x01, 0x04, 0x49, 0x44, 0x41, 0x54, 0x18, + 0xd3, 0x05, 0xc1, 0xc1, 0x4e, 0x83, 0x30, 0x00, 0x00, 0x50, 0x68, + 0x69, 0xb0, 0x6c, 0x23, 0x80, 0x30, 0x33, 0xa3, 0x84, 0x2c, 0x26, + 0x1e, 0x76, 0xf0, 0xb2, 0x19, 0xf5, 0xe6, 0xcd, 0x9b, 0x9f, 0xe1, + 0xe7, 0xf8, 0x2d, 0x7e, 0x84, 0x59, 0xb2, 0x78, 0xd0, 0x68, 0x74, + 0x1c, 0xdc, 0x34, 0x2e, 0x63, 0xc6, 0x41, 0x0b, 0x94, 0x01, 0x4d, + 0xa1, 0xbe, 0xa7, 0xde, 0x3f, 0xb6, 0x83, 0x28, 0x84, 0x52, 0x64, + 0x5d, 0x4b, 0x6a, 0xa8, 0xb5, 0x3c, 0x53, 0xe4, 0x0a, 0x44, 0x55, + 0xa3, 0x4a, 0x51, 0xd2, 0x1d, 0xc4, 0x8c, 0xec, 0xe9, 0x52, 0x75, + 0x1c, 0x8d, 0x37, 0x52, 0x08, 0xee, 0xfc, 0x2e, 0x86, 0x6f, 0x33, + 0xae, 0xe3, 0xe5, 0xd5, 0xad, 0x49, 0xd7, 0xbd, 0x82, 0x8a, 0xa6, + 0xc9, 0x2c, 0xef, 0x80, 0x50, 0x73, 0xf5, 0x59, 0xda, 0x1e, 0x39, + 0x9b, 0x00, 0x4e, 0xd8, 0x7e, 0xf8, 0x0c, 0x92, 0x6d, 0xec, 0x1e, + 0x17, 0xa8, 0x23, 0x37, 0xd1, 0x3c, 0x38, 0xef, 0x85, 0x2f, 0x92, + 0xe5, 0xf3, 0x60, 0x6c, 0x46, 0xcb, 0x1a, 0x19, 0xb1, 0x7d, 0xf4, + 0x63, 0x9f, 0x00, 0x85, 0xa6, 0x20, 0x63, 0x30, 0x2b, 0x3a, 0x59, + 0x12, 0x77, 0x0f, 0xdf, 0xfd, 0xcb, 0xe6, 0x8f, 0x48, 0xc6, 0x08, + 0x76, 0xab, 0x5a, 0xd4, 0x15, 0x5f, 0x19, 0xfd, 0x54, 0xd5, 0xb3, + 0x52, 0xd1, 0xec, 0xed, 0x77, 0x25, 0x80, 0x00, 0x68, 0x7a, 0x7d, + 0x47, 0xb0, 0xdb, 0x12, 0x3a, 0x9a, 0x3e, 0xcc, 0x4e, 0x6f, 0xbc, + 0xf5, 0x62, 0x00, 0x9f, 0x10, 0xcb, 0x2b, 0x07, 0x50, 0xc3, 0x2e, + 0x14, 0xa4, 0x11, 0x6c, 0x95, 0xc1, 0x58, 0xaa, 0x20, 0x41, 0x96, + 0xd2, 0x2a, 0x26, 0x67, 0xa1, 0x3f, 0xf9, 0x18, 0x5e, 0xf4, 0xbf, + 0x5e, 0x71, 0x19, 0x43, 0x7f, 0xd4, 0xb0, 0x74, 0x57, 0xf0, 0x16, + 0x6a, 0xff, 0xc1, 0x85, 0x8a, 0x8b, 0x87, 0xa4, 0x8a, 0x0e, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, + 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, + 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, + 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, + 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, + 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, + 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Colour type 3, bit depth 1 */ +PIX ( ctype_3_1, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x02, 0x03, 0x00, 0x00, 0x00, 0x8e, 0x75, 0x47, 0x2f, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x0c, + 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, + 0x00, 0xff, 0x00, 0xff, 0xff, 0x35, 0x24, 0xb1, 0xc4, 0x00, 0x00, + 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, 0x05, 0x1d, 0x48, + 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, + 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, + 0x00, 0x00, 0x24, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, + 0x00, 0x01, 0xc6, 0x06, 0xa6, 0x06, 0x06, 0xae, 0xc6, 0x2e, 0x06, + 0x06, 0xad, 0x8d, 0x5c, 0x06, 0x0c, 0x1a, 0xbf, 0xda, 0x0c, 0x18, + 0x98, 0x0f, 0xbf, 0xfa, 0x00, 0x00, 0x4a, 0x48, 0x07, 0xa6, 0x66, + 0x5c, 0x57, 0x79, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, + 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, + 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, + 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, + 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, + 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xff0000, + 0xff00ff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xff00ff, 0xff00ff, 0xffffff, 0xffffff, 0xffffff, + 0xff00ff, 0xff00ff, 0xff00ff, 0xffffff, 0xffffff, 0xff0000, + 0xff00ff, 0xffffff, 0xff00ff, 0xff00ff, 0xffffff, 0xffffff, + 0xffffff, 0xff00ff, 0xff00ff, 0xff00ff, 0xff00ff, 0x00ffff, + 0xffffff, 0xff0000, 0xffffff, 0xffffff, 0xff00ff, 0xff00ff, + 0xffffff, 0x00ffff, 0xffffff, 0xff00ff, 0xff00ff, 0xffffff, + 0x00ffff, 0x00ffff, 0xff00ff, 0xff00ff, 0xff00ff, 0xffffff, + 0xff0000, 0xff00ff, 0xffffff, 0x00ffff, 0xffffff, 0xffffff, + 0xffffff, 0x00ffff, 0x00ffff, 0xffffff, 0xffffff, 0x00ffff, + 0x00ffff, 0xff00ff, 0xff00ff, 0xff00ff, 0x00ffff, 0x00ffff ) ); + +/* Colour type 3, bit depth 2 */ +PIX ( ctype_3_2, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x35, 0xb2, 0x8f, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x15, + 0x50, 0x4c, 0x54, 0x45, 0xaa, 0xaa, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0xff, 0x55, 0xaa, 0xaa, + 0xff, 0xff, 0xff, 0xef, 0x1e, 0x2f, 0x5e, 0x00, 0x00, 0x00, 0x01, + 0x62, 0x4b, 0x47, 0x44, 0x06, 0x61, 0x66, 0xb8, 0x7d, 0x00, 0x00, + 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, + 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, + 0x34, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x10, 0x60, + 0x00, 0x03, 0x46, 0x21, 0x43, 0x41, 0x41, 0x61, 0x43, 0x06, 0x46, + 0x63, 0x43, 0x26, 0x03, 0x63, 0x01, 0x06, 0x66, 0x63, 0x13, 0x26, + 0x01, 0x63, 0x11, 0x06, 0x61, 0x03, 0x17, 0x63, 0x43, 0x65, 0x11, + 0x06, 0x41, 0x11, 0x07, 0x91, 0x60, 0xe3, 0x10, 0x00, 0x53, 0x53, + 0x04, 0xcd, 0x45, 0xaa, 0x11, 0x71, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0xaaaaff, 0xaaaaff, 0xaaaaaa, 0xaaaaff, 0xaaaaff, 0xaaaaff, + 0xaaaaff, 0xaaaaff, 0xaaaaff, 0xaaaaff, 0xaaaaff, 0xaaaaff, + 0xaaaaff, 0xaaaaff, 0xaaaaff, 0xaaaaaa, 0xaaaaaa, 0xaa5555, + 0xaa55aa, 0xaaaaaa, 0xaaaaaa, 0xaaaaaa, 0xaaaaaa, 0xaaaaaa, + 0xaaaaaa, 0xaa55aa, 0xaa55aa, 0xaaaaaa, 0xaaaaff, 0xaaaaaa, + 0xaa55aa, 0xaa55aa, 0xaa55aa, 0xaaaaaa, 0xaaaaff, 0xaa5555, + 0xaa55aa, 0xaaaaff, 0xaa55aa, 0xaa55aa, 0xaaaaaa, 0xaaaaff, + 0xaaaaff, 0xaa55aa, 0xaa55aa, 0xaa55aa, 0xaa55aa, 0x55aaff, + 0xaaaaff, 0xaa5555, 0xaaaaaa, 0xaaaaff, 0xaa55aa, 0xaa55aa, + 0xaaaaaa, 0x55aaff, 0xaaaaaa, 0xaa55aa, 0xaa55aa, 0xaaaaff, + 0x55aaff, 0x55aaff, 0xaa55aa, 0xaa55aa, 0xaa55aa, 0xaaaaaa, + 0xaa5555, 0xaa55aa, 0xaaaaaa, 0x55aaff, 0xaaaaaa, 0xaaaaaa, + 0xaaaaaa, 0x55aaff, 0x55aaff, 0xaaaaff, 0xaaaaaa, 0x55aaff, + 0x55aaaa, 0xaa55aa, 0xaa55aa, 0xaa55aa, 0x55aaaa, 0x55aaff ) ); + +/* Colour type 3, bit depth 4 */ +PIX ( ctype_3_4, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x8a, + 0x50, 0x4c, 0x54, 0x45, 0x88, 0xcc, 0xff, 0xaa, 0xaa, 0xdd, 0xaa, + 0xaa, 0xcc, 0x99, 0xbb, 0xdd, 0x99, 0xbb, 0xee, 0x99, 0xcc, 0xff, + 0xaa, 0xcc, 0xee, 0x99, 0xcc, 0xee, 0x88, 0xbb, 0xee, 0x99, 0xaa, + 0xdd, 0x88, 0xbb, 0xff, 0xbb, 0x99, 0xaa, 0xcc, 0x66, 0x77, 0xcc, + 0x66, 0x88, 0xbb, 0x99, 0xbb, 0xbb, 0x88, 0xaa, 0xaa, 0x99, 0xbb, + 0xbb, 0x77, 0x99, 0x88, 0xaa, 0xee, 0xbb, 0x88, 0x99, 0xbb, 0x77, + 0x88, 0xaa, 0x88, 0xbb, 0x88, 0x99, 0xdd, 0xaa, 0x77, 0xaa, 0x77, + 0xaa, 0xee, 0xcc, 0x55, 0x66, 0xaa, 0x88, 0xaa, 0xbb, 0x66, 0x88, + 0x99, 0x77, 0xaa, 0x99, 0x88, 0xbb, 0x77, 0xbb, 0xee, 0xaa, 0x77, + 0x99, 0x77, 0xbb, 0xff, 0x99, 0x77, 0xbb, 0xaa, 0x66, 0x99, 0xbb, + 0x55, 0x77, 0x88, 0x99, 0xcc, 0x88, 0x88, 0xcc, 0x77, 0xaa, 0xff, + 0x88, 0x88, 0xbb, 0x66, 0xaa, 0xff, 0x77, 0x88, 0xcc, 0x88, 0x77, + 0xbb, 0x99, 0x77, 0x99, 0x99, 0x66, 0x99, 0xff, 0xff, 0xff, 0xac, + 0x68, 0xae, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, + 0x2d, 0xcd, 0xda, 0x41, 0x3d, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, + 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, + 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x59, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x0d, 0xc5, 0xd9, 0x02, 0x40, 0x20, 0x10, 0x00, + 0xc0, 0x95, 0x2b, 0x47, 0xb2, 0x49, 0xce, 0x08, 0xe5, 0xfe, 0xff, + 0xef, 0x63, 0x5e, 0x06, 0xc0, 0x23, 0x7e, 0x10, 0x46, 0x51, 0x1c, + 0xd0, 0xc4, 0x8f, 0x21, 0x25, 0x59, 0xce, 0x48, 0xc1, 0x79, 0xc9, + 0x19, 0x12, 0x10, 0x15, 0xa2, 0xac, 0x69, 0x8e, 0x94, 0xfd, 0x81, + 0x42, 0xc9, 0x9a, 0x56, 0x75, 0xbd, 0x18, 0x46, 0x3d, 0x81, 0x9e, + 0x51, 0x98, 0x76, 0x58, 0x56, 0xbd, 0x8d, 0xd6, 0x80, 0x75, 0x6e, + 0x37, 0xea, 0x38, 0xaf, 0xfb, 0x79, 0x2f, 0xf3, 0x01, 0xcb, 0xd6, + 0x06, 0x9f, 0x93, 0x26, 0xe0, 0xd0, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x88ccff, 0xaaaadd, 0xaaaacc, 0x99bbdd, 0x99bbee, 0x99ccff, + 0xaaccee, 0xaaccee, 0x99ccee, 0x99bbee, 0x88bbee, 0x99aadd, + 0x99bbdd, 0x99ccee, 0x88bbff, 0xaaaacc, 0xbb99aa, 0xcc6677, + 0xcc6688, 0xaaaacc, 0xbb99bb, 0xbb88aa, 0xbb88aa, 0xaa99bb, + 0xbb88aa, 0xcc6688, 0xbb7799, 0xaaaacc, 0x88aaee, 0xbb8899, + 0xbb7799, 0xbb7799, 0xbb7788, 0xaa88bb, 0x88bbee, 0xcc6677, + 0xbb7799, 0x88bbee, 0xcc6688, 0xbb7788, 0xaa88bb, 0x88bbee, + 0x8899dd, 0xbb7799, 0xbb7788, 0xcc6688, 0xaa77aa, 0x77aaee, + 0x8899dd, 0xcc5566, 0xaa88aa, 0x88aaee, 0xbb6688, 0x9977aa, + 0x9988bb, 0x77bbee, 0x9988bb, 0xaa7799, 0xbb7799, 0x88aaee, + 0x77bbff, 0x77aaee, 0xbb6688, 0x9977bb, 0xaa6699, 0x9988bb, + 0xbb5577, 0x9977aa, 0x8899cc, 0x77bbff, 0x8899cc, 0x8888cc, + 0x8888cc, 0x77aaff, 0x77bbff, 0x8899dd, 0x8888bb, 0x66aaff, + 0x7788cc, 0x8877bb, 0x997799, 0x996699, 0x7788cc, 0x77bbff ) ); + +/* Colour type 3, bit depth 8 */ +PIX ( ctype_3_8, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x62, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x60, 0x60, 0x64, 0x62, 0x66, 0x61, 0x65, 0x63, 0xe7, 0xe0, 0xe4, + 0xe2, 0xe6, 0xe1, 0x65, 0xe0, 0xe3, 0x17, 0x10, 0x14, 0x12, 0x16, + 0x11, 0x15, 0x13, 0x97, 0x90, 0x94, 0x92, 0x66, 0x90, 0x91, 0x95, + 0x93, 0x57, 0x50, 0x54, 0x52, 0x56, 0x51, 0x55, 0x53, 0xd7, 0xd0, + 0x64, 0xd0, 0xd2, 0xd6, 0xd1, 0xd5, 0xd3, 0x37, 0x30, 0x34, 0x32, + 0x36, 0x31, 0x35, 0x33, 0x67, 0xb0, 0xb0, 0xb4, 0xb2, 0xb6, 0xb1, + 0xb5, 0xb3, 0x77, 0x70, 0x74, 0x72, 0x76, 0x71, 0x65, 0x70, 0x73, + 0xf7, 0xf0, 0xf4, 0xf2, 0xf6, 0xf1, 0xf5, 0xf3, 0x0f, 0x08, 0x0c, + 0x0a, 0x06, 0x00, 0x96, 0xe0, 0x0d, 0x9f, 0x37, 0x73, 0x30, 0xa4, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, + 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, + 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Colour type 4, bit depth 16 */ +PIX ( ctype_4_16, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x10, 0x04, 0x00, 0x00, 0x00, 0x09, 0x82, 0xbb, 0x74, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0xff, 0xff, 0x14, 0xab, 0x31, 0xcd, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x93, + 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x4d, 0xcf, 0xc1, 0x4e, 0xc2, + 0x60, 0x10, 0x04, 0xe0, 0x8f, 0xf2, 0x0b, 0x24, 0x72, 0x13, 0x4f, + 0x9e, 0x48, 0x78, 0xd0, 0x5e, 0x78, 0x51, 0x0f, 0x1e, 0x4a, 0xaa, + 0x80, 0x96, 0x22, 0x68, 0xeb, 0xc1, 0x39, 0x74, 0x93, 0xc9, 0x4e, + 0x76, 0x76, 0x33, 0xb3, 0xb3, 0x7d, 0x3d, 0xd6, 0x8d, 0xff, 0x5a, + 0xa1, 0x60, 0x83, 0x21, 0xfc, 0x16, 0x9c, 0xd1, 0x65, 0xe7, 0x19, + 0xe5, 0x1e, 0xe1, 0x13, 0x07, 0xcc, 0xb0, 0xc5, 0x05, 0x3f, 0xc1, + 0x0a, 0x5f, 0xc1, 0x22, 0xfb, 0x55, 0x8b, 0xb7, 0x1c, 0x16, 0x8c, + 0x68, 0xe2, 0xda, 0xa2, 0x0f, 0xef, 0x92, 0x6a, 0x81, 0x35, 0xca, + 0x11, 0xd7, 0x38, 0x8d, 0xe9, 0x4f, 0x71, 0xbf, 0x61, 0x99, 0xe3, + 0x6f, 0x54, 0xf8, 0x8d, 0x73, 0x39, 0xe1, 0x9e, 0xe1, 0x2e, 0xb1, + 0xde, 0xf1, 0x8a, 0x07, 0x7c, 0x4c, 0x22, 0xcf, 0x93, 0x6a, 0x40, + 0x55, 0x62, 0xfd, 0x18, 0x61, 0x98, 0xfc, 0xf5, 0x92, 0xde, 0x45, + 0xeb, 0x27, 0xfc, 0x0f, 0x08, 0x4c, 0x30, 0x03, 0xe4, 0x95, 0x23, + 0xfb, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, + 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, + 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, + 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, + 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, + 0x82 ), + 14, 6, + DATA ( 0x858585, 0x6f6f6f, 0x6f6f6f, 0x777777, 0x7b7b7b, 0x8f8f8f, + 0x8d8d8d, 0x919191, 0x8b8b8b, 0x858585, 0x777777, 0x6c6c6c, + 0x747474, 0x898989, 0x808080, 0x696969, 0x5c5c5c, 0x474747, + 0x484848, 0x696969, 0x5f5f5f, 0x5b5b5b, 0x575757, 0x5f5f5f, + 0x535353, 0x474747, 0x4d4d4d, 0x6e6e6e, 0x6d6d6d, 0x4f4f4f, + 0x4f4f4f, 0x4b4b4b, 0x474747, 0x535353, 0x737373, 0x484848, + 0x4e4e4e, 0x737373, 0x484848, 0x474747, 0x535353, 0x7a7a7a, + 0x5d5d5d, 0x474747, 0x484848, 0x474747, 0x484848, 0x666666, + 0x5e5e5e, 0x424242, 0x4f4f4f, 0x6a6a6a, 0x414141, 0x434343, + 0x505050, 0x6e6e6e, 0x4e4e4e, 0x424242, 0x444444, 0x686868, + 0x707070, 0x5e5e5e, 0x404040, 0x454545, 0x3e3e3e, 0x4b4b4b, + 0x3d3d3d, 0x404040, 0x545454, 0x6c6c6c, 0x525252, 0x4e4e4e, + 0x4f4f4f, 0x6b6b6b, 0x6e6e6e, 0x5a5a5a, 0x484848, 0x606060, + 0x464646, 0x404040, 0x404040, 0x373737, 0x494949, 0x6f6f6f ) ); + +/* Colour type 4, bit depth 8 */ +PIX ( ctype_4_8, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x04, 0x00, 0x00, 0x00, 0x59, 0x12, 0x67, 0x37, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x01, 0x86, + 0xa0, 0x31, 0xe8, 0x96, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, + 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x72, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x05, 0xc1, 0xbb, 0x0e, 0x82, + 0x30, 0x00, 0x00, 0xc0, 0xa3, 0x54, 0x6d, 0x0c, 0x9b, 0xb8, 0xb9, + 0x18, 0xbf, 0xd5, 0x1f, 0x75, 0x70, 0xf0, 0x15, 0x1f, 0x20, 0xa6, + 0x56, 0xf0, 0xae, 0xda, 0x4f, 0x27, 0x24, 0x51, 0x6b, 0x14, 0x65, + 0xd9, 0x53, 0x2f, 0x59, 0x8b, 0x5f, 0xd9, 0xcb, 0x05, 0x5b, 0x6f, + 0x45, 0x91, 0x74, 0x3a, 0x0b, 0x59, 0xb8, 0x3a, 0xea, 0xd4, 0x26, + 0x27, 0xad, 0x9b, 0x41, 0xeb, 0x8d, 0xb9, 0x46, 0xbc, 0xfb, 0x08, + 0x46, 0x95, 0x95, 0xb3, 0x6c, 0x6e, 0xf0, 0x11, 0x14, 0x9d, 0xf8, + 0xf0, 0x55, 0xdb, 0x49, 0x6e, 0x0e, 0x66, 0xee, 0x8a, 0x9f, 0x49, + 0x34, 0x0a, 0x51, 0x63, 0xa9, 0x36, 0x2a, 0x92, 0x8d, 0x85, 0x5e, + 0x30, 0xe8, 0xd5, 0xfe, 0x3c, 0xbb, 0x2f, 0xff, 0xe5, 0xd1, 0x65, + 0x25, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, + 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, + 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, + 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, + 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, + 0x82 ), + 14, 6, + DATA ( 0x858585, 0x6f6f6f, 0x6f6f6f, 0x777777, 0x7b7b7b, 0x8f8f8f, + 0x8d8d8d, 0x919191, 0x8b8b8b, 0x858585, 0x777777, 0x6c6c6c, + 0x747474, 0x898989, 0x808080, 0x696969, 0x5c5c5c, 0x484848, + 0x484848, 0x696969, 0x5f5f5f, 0x5b5b5b, 0x575757, 0x5f5f5f, + 0x535353, 0x474747, 0x4e4e4e, 0x6e6e6e, 0x6d6d6d, 0x4f4f4f, + 0x505050, 0x4b4b4b, 0x474747, 0x535353, 0x737373, 0x494949, + 0x4e4e4e, 0x737373, 0x494949, 0x474747, 0x545454, 0x7a7a7a, + 0x5d5d5d, 0x474747, 0x494949, 0x474747, 0x484848, 0x666666, + 0x5e5e5e, 0x434343, 0x4f4f4f, 0x6a6a6a, 0x414141, 0x434343, + 0x505050, 0x6e6e6e, 0x4e4e4e, 0x424242, 0x454545, 0x686868, + 0x707070, 0x5e5e5e, 0x404040, 0x454545, 0x3f3f3f, 0x4b4b4b, + 0x3e3e3e, 0x404040, 0x545454, 0x6c6c6c, 0x525252, 0x4e4e4e, + 0x4f4f4f, 0x6b6b6b, 0x6e6e6e, 0x5a5a5a, 0x484848, 0x616161, + 0x464646, 0x404040, 0x404040, 0x373737, 0x494949, 0x6f6f6f ) ); + +/* Colour type 6, bit depth 16 */ +PIX ( ctype_6_16, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x10, 0x06, 0x00, 0x00, 0x00, 0xa3, 0x8b, 0x73, 0xff, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x06, + 0x62, 0x4b, 0x47, 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x09, + 0x58, 0xf7, 0xdc, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, + 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, + 0x9c, 0x18, 0x00, 0x00, 0x01, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x28, + 0xcf, 0x4d, 0xd0, 0x31, 0x6e, 0xd3, 0x00, 0x00, 0x85, 0xe1, 0x2f, + 0x76, 0xac, 0x90, 0xb4, 0x8d, 0x92, 0xd0, 0x14, 0x15, 0x41, 0x84, + 0x2a, 0x24, 0x86, 0x0e, 0x2c, 0x14, 0x01, 0x1b, 0x1b, 0x1b, 0xc7, + 0xe0, 0x1a, 0xb9, 0x01, 0x67, 0xe1, 0x10, 0xa8, 0x52, 0xc5, 0x00, + 0x02, 0x01, 0x19, 0x68, 0x41, 0xad, 0x1a, 0x10, 0x4d, 0xec, 0xb8, + 0x4e, 0x93, 0x58, 0x4e, 0xcc, 0xe2, 0x81, 0xf5, 0x0d, 0xef, 0xfd, + 0xef, 0xaf, 0xbd, 0x1d, 0xbe, 0x1f, 0x6e, 0x86, 0xe5, 0x70, 0xdf, + 0xd8, 0x08, 0xa1, 0x52, 0x81, 0xd4, 0xb6, 0x0e, 0x4a, 0x75, 0x11, + 0x36, 0x3a, 0xfa, 0x68, 0x2b, 0x5c, 0x83, 0x50, 0x84, 0xa5, 0xb5, + 0x1a, 0x4a, 0x85, 0x05, 0x12, 0x37, 0x42, 0x34, 0x65, 0x62, 0xdc, + 0xd2, 0x50, 0xa2, 0xa6, 0xa7, 0x87, 0x7a, 0x6e, 0xad, 0x44, 0xa1, + 0x90, 0xa3, 0xe7, 0x8f, 0x53, 0x1c, 0xf8, 0xe2, 0x04, 0xb9, 0x86, + 0x26, 0xce, 0xbc, 0xf0, 0x1a, 0x6d, 0x89, 0x4b, 0xec, 0x98, 0x4b, + 0x50, 0x58, 0x5b, 0x23, 0xad, 0x80, 0xee, 0x88, 0x25, 0x68, 0xbb, + 0xf0, 0x03, 0x0b, 0x5d, 0x7d, 0xc4, 0x1e, 0x3b, 0x42, 0x90, 0x8b, + 0x65, 0xb8, 0x6d, 0xe4, 0x23, 0x02, 0x53, 0x57, 0x98, 0xd8, 0x75, + 0x1f, 0x73, 0x91, 0x2d, 0x94, 0x7e, 0x1b, 0xe3, 0xbb, 0x07, 0x9e, + 0x62, 0xc7, 0xc8, 0x27, 0x94, 0x32, 0xd7, 0x55, 0xfe, 0x04, 0x6d, + 0x63, 0x67, 0x58, 0x89, 0xb4, 0x30, 0xd1, 0x75, 0x0f, 0xe7, 0xba, + 0x1e, 0x22, 0x20, 0x31, 0x43, 0x20, 0x95, 0x21, 0x94, 0x9a, 0x63, + 0x4b, 0x6a, 0x8a, 0x89, 0x6d, 0x77, 0xf1, 0xd5, 0xc0, 0x73, 0xac, + 0xfd, 0x15, 0x57, 0x43, 0x19, 0x62, 0x4d, 0xbb, 0x58, 0x5a, 0x29, + 0xb0, 0xb2, 0x94, 0xe3, 0x42, 0xcb, 0x1e, 0x66, 0x6a, 0x1a, 0x48, + 0x2d, 0x40, 0xbd, 0xeb, 0xca, 0x2f, 0x2c, 0x15, 0x02, 0x14, 0x02, + 0x11, 0x8e, 0xbd, 0xf4, 0xe6, 0xbf, 0xc2, 0x4d, 0xa5, 0xea, 0xd0, + 0xb1, 0x77, 0x38, 0xf1, 0xc8, 0x2b, 0xf4, 0x5d, 0x3a, 0xc5, 0xbe, + 0xd0, 0x07, 0x44, 0xd5, 0xe3, 0xa5, 0x9e, 0x00, 0x89, 0x96, 0x2e, + 0xe6, 0x88, 0x50, 0x8f, 0x35, 0x75, 0xb0, 0xa8, 0x94, 0x94, 0x6a, + 0x02, 0x4c, 0x45, 0x3a, 0x60, 0x03, 0xda, 0x72, 0x19, 0x46, 0x06, + 0x8e, 0xf0, 0xcd, 0x81, 0x67, 0xd8, 0xf3, 0xd3, 0x67, 0x34, 0x2d, + 0x4c, 0x10, 0x1a, 0x38, 0xc4, 0x5a, 0x66, 0x86, 0x1b, 0x73, 0x39, + 0x36, 0x42, 0x75, 0xfc, 0x03, 0x3f, 0x65, 0x8d, 0x8a, 0xc6, 0x64, + 0x55, 0xda, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, + 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, + 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Colour type 6, bit depth 8 */ +PIX ( ctype_6_8, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x06, 0x00, 0x00, 0x00, 0xf3, 0x1b, 0xaf, 0xbc, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x06, + 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0, + 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, + 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, + 0x9c, 0x18, 0x00, 0x00, 0x01, 0x23, 0x49, 0x44, 0x41, 0x54, 0x18, + 0xd3, 0x05, 0xc1, 0x4d, 0x4e, 0xc2, 0x40, 0x00, 0x80, 0xd1, 0xaf, + 0x7f, 0xc1, 0x22, 0x36, 0x2d, 0x02, 0x06, 0xa3, 0x84, 0x10, 0x13, + 0x17, 0x2e, 0xdc, 0x80, 0x51, 0x77, 0xee, 0xdc, 0x79, 0x0c, 0x8f, + 0xe3, 0x59, 0x3c, 0x84, 0x31, 0x21, 0x2e, 0x34, 0x1a, 0x95, 0x85, + 0xa8, 0x91, 0x88, 0x46, 0x60, 0x4a, 0x99, 0xd2, 0xd2, 0x4c, 0x3b, + 0xbe, 0x67, 0x5c, 0xdd, 0x14, 0xba, 0x39, 0x1e, 0x60, 0x69, 0x45, + 0x54, 0xf1, 0xd1, 0xb6, 0x43, 0xe1, 0xd7, 0xf1, 0xd4, 0x02, 0x2c, + 0x87, 0x34, 0x37, 0xd0, 0x2a, 0x21, 0x5c, 0x5a, 0xb8, 0x52, 0xb0, + 0x56, 0xd2, 0x18, 0xd5, 0x2a, 0x76, 0x96, 0x6b, 0x94, 0xca, 0xa8, + 0xfe, 0x0e, 0xe9, 0x3c, 0xf5, 0xc9, 0x4a, 0x2e, 0xef, 0xa7, 0x17, + 0x78, 0xe1, 0x37, 0x1b, 0x71, 0x88, 0xca, 0x73, 0x22, 0xbf, 0xce, + 0x96, 0x08, 0xf1, 0x46, 0x6f, 0x24, 0x41, 0x1d, 0x71, 0xd8, 0xc3, + 0xcc, 0x84, 0x64, 0x73, 0x70, 0x8f, 0x39, 0x9b, 0x30, 0xad, 0xed, + 0x12, 0x3b, 0xeb, 0xe8, 0x9f, 0x31, 0xaf, 0xed, 0x23, 0x36, 0x06, + 0x0f, 0x68, 0xb9, 0xe0, 0xb5, 0xdd, 0xc5, 0x1b, 0xbf, 0xb3, 0x72, + 0xca, 0x4c, 0x83, 0x1d, 0xbe, 0x82, 0x3d, 0x4c, 0xc2, 0x39, 0x66, + 0x24, 0xb1, 0xa2, 0x98, 0xf5, 0x68, 0xc6, 0xb4, 0xb2, 0xcd, 0x73, + 0xeb, 0x84, 0xfc, 0x4f, 0xa0, 0xa5, 0x44, 0xb8, 0x35, 0xd2, 0x95, + 0x62, 0x95, 0x66, 0x8c, 0xca, 0x0d, 0xe6, 0x46, 0x89, 0x28, 0x01, + 0x3b, 0x98, 0x7c, 0x92, 0x2a, 0x13, 0x65, 0x3a, 0xdc, 0x9e, 0x5d, + 0x22, 0xdc, 0x1a, 0x85, 0x08, 0x39, 0xb8, 0xbd, 0xa6, 0xbf, 0x7f, + 0x4e, 0xfd, 0x7b, 0x48, 0xd3, 0xba, 0xc3, 0x91, 0x0b, 0xd2, 0xaa, + 0x49, 0x58, 0x0e, 0x88, 0x71, 0xb0, 0x85, 0xeb, 0x93, 0xb4, 0xbb, + 0x68, 0xc3, 0x64, 0xe6, 0xf8, 0x50, 0x80, 0x97, 0x49, 0x06, 0xad, + 0x1e, 0x2f, 0x9d, 0x63, 0x1a, 0x1f, 0x8f, 0xb8, 0xc9, 0x14, 0xab, + 0x75, 0x40, 0x2e, 0xe7, 0x2c, 0xe3, 0x8c, 0xc2, 0xb2, 0xf9, 0x07, + 0xb2, 0x82, 0x8b, 0x8a, 0x51, 0x8a, 0xfe, 0x2f, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, + 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, + 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, + 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, + 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Filter method 0 */ +PIX ( filter_0, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x62, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x60, 0x60, 0x64, 0x62, 0x66, 0x61, 0x65, 0x63, 0xe7, 0xe0, 0xe4, + 0xe2, 0xe6, 0xe1, 0x65, 0xe0, 0xe3, 0x17, 0x10, 0x14, 0x12, 0x16, + 0x11, 0x15, 0x13, 0x97, 0x90, 0x94, 0x92, 0x66, 0x90, 0x91, 0x95, + 0x93, 0x57, 0x50, 0x54, 0x52, 0x56, 0x51, 0x55, 0x53, 0xd7, 0xd0, + 0x64, 0xd0, 0xd2, 0xd6, 0xd1, 0xd5, 0xd3, 0x37, 0x30, 0x34, 0x32, + 0x36, 0x31, 0x35, 0x33, 0x67, 0xb0, 0xb0, 0xb4, 0xb2, 0xb6, 0xb1, + 0xb5, 0xb3, 0x77, 0x70, 0x74, 0x72, 0x76, 0x71, 0x65, 0x70, 0x73, + 0xf7, 0xf0, 0xf4, 0xf2, 0xf6, 0xf1, 0xf5, 0xf3, 0x0f, 0x08, 0x0c, + 0x0a, 0x06, 0x00, 0x96, 0xe0, 0x0d, 0x9f, 0x37, 0x73, 0x30, 0xa4, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, + 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, + 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Filter method 1 */ +PIX ( filter_1, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x1b, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x64, 0x60, 0x44, 0x01, 0x7c, 0xa8, 0x5c, 0x19, 0x54, 0xae, 0x16, + 0x2a, 0xd7, 0x02, 0x95, 0xeb, 0x86, 0xc2, 0x03, 0x00, 0x2b, 0x08, + 0x01, 0x27, 0x21, 0x1c, 0x62, 0x0d, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Filter method 2 */ +PIX ( filter_2, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x62, 0x60, 0x64, 0x62, 0x66, 0x61, 0x65, 0x63, 0xe7, 0xe0, 0xe4, + 0xe2, 0xe6, 0xe1, 0x65, 0xe2, 0x43, 0x01, 0x94, 0x70, 0x01, 0xae, + 0xce, 0x04, 0x3c, 0x32, 0x9e, 0x82, 0x4f, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, + 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, + 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, + 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, + 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Filter method 3 */ +PIX ( filter_3, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x28, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x66, 0x60, 0x64, 0x62, 0x62, 0x66, 0x66, 0x61, 0x61, 0x65, 0x65, + 0x63, 0x63, 0x67, 0x67, 0xe6, 0xe3, 0x40, 0x06, 0xcc, 0xa2, 0xa8, + 0x5c, 0x19, 0x54, 0xae, 0x32, 0x2a, 0x57, 0x0b, 0x85, 0x0b, 0x00, + 0x74, 0x6c, 0x02, 0xde, 0x3a, 0xf5, 0xbf, 0x99, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, + 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, + 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, + 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, + 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, + 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Filter method 4 */ +PIX ( filter_4, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x11, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x61, 0x60, 0x44, 0x06, 0x2c, 0x7c, 0x54, 0xe3, 0x02, 0x00, 0x1e, + 0xdd, 0x00, 0xad, 0x19, 0xa1, 0xfb, 0x47, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, + 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, + 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, + 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, + 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Interlaced */ +PIX ( interlaced, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x01, 0xb3, 0xc2, 0x6f, 0x18, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x68, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, + 0x60, 0xe0, 0x60, 0x60, 0xe1, 0x61, 0xb0, 0xb0, 0x71, 0x70, 0x61, + 0x60, 0x62, 0xe3, 0x62, 0xb0, 0xb2, 0x73, 0x62, 0x90, 0x91, 0x53, + 0x50, 0x52, 0x51, 0xd3, 0x60, 0x60, 0x64, 0x66, 0x65, 0xe7, 0xe4, + 0xe6, 0x65, 0x90, 0x95, 0x57, 0x54, 0x56, 0x55, 0xd7, 0x64, 0xb0, + 0xb4, 0xb6, 0xb5, 0x77, 0x74, 0x76, 0x65, 0xe0, 0xe3, 0x17, 0x10, + 0x14, 0x12, 0x16, 0x11, 0x15, 0x13, 0x97, 0x90, 0x94, 0x92, 0x66, + 0xd0, 0xd2, 0xd6, 0xd1, 0xd5, 0xd3, 0x37, 0x30, 0x34, 0x32, 0x36, + 0x31, 0x35, 0x33, 0x67, 0x70, 0x73, 0xf7, 0xf0, 0xf4, 0xf2, 0xf6, + 0xf1, 0xf5, 0xf3, 0x0f, 0x08, 0x0c, 0x0a, 0x06, 0x00, 0xf9, 0xc2, + 0x0d, 0x9f, 0x36, 0xdc, 0x4b, 0x87, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Interlaced (height 1) */ +PIX ( interlaced_h1, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x04, 0x03, 0x00, 0x00, 0x01, 0x66, 0x29, 0xc2, 0xe6, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x1b, + 0x50, 0x4c, 0x54, 0x45, 0x9a, 0x9a, 0xcd, 0xae, 0x88, 0xae, 0x9f, + 0x94, 0xc3, 0x9a, 0x9d, 0xcf, 0xab, 0x8a, 0xb3, 0xa2, 0x91, 0xbb, + 0xa9, 0x7f, 0xa6, 0x93, 0xa4, 0xd7, 0xff, 0xff, 0xff, 0x01, 0x68, + 0x32, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x08, + 0x86, 0xde, 0x95, 0x7a, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, + 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, + 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x11, 0x49, 0x44, 0x41, 0x54, + 0x08, 0xd7, 0x63, 0x60, 0x60, 0x70, 0x60, 0x50, 0x63, 0x10, 0x0e, + 0x07, 0x00, 0x02, 0x9e, 0x00, 0xd1, 0x1a, 0x21, 0xdf, 0x5d, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, + 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, + 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, + 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, + 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, + 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, + 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 8, 1, + DATA ( 0x9a9acd, 0xae88ae, 0x9f94c3, 0x9a9dcf, 0xab8ab3, 0xa291bb, + 0xa97fa6, 0x93a4d7, ) ); + +/* Interlaced (height 2) */ +PIX ( interlaced_h2, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x02, 0x08, 0x03, 0x00, 0x00, 0x01, 0x25, 0x4d, 0x5d, 0x49, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x33, + 0x50, 0x4c, 0x54, 0x45, 0x9b, 0xa9, 0xda, 0xb7, 0x8b, 0xab, 0xb1, + 0x8b, 0xae, 0xa4, 0xa6, 0xd2, 0xb7, 0x94, 0xb5, 0xa7, 0x9e, 0xc5, + 0xb0, 0x86, 0xab, 0xa2, 0xa5, 0xd0, 0x99, 0x8b, 0xbe, 0xa7, 0x82, + 0xae, 0x8e, 0x9b, 0xd5, 0x90, 0x92, 0xcb, 0xa0, 0x7e, 0xad, 0x9e, + 0x82, 0xae, 0xa4, 0x76, 0x9f, 0x85, 0xa2, 0xde, 0xff, 0xff, 0xff, + 0xf3, 0x35, 0x13, 0x79, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, + 0x44, 0x10, 0x95, 0xb2, 0x0d, 0x2c, 0x00, 0x00, 0x00, 0x09, 0x70, + 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, + 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x1d, 0x49, 0x44, + 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x60, 0x60, 0x61, 0x60, 0x62, + 0x63, 0x60, 0x64, 0x66, 0x65, 0x67, 0xe0, 0xe0, 0xe4, 0xe2, 0xe6, + 0xe1, 0xe5, 0xe3, 0x07, 0x00, 0x02, 0xf9, 0x00, 0x79, 0x11, 0xe8, + 0xb8, 0x97, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, + 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, + 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 ), + 8, 2, + DATA ( 0x9ba9da, 0xb78bab, 0xb18bae, 0xa4a6d2, 0xb794b5, 0xa79ec5, + 0xb086ab, 0xa2a5d0, 0x998bbe, 0xa782ae, 0x8e9bd5, 0x9092cb, + 0xa07ead, 0x9e82ae, 0xa4769f, 0x85a2de, ) ); + +/* Interlaced (height 3) */ +PIX ( interlaced_h3, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x03, 0x08, 0x03, 0x00, 0x00, 0x01, 0xee, 0x11, 0x8e, 0xec, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x4b, + 0x50, 0x4c, 0x54, 0x45, 0x99, 0xb4, 0xe6, 0xb3, 0x97, 0xb9, 0xb1, + 0x95, 0xb7, 0xa9, 0xaf, 0xd7, 0xb4, 0xa4, 0xc7, 0xa8, 0xa6, 0xce, + 0xad, 0x90, 0xb7, 0xa8, 0xa8, 0xcf, 0x9d, 0x94, 0xc5, 0xbc, 0x78, + 0x97, 0xac, 0x81, 0xa8, 0x9a, 0x98, 0xca, 0xb9, 0x79, 0x99, 0xa5, + 0x8f, 0xb6, 0xb1, 0x76, 0x9a, 0x94, 0xa1, 0xd4, 0x96, 0x87, 0xbc, + 0x9a, 0x8a, 0xbe, 0x7d, 0xaa, 0xef, 0x8c, 0x8f, 0xcc, 0x91, 0x83, + 0xbc, 0x9b, 0x7c, 0xaa, 0x9c, 0x76, 0xa2, 0x7d, 0xa3, 0xe2, 0xff, + 0xff, 0xff, 0x53, 0xa1, 0xdb, 0xb9, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x4b, 0x47, 0x44, 0x18, 0x9b, 0x69, 0x85, 0x1e, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x26, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x05, 0xc1, 0x85, 0x01, 0x00, + 0x20, 0x00, 0xc0, 0xa0, 0xd9, 0xdd, 0xf5, 0xff, 0xa7, 0x02, 0xa0, + 0x91, 0x96, 0x3e, 0xf7, 0x45, 0x28, 0xe3, 0x18, 0xeb, 0x3c, 0x7c, + 0x88, 0x29, 0x97, 0xda, 0x3e, 0x0d, 0xb1, 0x01, 0x15, 0x29, 0x54, + 0xbc, 0x10, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, + 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, + 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, + 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, 0xde, + 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82 ), + 8, 3, + DATA ( 0x99b4e6, 0xb397b9, 0xb195b7, 0xa9afd7, 0xb4a4c7, 0xa8a6ce, + 0xad90b7, 0xa8a8cf, 0x9d94c5, 0xbc7897, 0xac81a8, 0x9a98ca, + 0xb97999, 0xa58fb6, 0xb1769a, 0x94a1d4, 0x9687bc, 0x9a8abe, + 0x7daaef, 0x8c8fcc, 0x9183bc, 0x9b7caa, 0x9c76a2, 0x7da3e2 ) ); + +/* Interlaced (height 4) */ +PIX ( interlaced_h4, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x04, 0x08, 0x03, 0x00, 0x00, 0x01, 0xf3, 0x14, 0xbe, 0x54, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x63, + 0x50, 0x4c, 0x54, 0x45, 0x99, 0xb8, 0xea, 0xaf, 0xa0, 0xc4, 0xab, + 0xa1, 0xc7, 0xa8, 0xb7, 0xe0, 0xaf, 0xb1, 0xd7, 0xa5, 0xae, 0xd7, + 0xa6, 0x9b, 0xc5, 0xa8, 0xad, 0xd3, 0x9a, 0xa3, 0xd4, 0xbd, 0x7e, + 0x9b, 0xbb, 0x77, 0x94, 0xa4, 0x9b, 0xc6, 0xbe, 0x80, 0x9d, 0xaa, + 0x93, 0xb9, 0xba, 0x76, 0x96, 0xa2, 0x9e, 0xca, 0x9f, 0x87, 0xb7, + 0xb7, 0x76, 0x99, 0x99, 0x91, 0xc5, 0x91, 0x94, 0xcc, 0xb1, 0x76, + 0x9a, 0xa2, 0x88, 0xb1, 0xa7, 0x77, 0x9f, 0x87, 0xa3, 0xde, 0x92, + 0x8a, 0xc1, 0x91, 0x91, 0xca, 0x77, 0xb0, 0xf8, 0x8a, 0x8f, 0xce, + 0x87, 0x89, 0xc8, 0x97, 0x7a, 0xaa, 0x99, 0x76, 0xa3, 0x7b, 0xa2, + 0xe3, 0xff, 0xff, 0xff, 0xfa, 0x09, 0xb4, 0x8e, 0x00, 0x00, 0x00, + 0x01, 0x62, 0x4b, 0x47, 0x44, 0x20, 0xb3, 0x6b, 0x3d, 0x80, 0x00, + 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, + 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, + 0x00, 0x30, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x60, + 0x60, 0x61, 0x60, 0x62, 0x63, 0x10, 0x10, 0x12, 0x11, 0x63, 0x60, + 0x64, 0x66, 0x65, 0x67, 0x10, 0x14, 0x16, 0x15, 0x67, 0xe0, 0xe0, + 0xe4, 0xe2, 0xe6, 0xe1, 0xe5, 0xe3, 0x67, 0x90, 0x90, 0x94, 0x92, + 0x96, 0x91, 0x95, 0x93, 0x07, 0x00, 0x1b, 0x22, 0x01, 0xf1, 0x69, + 0x98, 0xfa, 0x95, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, + 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, + 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, + 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, 0x00, + 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, + 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, + 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, + 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, 0xe9, + 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 ), + 8, 4, + DATA ( 0x99b8ea, 0xafa0c4, 0xaba1c7, 0xa8b7e0, 0xafb1d7, 0xa5aed7, + 0xa69bc5, 0xa8add3, 0x9aa3d4, 0xbd7e9b, 0xbb7794, 0xa49bc6, + 0xbe809d, 0xaa93b9, 0xba7696, 0xa29eca, 0x9f87b7, 0xb77699, + 0x9991c5, 0x9194cc, 0xb1769a, 0xa288b1, 0xa7779f, 0x87a3de, + 0x928ac1, 0x9191ca, 0x77b0f8, 0x8a8fce, 0x8789c8, 0x977aaa, + 0x9976a3, 0x7ba2e3, ) ); + +/* Interlaced (width 1) */ +PIX ( interlaced_w1, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x08, 0x04, 0x03, 0x00, 0x00, 0x01, 0xbd, 0x33, 0xb8, 0xe4, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x1b, + 0x50, 0x4c, 0x54, 0x45, 0x9f, 0xbd, 0xeb, 0xae, 0xa0, 0xc5, 0xb4, + 0x8a, 0xac, 0xac, 0x8a, 0xb0, 0xa5, 0x87, 0xb2, 0x9d, 0x86, 0xb6, + 0x90, 0x8c, 0xc3, 0x82, 0x93, 0xd3, 0xff, 0xff, 0xff, 0xac, 0xaf, + 0x93, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x08, + 0x86, 0xde, 0x95, 0x7a, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, + 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, + 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x18, 0x49, 0x44, 0x41, 0x54, + 0x08, 0xd7, 0x63, 0x60, 0x60, 0x70, 0x60, 0x50, 0x60, 0x48, 0x60, + 0x10, 0x60, 0x30, 0x60, 0x08, 0x60, 0x28, 0x00, 0x00, 0x0a, 0xd0, + 0x01, 0xc1, 0x05, 0xa2, 0x99, 0xc6, 0x00, 0x00, 0x00, 0x25, 0x74, + 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, + 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, + 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, + 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, + 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, + 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, + 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 1, 8, + DATA ( 0x9fbdeb, 0xaea0c5, 0xb48aac, 0xac8ab0, 0xa587b2, 0x9d86b6, + 0x908cc3, 0x8293d3, ) ); + +/* Interlaced (width 2) */ +PIX ( interlaced_w2, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x01, 0x93, 0xf4, 0xee, 0xe6, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x33, + 0x50, 0x4c, 0x54, 0x45, 0xa0, 0xbc, 0xe9, 0x9e, 0xbe, 0xec, 0xad, + 0xa1, 0xc7, 0xaf, 0x9e, 0xc2, 0xb4, 0x8b, 0xad, 0xb6, 0x88, 0xa9, + 0xae, 0x87, 0xac, 0xac, 0x8b, 0xb1, 0xa9, 0x83, 0xad, 0xa1, 0x8a, + 0xb6, 0x9e, 0x87, 0xb8, 0x9d, 0x84, 0xb3, 0x8e, 0x92, 0xcc, 0x92, + 0x85, 0xba, 0x80, 0x9b, 0xde, 0x84, 0x8b, 0xc7, 0xff, 0xff, 0xff, + 0xa3, 0x2a, 0xf5, 0x35, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, + 0x44, 0x10, 0x95, 0xb2, 0x0d, 0x2c, 0x00, 0x00, 0x00, 0x09, 0x70, + 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, + 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x20, 0x49, 0x44, + 0x41, 0x54, 0x08, 0xd7, 0x05, 0xc1, 0x05, 0x01, 0x00, 0x20, 0x00, + 0x00, 0x20, 0xec, 0xd6, 0xff, 0x6f, 0x05, 0x74, 0xd9, 0x16, 0x14, + 0xc3, 0x11, 0x93, 0xda, 0xcc, 0xe5, 0xbe, 0x0f, 0x04, 0xf2, 0x00, + 0x79, 0x83, 0x54, 0x1a, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, + 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, + 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, + 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, + 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, + 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, + 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, + 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, + 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, + 0x44, 0xae, 0x42, 0x60, 0x82 ), + 2, 8, + DATA ( 0xa0bce9, 0x9ebeec, 0xada1c7, 0xaf9ec2, 0xb48bad, 0xb688a9, + 0xae87ac, 0xac8bb1, 0xa983ad, 0xa18ab6, 0x9e87b8, 0x9d84b3, + 0x8e92cc, 0x9285ba, 0x809bde, 0x848bc7, ) ); + +/* Interlaced (width 3) */ +PIX ( interlaced_w3, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x01, 0x7c, 0x36, 0x85, 0xd8, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x4b, + 0x50, 0x4c, 0x54, 0x45, 0xa0, 0xb7, 0xe4, 0xa1, 0xc4, 0xf1, 0x9c, + 0xba, 0xe9, 0xab, 0xa0, 0xc7, 0xb1, 0xa1, 0xc5, 0xae, 0x9b, 0xc0, + 0xb1, 0x8d, 0xb0, 0xb8, 0x88, 0xa8, 0xb5, 0x87, 0xa9, 0xae, 0x86, + 0xab, 0xae, 0x88, 0xad, 0xaa, 0x8c, 0xb4, 0xac, 0x80, 0xa9, 0xa5, + 0x88, 0xb2, 0x9f, 0x8b, 0xb7, 0xa0, 0x88, 0xb8, 0x9e, 0x84, 0xb5, + 0x9c, 0x85, 0xb4, 0x8f, 0x94, 0xce, 0x8f, 0x8a, 0xc4, 0x93, 0x84, + 0xb6, 0x81, 0x9d, 0xdf, 0x7e, 0x95, 0xd8, 0x88, 0x86, 0xbe, 0xff, + 0xff, 0xff, 0xef, 0xfb, 0x85, 0x9c, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x4b, 0x47, 0x44, 0x18, 0x9b, 0x69, 0x85, 0x1e, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, + 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x28, + 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x05, 0xc1, 0x85, 0x01, 0x00, + 0x20, 0x00, 0xc0, 0xa0, 0xd9, 0xdd, 0xf5, 0xff, 0xa7, 0x02, 0x90, + 0x91, 0x54, 0xac, 0x67, 0x6e, 0x04, 0x8e, 0xc2, 0x42, 0x69, 0x43, + 0x88, 0x89, 0xd6, 0x07, 0xe7, 0xbe, 0x0f, 0x0f, 0x68, 0x01, 0x15, + 0x06, 0x65, 0x37, 0x5a, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, + 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, + 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, 0x28, 0x00, 0x00, + 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, + 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x34, + 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, + 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xd3, + 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 ), + 3, 8, + DATA ( 0xa0b7e4, 0xa1c4f1, 0x9cbae9, 0xaba0c7, 0xb1a1c5, 0xae9bc0, + 0xb18db0, 0xb888a8, 0xb587a9, 0xae86ab, 0xae88ad, 0xaa8cb4, + 0xac80a9, 0xa588b2, 0x9f8bb7, 0xa088b8, 0x9e84b5, 0x9c85b4, + 0x8f94ce, 0x8f8ac4, 0x9384b6, 0x819ddf, 0x7e95d8, 0x8886be ) ); + +/* Interlaced (width 4) */ +PIX ( interlaced_w4, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x03, 0x00, 0x00, 0x01, 0x9e, 0xea, 0x9e, 0xa1, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0x63, + 0x50, 0x4c, 0x54, 0x45, 0xa0, 0xb4, 0xe1, 0xa1, 0xc1, 0xee, 0x9f, + 0xc3, 0xf1, 0x9b, 0xb8, 0xe6, 0xa8, 0xa3, 0xcc, 0xb2, 0x9d, 0xc1, + 0xb0, 0xa2, 0xc6, 0xad, 0x99, 0xbe, 0xae, 0x92, 0xb7, 0xb9, 0x84, + 0xa4, 0xb8, 0x89, 0xa9, 0xb4, 0x87, 0xa9, 0xae, 0x87, 0xac, 0xae, + 0x86, 0xab, 0xaf, 0x88, 0xac, 0xa8, 0x8d, 0xb7, 0xaf, 0x7e, 0xa5, + 0xa4, 0x88, 0xb5, 0xa8, 0x85, 0xad, 0x9c, 0x8d, 0xbc, 0xa6, 0x81, + 0xae, 0x94, 0x90, 0xc7, 0xa8, 0x79, 0xa2, 0x96, 0x8b, 0xbd, 0x94, + 0x8e, 0xc4, 0x85, 0x9b, 0xdb, 0x99, 0x7b, 0xac, 0x8f, 0x89, 0xbe, + 0x84, 0x99, 0xd9, 0x7c, 0xa1, 0xe8, 0x83, 0x87, 0xc5, 0x88, 0x89, + 0xbf, 0xff, 0xff, 0xff, 0xec, 0xf4, 0xb8, 0xe8, 0x00, 0x00, 0x00, + 0x01, 0x62, 0x4b, 0x47, 0x44, 0x20, 0xb3, 0x6b, 0x3d, 0x80, 0x00, + 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, + 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, + 0x00, 0x34, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x05, 0xc1, 0x09, + 0x02, 0x80, 0x10, 0x00, 0x00, 0xc1, 0x4d, 0x85, 0x0e, 0x8a, 0xa2, + 0xc3, 0xf5, 0xff, 0x5f, 0x9a, 0x01, 0x4e, 0x04, 0x1e, 0xbd, 0xf2, + 0xfe, 0x0c, 0x23, 0xcb, 0x86, 0xbb, 0xf8, 0x12, 0xd3, 0x2c, 0x15, + 0xbb, 0xb1, 0x07, 0x77, 0x88, 0x0f, 0xb9, 0xd4, 0xd6, 0x01, 0x21, + 0x30, 0x01, 0xf1, 0x50, 0x46, 0x7a, 0xbf, 0x00, 0x00, 0x00, 0x25, + 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x34, 0x2d, 0x30, + 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, 0x32, 0x3a, 0x34, 0x33, 0x3a, + 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0xa2, 0xb4, 0x66, + 0x28, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, + 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, + 0x30, 0x31, 0x34, 0x2d, 0x30, 0x31, 0x2d, 0x31, 0x32, 0x54, 0x32, + 0x32, 0x3a, 0x34, 0x33, 0x3a, 0x30, 0x33, 0x2b, 0x30, 0x31, 0x3a, + 0x30, 0x30, 0xd3, 0xe9, 0xde, 0x94, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 4, 8, + DATA ( 0xa0b4e1, 0xa1c1ee, 0x9fc3f1, 0x9bb8e6, 0xa8a3cc, 0xb29dc1, + 0xb0a2c6, 0xad99be, 0xae92b7, 0xb984a4, 0xb889a9, 0xb487a9, + 0xae87ac, 0xae86ab, 0xaf88ac, 0xa88db7, 0xaf7ea5, 0xa488b5, + 0xa885ad, 0x9c8dbc, 0xa681ae, 0x9490c7, 0xa879a2, 0x968bbd, + 0x948ec4, 0x859bdb, 0x997bac, 0x8f89be, 0x8499d9, 0x7ca1e8, + 0x8387c5, 0x8889bf, ) ); + +/* Multiple IDAT sections */ +PIX ( multi_idat, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x06, 0x08, 0x03, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0x5f, 0x8e, + 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, + 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, + 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x20, + 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a, 0x26, 0x00, 0x00, 0x80, + 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80, 0xe8, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a, 0x98, 0x00, + 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00, 0xff, + 0x50, 0x4c, 0x54, 0x45, 0x8f, 0xc5, 0xfe, 0xa8, 0xac, 0xd7, 0xab, + 0xab, 0xd3, 0x9d, 0xb7, 0xe3, 0x9c, 0xbb, 0xe8, 0x9a, 0xcb, 0xfd, + 0xa8, 0xc7, 0xf0, 0xa8, 0xca, 0xf5, 0xa0, 0xc7, 0xf6, 0x9f, 0xc3, + 0xed, 0x8f, 0xb9, 0xf0, 0x98, 0xad, 0xdf, 0xa0, 0xb4, 0xde, 0xa1, + 0xc6, 0xf0, 0x89, 0xc2, 0xfd, 0xa4, 0xa8, 0xd1, 0xba, 0x91, 0xaf, + 0xcd, 0x65, 0x79, 0xc7, 0x6c, 0x82, 0xa6, 0xa6, 0xd1, 0xb6, 0x96, + 0xb7, 0xc3, 0x8b, 0xa7, 0xbf, 0x88, 0xa4, 0xb1, 0x98, 0xb9, 0xb6, + 0x87, 0xa9, 0xc4, 0x6b, 0x86, 0xbb, 0x7c, 0x9b, 0xaa, 0xab, 0xd0, + 0x83, 0xb1, 0xf1, 0xb7, 0x81, 0xa1, 0xbc, 0x7f, 0x9b, 0xba, 0x79, + 0x96, 0xbc, 0x71, 0x8d, 0xa5, 0x8e, 0xb8, 0x8e, 0xb6, 0xed, 0xd0, + 0x64, 0x78, 0xbe, 0x7c, 0x97, 0x89, 0xb8, 0xed, 0xc4, 0x6e, 0x88, + 0xbd, 0x70, 0x90, 0xa8, 0x8d, 0xb7, 0x8d, 0xbc, 0xf4, 0x83, 0xa1, + 0xe2, 0xb9, 0x73, 0x95, 0xbf, 0x71, 0x90, 0xc5, 0x6b, 0x84, 0xa9, + 0x7d, 0xa7, 0x7b, 0xac, 0xf1, 0x8b, 0xa1, 0xdc, 0xcf, 0x58, 0x6c, + 0xad, 0x85, 0xab, 0x81, 0xb1, 0xe9, 0xbd, 0x66, 0x82, 0xa1, 0x7a, + 0xa6, 0x99, 0x8e, 0xbe, 0x7f, 0xb3, 0xf4, 0x94, 0x8d, 0xc3, 0xb1, + 0x6f, 0x97, 0xb5, 0x71, 0x95, 0x86, 0xac, 0xeb, 0x75, 0xb5, 0xff, + 0x73, 0xa4, 0xef, 0xb6, 0x68, 0x8d, 0x99, 0x7f, 0xb4, 0xae, 0x6b, + 0x92, 0x9a, 0x88, 0xb5, 0xc2, 0x5a, 0x75, 0x99, 0x78, 0xa8, 0x89, + 0x98, 0xcf, 0x74, 0xb3, 0xf9, 0x83, 0x96, 0xd3, 0x8b, 0x8f, 0xcb, + 0x8a, 0x90, 0xcd, 0x74, 0xb1, 0xfb, 0x74, 0xb3, 0xff, 0x81, 0x9e, + 0xe3, 0x8f, 0x86, 0xc2, 0x66, 0xa8, 0xfa, 0x7c, 0x88, 0xcd, 0x85, + 0x7f, 0xba, 0x9d, 0x78, 0xa0, 0x96, 0x6c, 0x99, 0x7f, 0x8d, 0xc9, + 0x72, 0xb6, 0xfd, 0xff, 0xff, 0xff, 0xdb, 0x2a, 0x9f, 0xad, 0x00, + 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x54, 0xe4, 0x03, 0x88, + 0xa5, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, + 0x0b, 0x13, 0x00, 0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, + 0x00, 0x00, 0x00, 0x07, 0x49, 0x44, 0x41, 0x54, 0x08, 0x5b, 0x63, + 0x64, 0x60, 0x44, 0x01, 0xdd, 0xe3, 0x71, 0x09, 0x00, 0x00, 0x00, + 0x07, 0x49, 0x44, 0x41, 0x54, 0x7c, 0x28, 0x3c, 0x16, 0x0a, 0xb8, + 0x00, 0xb9, 0x49, 0x1a, 0x82, 0x00, 0x00, 0x00, 0x04, 0x49, 0x44, + 0x41, 0x54, 0x1c, 0xee, 0x00, 0xa7, 0x1b, 0x22, 0xc4, 0xc1, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 ), + 14, 6, + DATA ( 0x8fc5fe, 0xa8acd7, 0xababd3, 0x9db7e3, 0x9cbbe8, 0x9acbfd, + 0xa8c7f0, 0xa8caf5, 0xa0c7f6, 0x9fc3ed, 0x8fb9f0, 0x98addf, + 0xa0b4de, 0xa1c6f0, 0x89c2fd, 0xa4a8d1, 0xba91af, 0xcd6579, + 0xc76c82, 0xa6a6d1, 0xb696b7, 0xc38ba7, 0xbf88a4, 0xb198b9, + 0xb687a9, 0xc46b86, 0xbb7c9b, 0xaaabd0, 0x83b1f1, 0xb781a1, + 0xbc7f9b, 0xba7996, 0xbc718d, 0xa58eb8, 0x8eb6ed, 0xd06478, + 0xbe7c97, 0x89b8ed, 0xc46e88, 0xbd7090, 0xa88db7, 0x8dbcf4, + 0x83a1e2, 0xb97395, 0xbf7190, 0xc56b84, 0xa97da7, 0x7bacf1, + 0x8ba1dc, 0xcf586c, 0xad85ab, 0x81b1e9, 0xbd6682, 0xa17aa6, + 0x998ebe, 0x7fb3f4, 0x948dc3, 0xb16f97, 0xb57195, 0x86aceb, + 0x75b5ff, 0x73a4ef, 0xb6688d, 0x997fb4, 0xae6b92, 0x9a88b5, + 0xc25a75, 0x9978a8, 0x8998cf, 0x74b3f9, 0x8396d3, 0x8b8fcb, + 0x8a90cd, 0x74b1fb, 0x74b3ff, 0x819ee3, 0x8f86c2, 0x66a8fa, + 0x7c88cd, 0x857fba, 0x9d78a0, 0x966c99, 0x7f8dc9, 0x72b6fd ) ); + +/* Original large image */ +PIX ( original, &png_image_type, + DATA ( 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x0c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x71, 0xdb, 0xdd, 0x0f, + 0x00, 0x00, 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, + 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b, + 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, + 0x49, 0x4d, 0x45, 0x07, 0xde, 0x01, 0x06, 0x10, 0x37, 0x03, 0xe9, + 0xc3, 0xf3, 0x6d, 0x00, 0x00, 0x00, 0x1d, 0x69, 0x54, 0x58, 0x74, + 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x64, 0x2e, 0x65, 0x07, + 0x00, 0x00, 0x04, 0x14, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x35, + 0xcd, 0x5d, 0x4c, 0x56, 0x65, 0x00, 0xc0, 0xf1, 0xff, 0xf3, 0x9c, + 0x6f, 0x10, 0x04, 0x14, 0x14, 0x03, 0x11, 0xc9, 0x8f, 0x54, 0x96, + 0x42, 0x5a, 0x2d, 0x5d, 0x19, 0xa6, 0x76, 0xd1, 0xec, 0xc6, 0x34, + 0x6b, 0xf3, 0xa3, 0x39, 0xb3, 0x69, 0x6b, 0x6b, 0xb3, 0xac, 0x95, + 0x5b, 0x8b, 0x5a, 0xb9, 0xd2, 0x0b, 0xaf, 0x32, 0xbd, 0xc0, 0xa5, + 0xd5, 0x85, 0xce, 0x69, 0xf8, 0xb1, 0x35, 0x96, 0x92, 0x3a, 0x33, + 0xdd, 0x50, 0xd4, 0xa5, 0x94, 0x86, 0x06, 0xa8, 0x7c, 0xc8, 0xfb, + 0xf2, 0xbe, 0xe7, 0x9c, 0xe7, 0x9c, 0xe7, 0xe9, 0xa2, 0x75, 0xf5, + 0xbb, 0xfc, 0x89, 0x9d, 0xed, 0xda, 0x08, 0x93, 0xe2, 0x49, 0x70, + 0x03, 0x9b, 0x54, 0x43, 0x12, 0x2b, 0x54, 0xa2, 0x71, 0x3d, 0x17, + 0x23, 0x04, 0x49, 0xa2, 0x29, 0xf0, 0x25, 0xd2, 0x80, 0x30, 0x9a, + 0x02, 0x5f, 0x20, 0xb5, 0x60, 0x24, 0x34, 0x24, 0x06, 0x6c, 0x0f, + 0x84, 0x05, 0xc3, 0x23, 0x8a, 0x5c, 0x5e, 0xa3, 0x8d, 0x8b, 0x6b, + 0x49, 0xd2, 0x44, 0x61, 0xd9, 0x8a, 0xb2, 0xb2, 0x00, 0x93, 0x6a, + 0xa2, 0x48, 0x62, 0x1b, 0x21, 0xd0, 0xa9, 0x26, 0xb2, 0x2c, 0xe6, + 0xef, 0xfe, 0x08, 0x30, 0xb4, 0xbf, 0xf1, 0x29, 0x39, 0x17, 0x42, + 0x09, 0xb6, 0x0b, 0x26, 0x94, 0x48, 0xa5, 0x09, 0x3c, 0x89, 0x52, + 0x20, 0x02, 0x81, 0x0f, 0x10, 0x19, 0x4c, 0xaa, 0xc9, 0x69, 0x0b, + 0xab, 0x48, 0x60, 0xa5, 0x2e, 0x22, 0x1f, 0x93, 0xb3, 0x24, 0x89, + 0x07, 0x56, 0xe0, 0x90, 0x0d, 0x1d, 0x1c, 0x0b, 0x02, 0xdf, 0x42, + 0x2a, 0x83, 0x1d, 0x27, 0x06, 0xd7, 0x76, 0xd0, 0x02, 0x12, 0xad, + 0xb1, 0x2c, 0x0b, 0x27, 0x97, 0xe5, 0xbd, 0x55, 0x93, 0xd1, 0x5e, + 0x80, 0xb2, 0x5c, 0x6e, 0x3d, 0xf1, 0x02, 0x27, 0xd7, 0x7c, 0x46, + 0x54, 0x5a, 0x42, 0xd1, 0x40, 0x1f, 0xcb, 0xd6, 0x2d, 0xa6, 0x67, + 0xde, 0x62, 0xce, 0x6e, 0xfa, 0x8a, 0x54, 0x6b, 0x1a, 0x5a, 0x3e, + 0x67, 0x76, 0xeb, 0x5e, 0x8e, 0x6e, 0x3b, 0x40, 0xb6, 0x6a, 0x0e, + 0x1b, 0xb7, 0x2d, 0xa5, 0xe2, 0xee, 0x75, 0xd0, 0x1a, 0x21, 0x04, + 0x26, 0xd5, 0x74, 0x37, 0x2c, 0xe4, 0xc4, 0xb6, 0x16, 0xec, 0x30, + 0x52, 0xb8, 0xae, 0x83, 0x46, 0x70, 0xf4, 0xcd, 0x66, 0xc6, 0x4a, + 0xa8, 0x6b, 0x3b, 0xc4, 0x50, 0x65, 0x1d, 0x47, 0x56, 0x37, 0xe3, + 0xa1, 0x59, 0xb2, 0xef, 0x63, 0x9e, 0xfc, 0x71, 0x3b, 0xa7, 0xd6, + 0x35, 0x23, 0xca, 0x2b, 0xe9, 0x7c, 0x7e, 0x15, 0xd3, 0xcf, 0x1d, + 0xc1, 0x7e, 0x38, 0xc0, 0x84, 0xae, 0x2b, 0xcc, 0x3e, 0xb6, 0x97, + 0xd6, 0xcd, 0x3b, 0xe8, 0x9d, 0x3e, 0x97, 0xc2, 0xbe, 0x07, 0xb8, + 0xe1, 0x08, 0x3f, 0x2f, 0xdb, 0xca, 0xed, 0x99, 0xcf, 0x62, 0x5b, + 0x9a, 0x34, 0xce, 0x23, 0xc6, 0x8f, 0xc5, 0x06, 0x64, 0x2e, 0x4c, + 0xc8, 0x8c, 0xc0, 0xb4, 0x4b, 0xc7, 0xd8, 0xb2, 0xa2, 0x8e, 0xfe, + 0x14, 0x26, 0x74, 0xb4, 0x33, 0x52, 0x36, 0x8e, 0xee, 0xba, 0x46, + 0x3a, 0xa6, 0xcc, 0x67, 0xa0, 0xbc, 0x86, 0xd1, 0xfd, 0x77, 0xc8, + 0x86, 0x29, 0x99, 0x1c, 0x9c, 0x5e, 0xbe, 0x15, 0x19, 0x87, 0x4c, + 0x39, 0xde, 0xc2, 0xc2, 0x1d, 0x6f, 0xd1, 0xfe, 0xda, 0x07, 0x5c, + 0x9d, 0xbb, 0x94, 0xa1, 0x4c, 0x44, 0x41, 0x38, 0xc8, 0xa8, 0xe1, + 0xfb, 0x9c, 0x99, 0xb7, 0x92, 0x9e, 0xda, 0xe9, 0xdc, 0xad, 0x99, + 0x41, 0xf7, 0xc4, 0xc7, 0xe9, 0x0d, 0xca, 0xc9, 0x47, 0x06, 0xdb, + 0x71, 0x7d, 0x32, 0x89, 0xa0, 0xec, 0xf2, 0x05, 0x6e, 0x34, 0x2e, + 0xc5, 0x0c, 0x19, 0x4a, 0xfe, 0xbe, 0x41, 0xcf, 0xd4, 0x46, 0xa2, + 0xb2, 0xd1, 0x54, 0x5d, 0x3c, 0xc7, 0x98, 0x9e, 0x2e, 0xce, 0x2f, + 0x5a, 0x4b, 0xa4, 0xc0, 0xa8, 0x98, 0xa2, 0xd1, 0x2e, 0xc7, 0x57, + 0x7f, 0xc1, 0x4b, 0xdf, 0xbc, 0xcd, 0xd5, 0x05, 0xcb, 0xb9, 0xd4, + 0xb4, 0x86, 0x28, 0x93, 0x25, 0x36, 0x1e, 0xc5, 0x37, 0xaf, 0xa0, + 0x2d, 0x8b, 0x95, 0x2d, 0x9b, 0xb1, 0x45, 0x8a, 0x30, 0x86, 0x7b, + 0x15, 0xb5, 0xb4, 0xbe, 0xde, 0x4c, 0x41, 0x62, 0xb0, 0xb5, 0x11, + 0x64, 0x14, 0x54, 0x5f, 0x3b, 0x4b, 0xe7, 0xc2, 0x95, 0xf8, 0x0f, + 0x07, 0x71, 0xf2, 0x19, 0xea, 0xdb, 0xf6, 0x33, 0xe7, 0xc4, 0x1e, + 0xa2, 0x82, 0x62, 0xfe, 0xaa, 0xaa, 0xa7, 0x6d, 0xc9, 0x46, 0x44, + 0xa8, 0xc9, 0xc5, 0x20, 0x0b, 0xc0, 0xef, 0xef, 0x45, 0x0a, 0xe8, + 0x2f, 0x7d, 0x84, 0x10, 0x09, 0x32, 0x20, 0x13, 0x0b, 0x2a, 0x2f, + 0xb4, 0x31, 0x5c, 0x52, 0x09, 0x46, 0x13, 0xa7, 0x06, 0xcf, 0x86, + 0xfe, 0xa2, 0x0a, 0x54, 0xac, 0xc9, 0x03, 0x76, 0x9c, 0x08, 0xac, + 0x38, 0xa5, 0xb2, 0xf7, 0x0f, 0x5a, 0xab, 0xe7, 0x50, 0x38, 0xf2, + 0x80, 0x92, 0xfe, 0x6e, 0x5a, 0xb6, 0x1c, 0x02, 0xd7, 0x62, 0xd8, + 0x04, 0xfc, 0x69, 0x8f, 0xc5, 0x1e, 0xd6, 0xf8, 0xae, 0x44, 0x49, + 0x97, 0xaa, 0xd3, 0x27, 0x59, 0x74, 0x78, 0x3b, 0x17, 0x67, 0xbd, + 0x48, 0x43, 0xdb, 0x3e, 0xce, 0xcc, 0x5d, 0x8e, 0xa8, 0x28, 0xc5, + 0xb8, 0x82, 0xfa, 0x6b, 0x6d, 0x1c, 0x58, 0xbb, 0x93, 0x8b, 0x33, + 0x9a, 0x78, 0xf8, 0x20, 0xa6, 0xba, 0xca, 0x25, 0x8d, 0xc0, 0x89, + 0x14, 0xd9, 0x44, 0x21, 0x35, 0x30, 0xb5, 0xaf, 0x83, 0x9c, 0x5f, + 0x4c, 0x0f, 0xe5, 0x4c, 0xe8, 0xfa, 0x9d, 0xc1, 0xb2, 0x89, 0xdc, + 0x9c, 0x54, 0xcf, 0x3f, 0xe3, 0x1f, 0x63, 0xb0, 0xa2, 0x16, 0xdb, + 0x2f, 0x24, 0x0c, 0x15, 0xd9, 0x9c, 0xa6, 0x78, 0xb0, 0x8f, 0x97, + 0x0f, 0x7f, 0xc2, 0x8d, 0xba, 0xa7, 0xd8, 0xb3, 0xe2, 0x6b, 0xac, + 0x24, 0x66, 0xda, 0xaf, 0x07, 0x19, 0x88, 0x04, 0x95, 0x77, 0x6e, + 0x63, 0xe9, 0x94, 0x2b, 0xfe, 0x14, 0xa2, 0x08, 0x62, 0x63, 0xb8, + 0xdb, 0x17, 0xe2, 0xf9, 0x90, 0x1a, 0x8b, 0x30, 0x9f, 0x60, 0x47, + 0x06, 0x26, 0x75, 0x9d, 0x27, 0x5b, 0x58, 0x46, 0x7f, 0x30, 0x86, + 0x49, 0x1d, 0xbf, 0x70, 0x7d, 0xc6, 0x73, 0xc4, 0x31, 0x48, 0x23, + 0x40, 0x18, 0x3c, 0x4b, 0xa2, 0x8c, 0x21, 0x8b, 0x64, 0xd3, 0x81, + 0x77, 0xc0, 0x18, 0xbe, 0x7d, 0x65, 0x17, 0x8e, 0x80, 0xef, 0x9a, + 0x3e, 0x64, 0xfd, 0x4f, 0xef, 0xd3, 0xd6, 0xb0, 0x82, 0xc9, 0xd7, + 0x4f, 0xa1, 0x2d, 0x9b, 0x0d, 0x07, 0xdf, 0xc5, 0x38, 0x1e, 0xda, + 0x68, 0x4c, 0x9a, 0x72, 0x74, 0xc3, 0x97, 0x0c, 0x16, 0x56, 0xa3, + 0x22, 0x89, 0x0c, 0x55, 0x8c, 0x9f, 0x19, 0xe0, 0x56, 0x6d, 0x23, + 0x19, 0xcf, 0xc1, 0xc9, 0x0c, 0x71, 0x69, 0xe6, 0x12, 0x12, 0x05, + 0xa1, 0x02, 0xa5, 0x04, 0xc2, 0x18, 0x1c, 0xd7, 0xa5, 0xe9, 0xb7, + 0xef, 0xb1, 0x13, 0xc5, 0xae, 0x57, 0x77, 0x13, 0x5a, 0x2e, 0x69, + 0x62, 0xb8, 0xfc, 0xe8, 0x02, 0x3a, 0x6a, 0x9e, 0xe6, 0x99, 0xd3, + 0x2d, 0x04, 0xf7, 0xfb, 0xe8, 0xae, 0x99, 0x85, 0xb2, 0x1d, 0x42, + 0xa5, 0x10, 0x52, 0x10, 0xd9, 0x3e, 0xf7, 0x43, 0x17, 0x3b, 0x90, + 0xd8, 0x9e, 0x8f, 0x58, 0xff, 0x43, 0xc6, 0x38, 0xc1, 0x28, 0x3c, + 0x0f, 0xa2, 0x61, 0x43, 0x2e, 0x85, 0xc2, 0x40, 0xe0, 0x59, 0x06, + 0xc1, 0x7f, 0xd9, 0xff, 0x46, 0x5a, 0x90, 0x4f, 0xc1, 0x28, 0x83, + 0x11, 0x60, 0x10, 0x24, 0x1a, 0x06, 0x43, 0x43, 0x3e, 0x9f, 0xa3, + 0xa0, 0xb4, 0x90, 0x31, 0xe3, 0x20, 0x1f, 0x43, 0x67, 0xe7, 0x3d, + 0x6a, 0x6b, 0x2b, 0x50, 0x0a, 0xc8, 0x85, 0xd4, 0x57, 0xf9, 0x88, + 0xc4, 0xf0, 0x2f, 0xb4, 0x16, 0xf4, 0xd5, 0x82, 0x00, 0xa9, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, + 0x82 ), + 28, 12, + DATA ( 0x90c4fe, 0x91c3fb, 0x98c5fb, 0x9eceff, 0x9bccff, 0x97c6fa, + 0x92c2f8, 0x98c9fe, 0x97caff, 0x93c6fd, 0x9dceff, 0x9fcdff, + 0xa0ccfd, 0xaad4fe, 0xacd2ff, 0xa1cafe, 0x9dc9fe, 0xa1d0fe, + 0xa2d3fe, 0x94c8f9, 0x8abff7, 0x88befd, 0x8ec1ff, 0x8bbdfa, + 0x8ec1f5, 0xa0d3fe, 0x9fd0fc, 0x98c9fe, 0x8fc5ff, 0x8ec1f9, + 0x91c6fc, 0xd4697c, 0xd4697b, 0x98ccff, 0x88ccff, 0x8aceff, + 0x8ed4ff, 0x8dccff, 0x95c9fd, 0x9ed0ff, 0x9acbfd, 0xa1ddff, + 0xa9ddff, 0xa1cbfd, 0x9cc7fb, 0x97cefe, 0x9addff, 0x97d0ff, + 0x8bbff9, 0x7ec1ff, 0x84c8ff, 0x87caff, 0x7fc2ff, 0x93d6ff, + 0x9cdbff, 0x9acbfe, 0x89c1fe, 0x8fc5fe, 0x8fc7fe, 0xd0677a, + 0xd36a7d, 0x9dc2f3, 0xff1c15, 0xfd231e, 0xf82624, 0xd85a69, + 0x92baef, 0x97cbff, 0xa4b9e6, 0xf32d2c, 0xda6372, 0xa1cfff, + 0x99c9fb, 0xc97085, 0xf92623, 0xada5ca, 0x8bc1fb, 0xe74047, + 0xfd251f, 0xfd231d, 0xfe241e, 0xfd211c, 0xe0535d, 0x99d2ff, + 0x81baf9, 0x8fc7fe, 0x8dc7ff, 0x84cfff, 0x98d1ff, 0xbb90ae, + 0xef3538, 0xa294bd, 0xa994bb, 0xf03739, 0xc9647a, 0x8bc6ff, + 0x98ceff, 0xc86f86, 0xf03739, 0xa5c0ed, 0xb39dc1, 0xf92723, + 0xaf93b2, 0x95cdff, 0x96b6eb, 0xed383c, 0xba7498, 0x9b9fd7, + 0x9fa2d5, 0x9c9ccc, 0x9db4e0, 0x9dd2ff, 0x77b2f5, 0x82bcfe, + 0xb496b6, 0xfa2622, 0x85ceff, 0xd56272, 0xe4474f, 0x85b7f0, + 0x7bb9f7, 0xde4c58, 0xd8515e, 0x7fbefc, 0x8bc4ff, 0x8bc4ff, + 0xf23131, 0xca788f, 0xf42c2b, 0xbd829d, 0x85c8fa, 0x85c0f8, + 0xa0aeda, 0xf92a27, 0x80aaf0, 0x82c0ff, 0x84c1ff, 0x7fbafb, + 0x85bdf5, 0x94cbfe, 0x7cb8fd, 0x75b8ff, 0xc66982, 0xd5596a, + 0x84befe, 0xe5444d, 0xcc6a80, 0x7ec9ff, 0x9797c7, 0xf13335, + 0xbb7796, 0x78b9fc, 0x7eb9f9, 0x8bc8ff, 0xaa90ba, 0xf72a28, + 0xcd677d, 0x8cc5fd, 0x7ebbf1, 0x78baf8, 0xae8aae, 0xf72d2a, + 0xd84c5d, 0xdc4d5a, 0xdd4c59, 0xc7627a, 0x7dbeff, 0x8fc7fe, + 0x7ab7fe, 0x68b2ff, 0xe34049, 0xb881a1, 0x8cafed, 0xea3b40, + 0xf92926, 0xfd231d, 0xf62d2b, 0xd54958, 0x7abeff, 0x79b6fd, + 0x74b0f9, 0x80c3ff, 0xb27da2, 0xf92b28, 0xba7898, 0x84c5ff, + 0x7ebdfa, 0x6bb7fb, 0xc7566d, 0xe93d43, 0xd84b5b, 0xd64959, + 0xdd4d59, 0xb46f90, 0x78b8fd, 0x86befd, 0x74b3ff, 0x6bacfc, + 0xfc2823, 0x999ed2, 0x97a4d9, 0xfa2823, 0x9c9ed2, 0x9ca4d5, + 0x8ea3de, 0x6ca7f2, 0x70b0fd, 0x78b6ff, 0x6fb2ff, 0x9c86b9, + 0xf62e2d, 0xc75771, 0xec373b, 0x80aded, 0x7fc3fe, 0x6ac3ff, + 0xf42d2c, 0x9b8ebc, 0x69b8ff, 0x5aa4f9, 0x77c0ff, 0x74b9ff, + 0x79b2fa, 0x7ab4f5, 0x72b3ff, 0x9195ce, 0xf23031, 0x809ee7, + 0xb181a6, 0xe93a41, 0x78beff, 0x82bcfe, 0x7db9ff, 0x70affd, + 0x68a8f8, 0x6cacfd, 0x7da1e8, 0xec373b, 0xd15165, 0x64aeff, + 0xef3335, 0xa7729b, 0x6dbcff, 0x83a7e0, 0xf72b29, 0x6f96e1, + 0x62b1ff, 0x54a3f8, 0x5ca9f7, 0x7bc1ff, 0x76b1fd, 0x72abf1, + 0x6bb2ff, 0xb17298, 0xe63b43, 0x6da7fa, 0xd15367, 0xc16481, + 0x72b8ff, 0x7ab7ff, 0x7ab8fe, 0x77b2ff, 0x6ba7f7, 0x60acff, + 0xd84858, 0xec363a, 0x6da7f9, 0x69afff, 0x9476b0, 0xf92b28, + 0x66a4f2, 0xa57ca2, 0xf52e2d, 0xd64454, 0xd5495b, 0xd34859, + 0xd24556, 0x86ace0, 0x75b7fd, 0x6daaf3, 0x63adf9, 0xb96586, + 0xc65c76, 0x60aeff, 0xd64657, 0x908fc8, 0x6eb3ff, 0x72b2ff, + 0x75b3ff, 0x78b1fe, 0x70adfd, 0xa377a7, 0xdc4453, 0x808fd5, + 0x65aaff, 0x66abfe, 0x679aed, 0xcb4a61, 0xa16794, 0xae678b, + 0xd84d59, 0xd14859, 0xcd4456, 0xd44a5a, 0xcb495e, 0x71a4e6, + 0x79c0ff, 0x71b1fb, 0x65a9f3, 0x6ab2ff, 0x71b9ff, 0x6aabfe, + 0x60a8fe, 0x6bb1ff, 0x72b4fe, 0x73b4ff, 0x74b3fe, 0x75b3ff, + 0x76b2fe, 0x6fb0ff, 0x66adff, 0x65a8fe, 0x64a9fe, 0x63a9ff, + 0x5fa7ff, 0x4e9ffe, 0x4596f4, 0x4fa7ff, 0x62beff, 0x59b8ff, + 0x2e8de9, 0x4faeff, 0x4aa9ff, 0x4a9ff7, 0x77bbff, 0x78b7fe ) ); + +/** + * Perform PNG self-test + * + */ +static void png_test_exec ( void ) { + + /* Original image */ + pixbuf_ok ( &original ); + + /* All allowed colour type and bit depth combinations */ + pixbuf_ok ( &ctype_0_1 ); + pixbuf_ok ( &ctype_0_2 ); + pixbuf_ok ( &ctype_0_4 ); + pixbuf_ok ( &ctype_0_8 ); + pixbuf_ok ( &ctype_0_16 ); + pixbuf_ok ( &ctype_2_8 ); + pixbuf_ok ( &ctype_2_16 ); + pixbuf_ok ( &ctype_3_1 ); + pixbuf_ok ( &ctype_3_2 ); + pixbuf_ok ( &ctype_3_4 ); + pixbuf_ok ( &ctype_3_8 ); + pixbuf_ok ( &ctype_4_8 ); + pixbuf_ok ( &ctype_4_16 ); + pixbuf_ok ( &ctype_6_8 ); + pixbuf_ok ( &ctype_6_16 ); + + /* All basic filter types */ + pixbuf_ok ( &filter_0 ); + pixbuf_ok ( &filter_1 ); + pixbuf_ok ( &filter_2 ); + pixbuf_ok ( &filter_3 ); + pixbuf_ok ( &filter_4 ); + + /* Multiple IDAT sections */ + pixbuf_ok ( &multi_idat ); + + /* Interlaced */ + pixbuf_ok ( &interlaced ); + pixbuf_ok ( &interlaced_w1 ); + pixbuf_ok ( &interlaced_w2 ); + pixbuf_ok ( &interlaced_w3 ); + pixbuf_ok ( &interlaced_w4 ); + pixbuf_ok ( &interlaced_h1 ); + pixbuf_ok ( &interlaced_h2 ); + pixbuf_ok ( &interlaced_h3 ); + pixbuf_ok ( &interlaced_h4 ); + + /* Alpha channel */ + pixbuf_ok ( &alpha ); +} + +/** PNG self-test */ +struct self_test png_test __self_test = { + .name = "png", + .exec = png_test_exec, +}; diff --git a/roms/ipxe/src/tests/pnm_test.c b/roms/ipxe/src/tests/pnm_test.c new file mode 100644 index 000000000..26b0c0726 --- /dev/null +++ b/roms/ipxe/src/tests/pnm_test.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * PNM self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <assert.h> +#include <ipxe/pixbuf.h> +#include <ipxe/pnm.h> +#include <ipxe/test.h> +#include "pixbuf_test.h" + +/** Define inline pixel data */ +#define DATA(...) { __VA_ARGS__ } + +/** PBM ASCII example (from Wikipedia) */ +PIX ( pbm_ascii, &pnm_image_type, + "P1\n" + "# This is an example bitmap of the letter \"J\"\n" + "6 10\n" + "0 0 0 0 1 0\n" + "0 0 0 0 1 0\n" + "0 0 0 0 1 0\n" + "0 0 0 0 1 0\n" + "0 0 0 0 1 0\n" + "0 0 0 0 1 0\n" + "1 0 0 0 1 0\n" + "0 1 1 1 0 0\n" + "0 0 0 0 0 0\n" + "0 0 0 0 0 0\n", + 6, 10, + DATA ( 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff ) ); + +/** PGM ASCII example (from Wikipedia) */ +PIX ( pgm_ascii, &pnm_image_type, + "P2\n" + "# Shows the word \"FEEP\" (example from Netpbm man page on PGM)\n" + "24 7\n" + "15\n" + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + "0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0\n" + "0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0\n" + "0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0\n" + "0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0\n" + "0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0\n" + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" + , 24, 7, + DATA ( 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x333333, 0x333333, 0x333333, 0x333333, 0x000000, + 0x000000, 0x777777, 0x777777, 0x777777, 0x777777, 0x000000, + 0x000000, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0x000000, + 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, + 0x000000, 0x333333, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x777777, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xbbbbbb, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xffffff, 0x000000, 0x000000, 0xffffff, 0x000000, + 0x000000, 0x333333, 0x333333, 0x333333, 0x000000, 0x000000, + 0x000000, 0x777777, 0x777777, 0x777777, 0x000000, 0x000000, + 0x000000, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0x000000, 0x000000, + 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, + 0x000000, 0x333333, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x777777, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xbbbbbb, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x333333, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x777777, 0x777777, 0x777777, 0x777777, 0x000000, + 0x000000, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0x000000, + 0x000000, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000 ) ); + +/** PPM ASCII example (from Wikipedia) */ +PIX ( ppm_ascii, &pnm_image_type, + "P3\n" + "# The P3 means colors are in ASCII, then 3 columns and 2 rows,\n" + "# then 255 for max color, then RGB triplets\n" + "3 2\n" + "255\n" + "255 0 0 0 255 0 0 0 255\n" + "255 255 0 255 255 255 0 0 0\n", + 3, 2, + DATA ( 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xffffff, 0x000000 ) ); + +/** PBM ASCII with no space between pixel values */ +PIX ( pbm_ascii_no_space, &pnm_image_type, + "P1\n" + "3 3\n" + "001\n" + "010\n" + "111\n", + 3, 3, + DATA ( 0xffffff, 0xffffff, 0x000000, 0xffffff, 0x000000, 0xffffff, + 0x000000, 0x000000, 0x000000 ) ); + +/** PBM binary example (converted from Wikipedia) */ +PIX ( pbm_binary, &pnm_image_type, + DATA ( 0x50, 0x34, 0x0a, 0x23, 0x20, 0x43, 0x52, 0x45, 0x41, 0x54, 0x4f, + 0x52, 0x3a, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x20, 0x50, 0x4e, 0x4d, + 0x20, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x20, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x31, 0x0a, 0x36, 0x20, + 0x31, 0x30, 0x0a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x88, 0x70, + 0x00, 0x00 ), + 6, 10, + DATA ( 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0x000000, 0xffffff, 0xffffff, 0xffffff, 0x000000, 0xffffff, + 0xffffff, 0x000000, 0x000000, 0x000000, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, + 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff ) ); + +/** PGM binary example (converted from Wikipedia) */ +PIX ( pgm_binary, &pnm_image_type, + DATA ( 0x50, 0x35, 0x0a, 0x32, 0x34, 0x20, 0x37, 0x0a, 0x31, 0x35, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x07, 0x07, + 0x07, 0x07, 0x00, 0x00, 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x0f, + 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x03, 0x03, 0x03, 0x00, + 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x0b, + 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x00, + 0x00, 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 ), + 24, 7, + DATA ( 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x333333, 0x333333, 0x333333, 0x333333, 0x000000, + 0x000000, 0x777777, 0x777777, 0x777777, 0x777777, 0x000000, + 0x000000, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0x000000, + 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, + 0x000000, 0x333333, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x777777, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xbbbbbb, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xffffff, 0x000000, 0x000000, 0xffffff, 0x000000, + 0x000000, 0x333333, 0x333333, 0x333333, 0x000000, 0x000000, + 0x000000, 0x777777, 0x777777, 0x777777, 0x000000, 0x000000, + 0x000000, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0x000000, 0x000000, + 0x000000, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x000000, + 0x000000, 0x333333, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x777777, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xbbbbbb, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x333333, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x777777, 0x777777, 0x777777, 0x777777, 0x000000, + 0x000000, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0xbbbbbb, 0x000000, + 0x000000, 0xffffff, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000 ) ); + +/** PPM binary example (converted from Wikipedia) */ +PIX ( ppm_binary, &pnm_image_type, + DATA ( 0x50, 0x36, 0x0a, 0x33, 0x20, 0x32, 0x0a, 0x32, 0x35, 0x35, 0x0a, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 ), + 3, 2, + DATA ( 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xffffff, 0x000000 ) ); + +/** + * Perform PNM self-test + * + */ +static void pnm_test_exec ( void ) { + + pixbuf_ok ( &pbm_ascii ); + pixbuf_ok ( &pgm_ascii ); + pixbuf_ok ( &ppm_ascii ); + pixbuf_ok ( &pbm_ascii_no_space ); + pixbuf_ok ( &pbm_binary ); + pixbuf_ok ( &pgm_binary ); + pixbuf_ok ( &ppm_binary ); +} + +/** PNM self-test */ +struct self_test pnm_test __self_test = { + .name = "pnm", + .exec = pnm_test_exec, +}; diff --git a/roms/ipxe/src/tests/profile_test.c b/roms/ipxe/src/tests/profile_test.c new file mode 100644 index 000000000..9d682bf2b --- /dev/null +++ b/roms/ipxe/src/tests/profile_test.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Profiling self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <assert.h> +#include <ipxe/test.h> +#include <ipxe/profile.h> + +/** A profiling test */ +struct profile_test { + /** Sample values */ + const unsigned long *samples; + /** Number of samples */ + unsigned int count; + /** Expected mean sample value */ + unsigned long mean; + /** Expected standard deviation */ + unsigned long stddev; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define a profiling test */ +#define PROFILE_TEST( name, MEAN, STDDEV, SAMPLES ) \ + static const unsigned long name ## _samples[] = SAMPLES; \ + static struct profile_test name = { \ + .samples = name ## _samples, \ + .count = ( sizeof ( name ## _samples ) / \ + sizeof ( name ## _samples [0] ) ), \ + .mean = MEAN, \ + .stddev = STDDEV, \ + } + +/** Empty data set */ +PROFILE_TEST ( empty, 0, 0, DATA() ); + +/** Single-element data set (zero) */ +PROFILE_TEST ( zero, 0, 0, DATA ( 0 ) ); + +/** Single-element data set (non-zero) */ +PROFILE_TEST ( single, 42, 0, DATA ( 42 ) ); + +/** Multiple identical element data set */ +PROFILE_TEST ( identical, 69, 0, DATA ( 69, 69, 69, 69, 69, 69, 69 ) ); + +/** Small element data set */ +PROFILE_TEST ( small, 5, 2, DATA ( 3, 5, 9, 4, 3, 2, 5, 7 ) ); + +/** Random data set */ +PROFILE_TEST ( random, 70198, 394, + DATA ( 69772, 70068, 70769, 69653, 70663, 71078, 70101, 70341, + 70215, 69600, 70020, 70456, 70421, 69972, 70267, 69999, + 69972 ) ); + +/** Large-valued random data set */ +PROFILE_TEST ( large, 93533894UL, 25538UL, + DATA ( 93510333UL, 93561169UL, 93492361UL, 93528647UL, + 93557566UL, 93503465UL, 93540126UL, 93549020UL, + 93502307UL, 93527320UL, 93537152UL, 93540125UL, + 93550773UL, 93586731UL, 93521312UL ) ); + +/** + * Report a profiling test result + * + * @v test Profiling test + * @v file Test code file + * @v line Test code line + */ +static void profile_okx ( struct profile_test *test, const char *file, + unsigned int line ) { + struct profiler profiler; + unsigned long mean; + unsigned long stddev; + unsigned int i; + + /* Initialise profiler */ + memset ( &profiler, 0, sizeof ( profiler ) ); + + /* Record sample values */ + for ( i = 0 ; i < test->count ; i++ ) + profile_update ( &profiler, test->samples[i] ); + + /* Check resulting statistics */ + mean = profile_mean ( &profiler ); + stddev = profile_stddev ( &profiler ); + DBGC ( test, "PROFILE calculated mean %ld stddev %ld\n", mean, stddev ); + okx ( mean == test->mean, file, line ); + okx ( stddev == test->stddev, file, line ); +} +#define profile_ok( test ) profile_okx ( test, __FILE__, __LINE__ ) + +/** + * Perform profiling self-tests + * + */ +static void profile_test_exec ( void ) { + + /* Perform profiling tests */ + profile_ok ( &empty ); + profile_ok ( &zero ); + profile_ok ( &single ); + profile_ok ( &identical ); + profile_ok ( &small ); + profile_ok ( &random ); + profile_ok ( &large ); +} + +/** Profiling self-test */ +struct self_test profile_test __self_test = { + .name = "profile", + .exec = profile_test_exec, +}; diff --git a/roms/ipxe/src/tests/settings_test.c b/roms/ipxe/src/tests/settings_test.c index 028f8163b..4ee6a10fa 100644 --- a/roms/ipxe/src/tests/settings_test.c +++ b/roms/ipxe/src/tests/settings_test.c @@ -38,22 +38,28 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Report a formatted-store test result * - * @v settings Settings block - * @v setting Setting - * @v formatted Formatted value - * @v raw_array Expected raw value + * @v _settings Settings block + * @v _setting Setting + * @v _formatted Formatted value + * @v _raw_array Expected raw value */ -#define storef_ok( settings, setting, formatted, raw_array ) do { \ - const uint8_t expected[] = raw_array; \ +#define storef_ok( _settings, _setting, _formatted, _raw_array ) do { \ + const uint8_t expected[] = _raw_array; \ uint8_t actual[ sizeof ( expected ) ]; \ int len; \ \ - ok ( storef_setting ( settings, setting, formatted ) == 0 ); \ - len = fetch_setting ( settings, setting, actual, \ + ok ( storef_setting ( _settings, _setting, _formatted ) == 0 ); \ + len = fetch_setting ( _settings, _setting, NULL, NULL, actual, \ sizeof ( actual ) ); \ - DBGC ( settings, "Stored %s \"%s\", got:\n", \ - (setting)->type->name, formatted ); \ - DBGC_HDA ( settings, 0, actual, len ); \ + if ( len >= 0 ) { \ + DBGC ( _settings, "Stored %s \"%s\", got:\n", \ + (_setting)->type->name, _formatted ); \ + DBGC_HDA ( _settings, 0, actual, len ); \ + } else { \ + DBGC ( _settings, "Stored %s \"%s\", got error %s\n", \ + (_setting)->type->name, _formatted, \ + strerror ( len ) ); \ + } \ ok ( len == ( int ) sizeof ( actual ) ); \ ok ( memcmp ( actual, expected, sizeof ( actual ) ) == 0 ); \ } while ( 0 ) @@ -61,25 +67,77 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Report a formatted-fetch test result * - * @v settings Settings block - * @v setting Setting - * @v raw_array Raw value - * @v formatted Expected formatted value + * @v _settings Settings block + * @v _setting Setting + * @v _raw_array Raw value + * @v _formatted Expected formatted value */ -#define fetchf_ok( settings, setting, raw_array, formatted ) do { \ - const uint8_t raw[] = raw_array; \ - char actual[ strlen ( formatted ) + 1 ]; \ +#define fetchf_ok( _settings, _setting, _raw_array, _formatted ) do { \ + const uint8_t raw[] = _raw_array; \ + char actual[ strlen ( _formatted ) + 1 ]; \ int len; \ \ - ok ( store_setting ( settings, setting, raw, \ + ok ( store_setting ( _settings, _setting, raw, \ sizeof ( raw ) ) == 0 ); \ - len = fetchf_setting ( settings, setting, actual, \ + len = fetchf_setting ( _settings, _setting, NULL, NULL, actual, \ sizeof ( actual ) ); \ - DBGC ( settings, "Fetched %s \"%s\" from:\n", \ - (setting)->type->name, formatted ); \ - DBGC_HDA ( settings, 0, raw, sizeof ( raw ) ); \ + DBGC ( _settings, "Fetched %s \"%s\" from:\n", \ + (_setting)->type->name, actual ); \ + DBGC_HDA ( _settings, 0, raw, sizeof ( raw ) ); \ ok ( len == ( int ) ( sizeof ( actual ) - 1 ) ); \ - ok ( strcmp ( actual, formatted ) == 0 ); \ + ok ( strcmp ( actual, _formatted ) == 0 ); \ + } while ( 0 ) + +/** + * Report a numeric-store test result + * + * @v _settings Settings block + * @v _setting Setting + * @v _numeric Numeric value + * @v _raw_array Expected raw value + */ +#define storen_ok( _settings, _setting, _numeric, _raw_array ) do { \ + const uint8_t expected[] = _raw_array; \ + uint8_t actual[ sizeof ( expected ) ]; \ + int len; \ + \ + ok ( storen_setting ( _settings, _setting, _numeric ) == 0 ); \ + len = fetch_setting ( _settings, _setting, NULL, NULL, actual, \ + sizeof ( actual ) ); \ + if ( len >= 0 ) { \ + DBGC ( _settings, "Stored %s %#lx, got:\n", \ + (_setting)->type->name, \ + ( unsigned long ) _numeric ); \ + DBGC_HDA ( _settings, 0, actual, len ); \ + } else { \ + DBGC ( _settings, "Stored %s %#lx, got error %s\n", \ + (_setting)->type->name, \ + ( unsigned long ) _numeric, strerror ( len ) ); \ + } \ + ok ( len == ( int ) sizeof ( actual ) ); \ + ok ( memcmp ( actual, expected, sizeof ( actual ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report a numeric-fetch test result + * + * @v _settings Settings block + * @v _setting Setting + * @v _raw_array Raw array + * @v _numeric Expected numeric value + */ +#define fetchn_ok( _settings, _setting, _raw_array, _numeric ) do { \ + const uint8_t raw[] = _raw_array; \ + unsigned long actual; \ + \ + ok ( store_setting ( _settings, _setting, raw, \ + sizeof ( raw ) ) == 0 ); \ + ok ( fetchn_setting ( _settings, _setting, NULL, NULL, \ + &actual ) == 0 ); \ + DBGC ( _settings, "Fetched %s %#lx from:\n", \ + (_setting)->type->name, actual ); \ + DBGC_HDA ( _settings, 0, raw, sizeof ( raw ) ); \ + ok ( actual == ( unsigned long ) _numeric ); \ } while ( 0 ) /** Test generic settings block */ @@ -104,18 +162,18 @@ static struct setting test_string_setting = { .type = &setting_type_string, }; -/** Test URI-encoded string setting */ -static struct setting test_uristring_setting = { - .name = "test_uristring", - .type = &setting_type_uristring, -}; - /** Test IPv4 address setting type */ static struct setting test_ipv4_setting = { .name = "test_ipv4", .type = &setting_type_ipv4, }; +/** Test IPv6 address setting type */ +static struct setting test_ipv6_setting = { + .name = "test_ipv6", + .type = &setting_type_ipv6, +}; + /** Test signed 8-bit integer setting type */ static struct setting test_int8_setting = { .name = "test_int8", @@ -164,12 +222,24 @@ static struct setting test_hexhyp_setting = { .type = &setting_type_hexhyp, }; +/** Test raw hex string setting type */ +static struct setting test_hexraw_setting = { + .name = "test_hexraw", + .type = &setting_type_hexraw, +}; + /** Test UUID setting type */ static struct setting test_uuid_setting = { .name = "test_uuid", .type = &setting_type_uuid, }; +/** Test PCI bus:dev.fn setting type */ +static struct setting test_busdevfn_setting = { + .name = "test_busdevfn", + .type = &setting_type_busdevfn, +}; + /** * Perform settings self-tests * @@ -185,20 +255,23 @@ static void settings_test_exec ( void ) { fetchf_ok ( &test_settings, &test_string_setting, RAW ( 'w', 'o', 'r', 'l', 'd' ), "world" ); - /* "uristring" setting type */ - storef_ok ( &test_settings, &test_uristring_setting, "hello%20world", - RAW ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', - 'd' ) ); - fetchf_ok ( &test_settings, &test_uristring_setting, - RAW ( 1, 2, 3, 4, 5 ), "%01%02%03%04%05" ); - /* "ipv4" setting type */ storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1", RAW ( 192, 168, 0, 1 ) ); fetchf_ok ( &test_settings, &test_ipv4_setting, RAW ( 212, 13, 204, 60 ), "212.13.204.60" ); - /* Integer setting types */ + /* "ipv6" setting type */ + storef_ok ( &test_settings, &test_ipv6_setting, + "2001:ba8:0:1d4::6950:5845", + RAW ( 0x20, 0x01, 0x0b, 0xa8, 0x00, 0x00, 0x01, 0xd4, + 0x00, 0x00, 0x00, 0x00, 0x69, 0x50, 0x58, 0x45 ) ); + fetchf_ok ( &test_settings, &test_ipv6_setting, + RAW ( 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x0c, 0x29, 0xff, 0xfe, 0xc5, 0x39, 0xa1 ), + "fe80::20c:29ff:fec5:39a1" ); + + /* Integer setting types (as formatted strings) */ storef_ok ( &test_settings, &test_int8_setting, "54", RAW ( 54 ) ); storef_ok ( &test_settings, &test_int8_setting, @@ -238,12 +311,50 @@ static void settings_test_exec ( void ) { fetchf_ok ( &test_settings, &test_uint32_setting, RAW ( 0xf2, 0x37, 0xb2, 0x18 ), "0xf237b218" ); + /* Integer setting types (as numeric values) */ + storen_ok ( &test_settings, &test_int8_setting, + 72, RAW ( 72 ) ); + storen_ok ( &test_settings, &test_int8_setting, + 0xabcd, RAW ( 0xcd ) ); + fetchn_ok ( &test_settings, &test_int8_setting, + RAW ( 0xfe ), -2 ); + storen_ok ( &test_settings, &test_uint8_setting, + 84, RAW ( 84 ) ); + fetchn_ok ( &test_settings, &test_uint8_setting, + RAW ( 0xfe ), 0xfe ); + storen_ok ( &test_settings, &test_int16_setting, + 0x87bd, RAW ( 0x87, 0xbd ) ); + fetchn_ok ( &test_settings, &test_int16_setting, + RAW ( 0x3d, 0x14 ), 0x3d14 ); + fetchn_ok ( &test_settings, &test_int16_setting, + RAW ( 0x80 ), -128 ); + storen_ok ( &test_settings, &test_uint16_setting, + 1, RAW ( 0x00, 0x01 ) ); + fetchn_ok ( &test_settings, &test_uint16_setting, + RAW ( 0xbd, 0x87 ), 0xbd87 ); + fetchn_ok ( &test_settings, &test_uint16_setting, + RAW ( 0x80 ), 0x0080 ); + storen_ok ( &test_settings, &test_int32_setting, + 0x0812bfd2, RAW ( 0x08, 0x12, 0xbf, 0xd2 ) ); + fetchn_ok ( &test_settings, &test_int32_setting, + RAW ( 0x43, 0x87, 0x91, 0xb4 ), 0x438791b4 ); + fetchn_ok ( &test_settings, &test_int32_setting, + RAW ( 0xff, 0xff, 0xfe ), -2 ); + storen_ok ( &test_settings, &test_uint32_setting, + 0xb5927ab8, RAW ( 0xb5, 0x92, 0x7a, 0xb8 ) ); + fetchn_ok ( &test_settings, &test_uint32_setting, + RAW ( 0x98, 0xab, 0x41, 0x81 ), 0x98ab4181 ); + fetchn_ok ( &test_settings, &test_uint32_setting, + RAW ( 0xff, 0xff, 0xfe ), 0x00fffffe ); + fetchn_ok ( &test_settings, &test_uint32_setting, + RAW ( 0, 0, 0, 0x12, 0x34, 0x56, 0x78 ), 0x12345678 ); + fetchn_ok ( &test_settings, &test_int32_setting, + RAW ( 0, 0, 0, 0x12, 0x34, 0x56, 0x78 ), 0x12345678 ); + fetchn_ok ( &test_settings, &test_int32_setting, + RAW ( 0xff, 0xff, 0x87, 0x65, 0x43, 0x21 ), -0x789abcdf ); + /* "hex" setting type */ storef_ok ( &test_settings, &test_hex_setting, - ":", RAW ( 0x00, 0x00 ) ); - storef_ok ( &test_settings, &test_hex_setting, - "1:2:", RAW ( 0x01, 0x02, 0x00 ) ); - storef_ok ( &test_settings, &test_hex_setting, "08:12:f5:22:90:1b:4b:47:a8:30:cb:4d:67:4c:d6:76", RAW ( 0x08, 0x12, 0xf5, 0x22, 0x90, 0x1b, 0x4b, 0x47, 0xa8, 0x30, 0xcb, 0x4d, 0x67, 0x4c, 0xd6, 0x76 ) ); @@ -260,12 +371,24 @@ static void settings_test_exec ( void ) { 0x09, 0x6c, 0x66, 0x13, 0xc1, 0xa8, 0xec, 0x27 ), "9f-e5-6d-fb-24-3a-4c-bb-a9-09-6c-66-13-c1-a8-ec-27" ); + /* "hexraw" setting type */ + storef_ok ( &test_settings, &test_hexraw_setting, + "012345abcdef", RAW ( 0x01, 0x23, 0x45, 0xab, 0xcd, 0xef )); + fetchf_ok ( &test_settings, &test_hexraw_setting, + RAW ( 0x9e, 0x4b, 0x6e, 0xef, 0x36, 0xb6, 0x46, 0xfe, 0x8f, + 0x17, 0x06, 0x39, 0x6b, 0xf4, 0x48, 0x4e ), + "9e4b6eef36b646fe8f1706396bf4484e" ); + /* "uuid" setting type (no store capability) */ fetchf_ok ( &test_settings, &test_uuid_setting, RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8, 0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ), "1a6a749d-0eda-461a-a87a-7cfe4fca4a57" ); + /* "busdevfn" setting type (no store capability) */ + fetchf_ok ( &test_settings, &test_busdevfn_setting, + RAW ( 0x03, 0x45 ), "03:08.5" ); + /* Clear and unregister test settings block */ clear_settings ( &test_settings ); unregister_settings ( &test_settings ); diff --git a/roms/ipxe/src/tests/tcpip_test.c b/roms/ipxe/src/tests/tcpip_test.c index 13423c397..00c88ae32 100644 --- a/roms/ipxe/src/tests/tcpip_test.c +++ b/roms/ipxe/src/tests/tcpip_test.c @@ -36,6 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/profile.h> #include <ipxe/tcpip.h> +/** Number of sample iterations for profiling */ +#define PROFILE_COUNT 16 + /** A TCP/IP fixed-data test */ struct tcpip_test { /** Data */ @@ -142,51 +145,74 @@ static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) { * Report TCP/IP fixed-data test result * * @v test TCP/IP test + * @v file Test code file + * @v line Test code line */ -#define tcpip_ok( test ) do { \ - uint16_t expected; \ - uint16_t generic_sum; \ - uint16_t sum; \ - expected = rfc_tcpip_chksum ( (test)->data, (test)->len ); \ - generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, \ - (test)->data, \ - (test)->len ); \ - ok ( generic_sum == expected ); \ - sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, (test)->data, \ - (test)->len ); \ - ok ( sum == expected ); \ - } while ( 0 ) +static void tcpip_okx ( struct tcpip_test *test, const char *file, + unsigned int line ) { + uint16_t expected; + uint16_t generic_sum; + uint16_t sum; + + /* Verify generic_tcpip_continue_chksum() result */ + expected = rfc_tcpip_chksum ( test->data, test->len ); + generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, + test->data, test->len ); + okx ( generic_sum == expected, file, line ); + + /* Verify optimised tcpip_continue_chksum() result */ + sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, test->data, test->len ); + okx ( sum == expected, file, line ); +} +#define tcpip_ok( test ) tcpip_okx ( test, __FILE__, __LINE__ ) /** * Report TCP/IP pseudorandom-data test result * * @v test TCP/IP test + * @v file Test code file + * @v line Test code line */ -#define tcpip_random_ok( test ) do { \ - uint8_t *data = ( tcpip_data + (test)->offset ); \ - uint16_t expected; \ - uint16_t generic_sum; \ - uint16_t sum; \ - unsigned long elapsed; \ - unsigned int i; \ - assert ( ( (test)->len + (test)->offset ) <= \ - sizeof ( tcpip_data ) ); \ - srandom ( (test)->seed ); \ - for ( i = 0 ; i < (test)->len ; i++ ) \ - data[i] = random(); \ - expected = rfc_tcpip_chksum ( data, (test)->len ); \ - generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, \ - data, \ - (test)->len ); \ - ok ( generic_sum == expected ); \ - simple_profile(); \ - sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, \ - (test)->len ); \ - elapsed = simple_profile(); \ - ok ( sum == expected ); \ - DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld ticks\n", \ - (test)->len, (test)->offset, elapsed ); \ - } while ( 0 ) +static void tcpip_random_okx ( struct tcpip_random_test *test, + const char *file, unsigned int line ) { + uint8_t *data = ( tcpip_data + test->offset ); + struct profiler profiler; + uint16_t expected; + uint16_t generic_sum; + uint16_t sum; + unsigned int i; + + /* Sanity check */ + assert ( ( test->len + test->offset ) <= sizeof ( tcpip_data ) ); + + /* Generate random data */ + srandom ( test->seed ); + for ( i = 0 ; i < test->len ; i++ ) + data[i] = random(); + + /* Verify generic_tcpip_continue_chksum() result */ + expected = rfc_tcpip_chksum ( data, test->len ); + generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, + data, test->len ); + okx ( generic_sum == expected, file, line ); + + /* Verify optimised tcpip_continue_chksum() result */ + sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, test->len ); + okx ( sum == expected, file, line ); + + /* Profile optimised calculation */ + memset ( &profiler, 0, sizeof ( profiler ) ); + for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { + profile_start ( &profiler ); + sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, + test->len ); + profile_stop ( &profiler ); + } + DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld +/- %ld ticks\n", + test->len, test->offset, profile_mean ( &profiler ), + profile_stddev ( &profiler ) ); +} +#define tcpip_random_ok( test ) tcpip_random_okx ( test, __FILE__, __LINE__ ) /** * Perform TCP/IP self-tests diff --git a/roms/ipxe/src/tests/test.c b/roms/ipxe/src/tests/test.c index 62f7c97d9..c05e72a76 100644 --- a/roms/ipxe/src/tests/test.c +++ b/roms/ipxe/src/tests/test.c @@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/test.h> #include <ipxe/init.h> #include <ipxe/image.h> +#include <usr/profstat.h> /** Current self-test set */ static struct self_test *current_tests; @@ -45,8 +46,10 @@ static struct self_test *current_tests; * @v success Test succeeded * @v file Test code file * @v line Test code line + * @v test Test code */ -void test_ok ( int success, const char *file, unsigned int line ) { +void test_ok ( int success, const char *file, unsigned int line, + const char *test ) { /* Sanity check */ assert ( current_tests != NULL ); @@ -57,8 +60,8 @@ void test_ok ( int success, const char *file, unsigned int line ) { /* Report failure if applicable */ if ( ! success ) { current_tests->failures++; - printf ( "FAILURE: \"%s\" test failed at %s line %d\n", - current_tests->name, file, line ); + printf ( "FAILURE: \"%s\" test failed at %s line %d: ( %s )\n", + current_tests->name, file, line, test ); } } @@ -132,6 +135,7 @@ static int run_all_tests ( void ) { return -EINPROGRESS; } else { printf ( "OK: all %d tests passed\n", total ); + profstat(); return 0; } } diff --git a/roms/ipxe/src/tests/tests.c b/roms/ipxe/src/tests/tests.c index af969ec8f..2b4b78c7c 100644 --- a/roms/ipxe/src/tests/tests.c +++ b/roms/ipxe/src/tests/tests.c @@ -28,12 +28,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Drag in all applicable self-tests */ REQUIRE_OBJECT ( memcpy_test ); REQUIRE_OBJECT ( string_test ); +REQUIRE_OBJECT ( math_test ); +REQUIRE_OBJECT ( vsprintf_test ); REQUIRE_OBJECT ( list_test ); REQUIRE_OBJECT ( byteswap_test ); REQUIRE_OBJECT ( base64_test ); +REQUIRE_OBJECT ( base16_test ); REQUIRE_OBJECT ( settings_test ); REQUIRE_OBJECT ( time_test ); REQUIRE_OBJECT ( tcpip_test ); +REQUIRE_OBJECT ( ipv6_test ); REQUIRE_OBJECT ( crc32_test ); REQUIRE_OBJECT ( md5_test ); REQUIRE_OBJECT ( sha1_test ); @@ -46,3 +50,9 @@ REQUIRE_OBJECT ( rsa_test ); REQUIRE_OBJECT ( x509_test ); REQUIRE_OBJECT ( ocsp_test ); REQUIRE_OBJECT ( cms_test ); +REQUIRE_OBJECT ( pnm_test ); +REQUIRE_OBJECT ( deflate_test ); +REQUIRE_OBJECT ( png_test ); +REQUIRE_OBJECT ( dns_test ); +REQUIRE_OBJECT ( uri_test ); +REQUIRE_OBJECT ( profile_test ); diff --git a/roms/ipxe/src/tests/uri_test.c b/roms/ipxe/src/tests/uri_test.c index c39c7ffed..14f1b4ad0 100644 --- a/roms/ipxe/src/tests/uri_test.c +++ b/roms/ipxe/src/tests/uri_test.c @@ -1,146 +1,858 @@ -#include <stdint.h> -#include <stddef.h> -#include <stdio.h> +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * URI self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + #include <string.h> -#include <errno.h> +#include <byteswap.h> #include <ipxe/uri.h> +#include <ipxe/params.h> +#include <ipxe/test.h> -#define URI_MAX_LEN 1024 - +/** A URI parsing/formatting test */ struct uri_test { - const char *base_uri_string; - const char *relative_uri_string; - const char *resolved_uri_string; -}; - -static struct uri_test uri_tests[] = { - { "http://www.fensystems.co.uk", "", - "http://www.fensystems.co.uk/" }, - { "http://ipxe.org/wiki/page1", "page2", - "http://ipxe.org/wiki/page2" }, - { "http://ipxe.org/wiki/page1", "../page3", - "http://ipxe.org/page3" }, - { "tftp://192.168.0.1/", "/tftpboot/vmlinuz", - "tftp://192.168.0.1/tftpboot/vmlinuz" }, - { "ftp://the%41nswer%3d:%34ty%32wo@ether%62oot.org:8080/p%41th/foo", - "to?%41=b#%43d", - "ftp://theAnswer%3d:4ty2wo@ipxe.org:8080/path/to?a=b#cd" }, -#if 0 - "http://www.ipxe.org/wiki", - "mailto:bob@nowhere.com", - "ftp://joe:secret@insecure.org:8081/hidden/path/to?what=is#this", -#endif -}; - -static int test_parse_unparse ( const char *uri_string ) { - char buf[URI_MAX_LEN]; - struct uri *uri = NULL; - int rc; - - /* Parse and unparse URI */ - uri = parse_uri ( uri_string ); - if ( ! uri ) { - rc = -ENOMEM; - goto done; - } - unparse_uri ( buf, sizeof ( buf ), uri, URI_ALL ); - - /* Compare result */ - if ( strcmp ( buf, uri_string ) != 0 ) { - printf ( "Unparse of \"%s\" produced \"%s\"\n", - uri_string, buf ); - rc = -EINVAL; - goto done; + /** URI string */ + const char *string; + /** URI */ + struct uri uri; +}; + +/** A URI port number test */ +struct uri_port_test { + /** URI string */ + const char *string; + /** Default port number */ + unsigned int default_port; + /** Expected port number */ + unsigned int port; +}; + +/** A URI or path resolution test */ +struct uri_resolve_test { + /** Base path or URI */ + const char *base; + /** Relative path or URI */ + const char *relative; + /** Expected resolved path or URI */ + const char *resolved; +}; + +/** A TFTP URI test */ +struct uri_tftp_test { + /** Next-server address */ + struct in_addr next_server; + /** Filename */ + const char *filename; + /** URI */ + struct uri uri; + /** URI string (for display only; cannot be reparsed) */ + const char *string; +}; + +/** A current working URI test */ +struct uri_churi_test { + /** Relative URI */ + const char *relative; + /** Expected new working URI */ + const char *expected; +}; + +/** A form parameter URI test list */ +struct uri_params_test_list { + /** Key */ + const char *key; + /** Value */ + const char *value; +}; + +/** A form parameter URI test */ +struct uri_params_test { + /** URI string */ + const char *string; + /** URI */ + struct uri uri; + /** Parameter list name */ + const char *name; + /** Parameter list */ + struct uri_params_test_list *list; +}; + +/** + * Compare two URI component strings + * + * @v first First string, or NULL + * @v second Second string, or NULL + * @v difference Difference + */ +static int uristrcmp ( const char *first, const char *second ) { + + /* Compare strings, allowing for either to be NULL */ + if ( first == second ) { + return 0; + } else if ( ( first == NULL ) || ( second == NULL ) ) { + return -1; + } else { + return strcmp ( first, second ); } +} - rc = 0; +/** + * Report URI equality test result + * + * @v uri URI + * @v expected Expected URI + * @v file Test code file + * @v line Test code line + */ +static void uri_okx ( struct uri *uri, struct uri *expected, const char *file, + unsigned int line ) { - done: + okx ( uristrcmp ( uri->scheme, expected->scheme ) == 0, file, line ); + okx ( uristrcmp ( uri->opaque, expected->opaque ) == 0, file, line ); + okx ( uristrcmp ( uri->user, expected->user ) == 0, file, line ); + okx ( uristrcmp ( uri->password, expected->password ) == 0, file, line); + okx ( uristrcmp ( uri->host, expected->host ) == 0, file, line ); + okx ( uristrcmp ( uri->port, expected->port ) == 0, file, line ); + okx ( uristrcmp ( uri->path, expected->path ) == 0, file, line ); + okx ( uristrcmp ( uri->query, expected->query ) == 0, file, line ); + okx ( uristrcmp ( uri->fragment, expected->fragment ) == 0, file, line); + okx ( uri->params == expected->params, file, line ); +} +#define uri_ok( uri, expected ) uri_okx ( uri, expected, __FILE__, __LINE__ ) + +/** + * Report URI parsing test result + * + * @v test URI test + * @v file Test code file + * @v line Test code line + */ +static void uri_parse_okx ( struct uri_test *test, const char *file, + unsigned int line ) { + struct uri *uri; + + /* Parse URI */ + uri = parse_uri ( test->string ); + okx ( uri != NULL, file, line ); + if ( uri ) + uri_okx ( uri, &test->uri, file, line ); uri_put ( uri ); - if ( rc ) { - printf ( "URI parse-unparse of \"%s\" failed: %s\n", - uri_string, strerror ( rc ) ); +} +#define uri_parse_ok( test ) uri_parse_okx ( test, __FILE__, __LINE__ ) + +/** + * Report URI formatting test result + * + * @v test URI test + * @v file Test code file + * @v line Test code line + */ +static void uri_format_okx ( struct uri_test *test, const char *file, + unsigned int line ) { + char buf[ strlen ( test->string ) + 1 /* NUL */ ]; + char *tmp; + size_t len; + + /* Format into fixed-size buffer */ + len = format_uri ( &test->uri, buf, sizeof ( buf ) ); + okx ( len == ( sizeof ( buf ) - 1 /* NUL */ ), file, line ); + okx ( strcmp ( buf, test->string ) == 0, file, line ); + + /* Format into temporarily allocated buffer */ + tmp = format_uri_alloc ( &test->uri ); + okx ( tmp != NULL, file, line ); + if ( tmp ) + okx ( strcmp ( tmp, test->string ) == 0, file, line ); + free ( tmp ); +} +#define uri_format_ok( test ) uri_format_okx ( test, __FILE__, __LINE__ ) + +/** + * Report URI duplication test result + * + * @v test URI + * @v file Test code file + * @v line Test code line + */ +static void uri_dup_okx ( struct uri *uri, const char *file, + unsigned int line ) { + struct uri *dup; + + dup = uri_dup ( uri ); + okx ( dup != NULL, file, line ); + if ( dup ) + uri_okx ( dup, uri, file, line ); + uri_put ( dup ); +} +#define uri_dup_ok( test ) uri_dup_okx ( test, __FILE__, __LINE__ ) + +/** + * Report URI combined parsing and formatting test result + * + * @v test URI test + * @v file Test code file + * @v line Test code line + */ +static void uri_parse_format_dup_okx ( struct uri_test *test, const char *file, + unsigned int line ) { + + uri_parse_okx ( test, file, line ); + uri_format_okx ( test, file, line ); + uri_dup_okx ( &test->uri, file, line ); +} +#define uri_parse_format_dup_ok( test ) \ + uri_parse_format_dup_okx ( test, __FILE__, __LINE__ ) + +/** + * Report URI port number test result + * + * @v test URI port number test + * @v file Test code file + * @v line Test code line + */ +static void uri_port_okx ( struct uri_port_test *test, const char *file, + unsigned int line ) { + struct uri *uri; + unsigned int port; + + /* Parse URI */ + uri = parse_uri ( test->string ); + okx ( uri != NULL, file, line ); + if ( uri ) { + port = uri_port ( uri, test->default_port ); + okx ( port == test->port, file, line ); } - return rc; + uri_put ( uri ); } +#define uri_port_ok( test ) uri_port_okx ( test, __FILE__, __LINE__ ) -static int test_resolve ( const char *base_uri_string, - const char *relative_uri_string, - const char *resolved_uri_string ) { - struct uri *base_uri = NULL; - struct uri *relative_uri = NULL; - struct uri *resolved_uri = NULL; - char buf[URI_MAX_LEN]; - int rc; +/** + * Report URI resolution test result + * + * @v test Path resolution test + * @v file Test code file + * @v line Test code line + */ +static void uri_resolve_okx ( struct uri_resolve_test *test, + const char *file, unsigned int line ) { + struct uri *base; + struct uri *relative; + struct uri *resolved = NULL; + char *formatted; /* Parse URIs */ - base_uri = parse_uri ( base_uri_string ); - if ( ! base_uri ) { - rc = -ENOMEM; - goto done; - } - relative_uri = parse_uri ( relative_uri_string ); - if ( ! relative_uri ) { - rc = -ENOMEM; - goto done; + base = parse_uri ( test->base ); + okx ( base != NULL, file, line ); + relative = parse_uri ( test->relative ); + okx ( relative != NULL, file, line ); + + /* Resolve URI */ + if ( base && relative ) { + resolved = resolve_uri ( base, relative ); + okx ( resolved != NULL, file, line ); } - /* Resolve URI */ - resolved_uri = resolve_uri ( base_uri, relative_uri ); - if ( ! resolved_uri ) { - rc = -ENOMEM; - goto done; + /* Format resolved URI */ + formatted = format_uri_alloc ( resolved ); + okx ( formatted != NULL, file, line ); + + /* Check resolved URI */ + if ( formatted ) + okx ( strcmp ( formatted, test->resolved ) == 0, file, line ); + + free ( formatted ); + uri_put ( resolved ); + uri_put ( relative ); + uri_put ( base ); +} +#define uri_resolve_ok( test ) uri_resolve_okx ( test, __FILE__, __LINE__ ) + +/** + * Report path resolution test result + * + * @v test Path resolution test + * @v file Test code file + * @v line Test code line + */ +static void uri_resolve_path_okx ( struct uri_resolve_test *test, + const char *file, unsigned int line ) { + char *resolved; + + /* Resolve paths using resolve_path() directly */ + resolved = resolve_path ( test->base, test->relative ); + okx ( resolved != NULL, file, line ); + if ( resolved ) + okx ( strcmp ( resolved, test->resolved ) == 0, file, line ); + free ( resolved ); + + /* Resolve paths as URIs (since all paths are valid URIs) */ + uri_resolve_okx ( test, file, line ); +} +#define uri_resolve_path_ok( test ) \ + uri_resolve_path_okx ( test, __FILE__, __LINE__ ) + +/** + * Report URI TFTP test result + * + * @v test URI TFTP test + * @v file Test code file + * @v line Test code line + */ +static void uri_tftp_okx ( struct uri_tftp_test *test, const char *file, + unsigned int line ) { + char buf[ strlen ( test->string ) + 1 /* NUL */ ]; + struct uri *uri; + size_t len; + + /* Construct URI */ + uri = tftp_uri ( test->next_server, test->filename ); + okx ( uri != NULL, file, line ); + if ( uri ) { + uri_okx ( uri, &test->uri, file, line ); + len = format_uri ( uri, buf, sizeof ( buf ) ); + okx ( len == ( sizeof ( buf ) - 1 /* NUL */ ), file, line ); + okx ( strcmp ( buf, test->string ) == 0, file, line ); } + uri_put ( uri ); +} +#define uri_tftp_ok( test ) uri_tftp_okx ( test, __FILE__, __LINE__ ) + +/** + * Report current working URI test result + * + * @v tests List of current working URI tests + * @v file Test code file + * @v line Test code line + */ +static void uri_churi_okx ( struct uri_churi_test *test, const char *file, + unsigned int line ) { + struct uri *old_cwuri; + struct uri *uri; + char *formatted; + + /* Preserve original current working URI */ + old_cwuri = uri_get ( cwuri ); - /* Compare result */ - unparse_uri ( buf, sizeof ( buf ), resolved_uri, URI_ALL ); - if ( strcmp ( buf, resolved_uri_string ) != 0 ) { - printf ( "Resolution of \"%s\"+\"%s\" produced \"%s\"\n", - base_uri_string, relative_uri_string, buf ); - rc = -EINVAL; - goto done; + /* Perform sequence of current working URI changes */ + do { + /* Parse relative URI */ + uri = parse_uri ( test->relative ); + okx ( uri != NULL, file, line ); + + /* Move to this URI */ + churi ( uri ); + + /* Format new current working URI */ + formatted = format_uri_alloc ( cwuri ); + okx ( formatted != NULL, file, line ); + if ( formatted ) { + okx ( strcmp ( formatted, test->expected ) == 0, + file, line ); + } + + /* Free temporary storage */ + free ( formatted ); + uri_put ( uri ); + + /* Move to next current working URI test */ + test++; + + } while ( test->relative != NULL ); + + /* Restore original current working URI */ + churi ( old_cwuri ); + uri_put ( old_cwuri ); +} +#define uri_churi_ok( test ) uri_churi_okx ( test, __FILE__, __LINE__ ) + +/** + * Report form parameter URI test list result + * + * @v test Form parameter URI test + * @v uri URI + * @v file Test code file + * @v line Test code line + */ +static void uri_params_list_okx ( struct uri_params_test *test, + struct uri *uri, const char *file, + unsigned int line ) { + struct uri_params_test_list *list; + struct parameter *param; + + /* Check URI */ + uri_okx ( uri, &test->uri, file, line ); + + /* Check URI parameters */ + okx ( uri->params != NULL, file, line ); + if ( uri->params ) { + list = test->list; + for_each_param ( param, uri->params ) { + okx ( strcmp ( param->key, list->key ) == 0, + file, line ); + okx ( strcmp ( param->value, list->value ) == 0, + file, line ); + list++; + } + okx ( list->key == NULL, file, line ); } +} +#define uri_params_list_ok( test ) \ + uri_params_list_okx ( test, __FILE__, __LINE__ ) - rc = 0; +/** + * Report form parameter URI test result + * + * @v test Form parameter URI test + * @v file Test code file + * @v line Test code line + */ +static void uri_params_okx ( struct uri_params_test *test, const char *file, + unsigned int line ) { + struct uri_params_test_list *list; + struct parameters *params; + struct parameter *param; + struct uri *uri; + struct uri *dup; - done: - uri_put ( base_uri ); - uri_put ( relative_uri ); - uri_put ( resolved_uri ); - if ( rc ) { - printf ( "URI resolution of \"%s\"+\"%s\" failed: %s\n", - base_uri_string, relative_uri_string, - strerror ( rc ) ); + /* Create parameter list */ + params = create_parameters ( test->name ); + okx ( params != NULL, file, line ); + if ( params ) { + for ( list = test->list ; list->key ; list++ ) { + param = add_parameter ( params, list->key, list->value); + okx ( param != NULL, file, line ); + } } - return rc; + + /* Record parameter list as part of expected URI */ + test->uri.params = params; + + /* Parse URI */ + uri = parse_uri ( test->string ); + okx ( uri != NULL, file, line ); + if ( uri ) + uri_params_list_okx ( test, uri, file, line ); + + /* Duplicate URI */ + dup = uri_dup ( uri ); + okx ( dup != NULL, file, line ); + if ( dup ) + uri_params_list_okx ( test, dup, file, line ); + + /* Clear parameter list in expected URI */ + test->uri.params = NULL; + + uri_put ( uri ); + uri_put ( dup ); } +#define uri_params_ok( test ) uri_params_okx ( test, __FILE__, __LINE__ ) -int uri_test ( void ) { - unsigned int i; - struct uri_test *uri_test; - int rc; - int overall_rc = 0; - - for ( i = 0 ; i < ( sizeof ( uri_tests ) / - sizeof ( uri_tests[0] ) ) ; i++ ) { - uri_test = &uri_tests[i]; - rc = test_parse_unparse ( uri_test->base_uri_string ); - if ( rc != 0 ) - overall_rc = rc; - rc = test_parse_unparse ( uri_test->relative_uri_string ); - if ( rc != 0 ) - overall_rc = rc; - rc = test_parse_unparse ( uri_test->resolved_uri_string ); - if ( rc != 0 ) - overall_rc = rc; - rc = test_resolve ( uri_test->base_uri_string, - uri_test->relative_uri_string, - uri_test->resolved_uri_string ); - if ( rc != 0 ) - overall_rc = rc; +/** Empty URI */ +static struct uri_test uri_empty = { + .string = "", +}; + +/** Basic HTTP URI */ +static struct uri_test uri_boot_ipxe_org = { + "http://boot.ipxe.org/demo/boot.php", + { .scheme = "http", .host = "boot.ipxe.org", .path = "/demo/boot.php" } +}; + +/** Basic opaque URI */ +static struct uri_test uri_mailto = { + "mailto:ipxe-devel@lists.ipxe.org", + { .scheme = "mailto", .opaque = "ipxe-devel@lists.ipxe.org" } +}; + +/** HTTP URI with all the trimmings */ +static struct uri_test uri_http_all = { + "http://anon:password@example.com:3001/~foo/cgi-bin/foo.pl?a=b&c=d#bit", + { + .scheme = "http", + .user = "anon", + .password = "password", + .host = "example.com", + .port = "3001", + .path = "/~foo/cgi-bin/foo.pl", + .query = "a=b&c=d", + .fragment = "bit", + }, +}; + +/** HTTP URI with escaped characters */ +static struct uri_test uri_http_escaped = { + "https://test.ipxe.org/wtf%3F%0A?kind%23of/uri%20is#this%3F", + { + .scheme = "https", + .host = "test.ipxe.org", + .path = "/wtf?\n", + .query = "kind#of/uri is", + .fragment = "this?", + }, +}; + +/** HTTP URI with improperly escaped characters */ +static struct uri_test uri_http_escaped_improper = { + /* We accept for parsing improperly escaped characters. + * (Formatting the parsed URI would produce the properly + * encoded form, and so would not exactly match the original + * URI string.) + */ + "https://test%2eipxe.org/wt%66%3f\n?kind%23of/uri is#this?", + { + .scheme = "https", + .host = "test.ipxe.org", + .path = "/wtf?\n", + .query = "kind#of/uri is", + .fragment = "this?", + }, +}; + +/** IPv6 URI */ +static struct uri_test uri_ipv6 = { + "http://[2001:ba8:0:1d4::6950:5845]/", + { + .scheme = "http", + .host = "[2001:ba8:0:1d4::6950:5845]", + .path = "/", + }, +}; + +/** IPv6 URI with port */ +static struct uri_test uri_ipv6_port = { + "http://[2001:ba8:0:1d4::6950:5845]:8001/boot", + { + .scheme = "http", + .host = "[2001:ba8:0:1d4::6950:5845]", + .port = "8001", + .path = "/boot", + }, +}; + +/** IPv6 URI with link-local address */ +static struct uri_test uri_ipv6_local = { + "http://[fe80::69ff:fe50:5845%25net0]/ipxe", + { + .scheme = "http", + .host = "[fe80::69ff:fe50:5845%net0]", + .path = "/ipxe", + }, +}; + +/** IPv6 URI with link-local address not conforming to RFC 6874 */ +static struct uri_test uri_ipv6_local_non_conforming = { + /* We accept for parsing a single "%" in "%net0" (rather than + * the properly encoded form "%25net0"). (Formatting the + * parsed URI would produce the properly encoded form, and so + * would not exactly match the original URI string.) + */ + "http://[fe80::69ff:fe50:5845%net0]/ipxe", + { + .scheme = "http", + .host = "[fe80::69ff:fe50:5845%net0]", + .path = "/ipxe", + }, +}; + +/** iSCSI URI */ +static struct uri_test uri_iscsi = { + "iscsi:10.253.253.1::::iqn.2010-04.org.ipxe:rabbit", + { + .scheme = "iscsi", + .opaque = "10.253.253.1::::iqn.2010-04.org.ipxe:rabbit", + }, +}; + +/** URI with port number */ +static struct uri_port_test uri_explicit_port = { + "http://192.168.0.1:8080/boot.php", + 80, + 8080, +}; + +/** URI without port number */ +static struct uri_port_test uri_default_port = { + "http://192.168.0.1/boot.php", + 80, + 80, +}; + +/** Simple path resolution test */ +static struct uri_resolve_test uri_simple_path = { + "/etc/passwd", + "group", + "/etc/group", +}; + +/** Path resolution test with "." and ".." elements */ +static struct uri_resolve_test uri_relative_path = { + "/var/lib/tftpboot/pxe/pxelinux.0", + "./../ipxe/undionly.kpxe", + "/var/lib/tftpboot/ipxe/undionly.kpxe", +}; + +/** Path resolution test terminating with directory */ +static struct uri_resolve_test uri_directory_path = { + "/test/cgi-bin.pl/boot.ipxe", + "..", + "/test/", +}; + +/** Path resolution test with excessive ".." elements */ +static struct uri_resolve_test uri_excessive_path = { + "/var/lib/tftpboot/ipxe.pxe", + "../../../../../../../foo", + "/foo", +}; + +/** Path resolution test with absolute path */ +static struct uri_resolve_test uri_absolute_path = { + "/var/lib/tftpboot", + "/etc/hostname", + "/etc/hostname", +}; + +/** Relative URI resolution test */ +static struct uri_resolve_test uri_relative = { + "http://boot.ipxe.org/demo/boot.php?vendor=10ec&device=8139", + "initrd.img", + "http://boot.ipxe.org/demo/initrd.img", +}; + +/** Absolute URI resolution test */ +static struct uri_resolve_test uri_absolute = { + "http://boot.ipxe.org/demo/boot.php", + "ftp://192.168.0.1/boot.ipxe", + "ftp://192.168.0.1/boot.ipxe", +}; + +/** Absolute path URI resolution test */ +static struct uri_resolve_test uri_absolute_uri_path = { + "http://boot.ipxe.org/demo/boot.php#test", + "/demo/vmlinuz", + "http://boot.ipxe.org/demo/vmlinuz", +}; + +/** Query URI resolution test */ +static struct uri_resolve_test uri_query = { + "http://10.253.253.1/test.pl?mac=02-00-69-50-58-45", + "?mac=00-1f-16-bc-fe-2f", + "http://10.253.253.1/test.pl?mac=00-1f-16-bc-fe-2f", +}; + +/** Fragment URI resolution test */ +static struct uri_resolve_test uri_fragment = { + "http://192.168.0.254/test#foo", + "#bar", + "http://192.168.0.254/test#bar", +}; + +/** TFTP URI with absolute path */ +static struct uri_tftp_test uri_tftp_absolute = { + { .s_addr = htonl ( 0xc0a80002 ) /* 192.168.0.2 */ }, + "/absolute/path", + { + .scheme = "tftp", + .host = "192.168.0.2", + .path = "/absolute/path", + }, + "tftp://192.168.0.2/absolute/path", +}; + +/** TFTP URI with relative path */ +static struct uri_tftp_test uri_tftp_relative = { + { .s_addr = htonl ( 0xc0a80003 ) /* 192.168.0.3 */ }, + "relative/path", + { + .scheme = "tftp", + .host = "192.168.0.3", + .path = "relative/path", + }, + "tftp://192.168.0.3/relative/path", +}; + +/** TFTP URI with path containing special characters */ +static struct uri_tftp_test uri_tftp_icky = { + { .s_addr = htonl ( 0x0a000006 ) /* 10.0.0.6 */ }, + "C:\\tftpboot\\icky#path", + { + .scheme = "tftp", + .host = "10.0.0.6", + .path = "C:\\tftpboot\\icky#path", + }, + "tftp://10.0.0.6/C%3A\\tftpboot\\icky%23path", +}; + +/** Current working URI test */ +static struct uri_churi_test uri_churi[] = { + { + "http://boot.ipxe.org/demo/boot.php", + "http://boot.ipxe.org/demo/boot.php", + }, + { + "?vendor=10ec&device=8139", + "http://boot.ipxe.org/demo/boot.php?vendor=10ec&device=8139", + }, + { + "fedora/fedora.ipxe", + "http://boot.ipxe.org/demo/fedora/fedora.ipxe", + }, + { + "vmlinuz", + "http://boot.ipxe.org/demo/fedora/vmlinuz", + }, + { + "http://local/boot/initrd.img", + "http://local/boot/initrd.img", + }, + { + "modules/8139too.ko", + "http://local/boot/modules/8139too.ko", + }, + { + NULL, + NULL, } +}; - if ( overall_rc ) - printf ( "URI tests failed: %s\n", strerror ( overall_rc ) ); - return overall_rc; +/** Form parameter URI test list */ +static struct uri_params_test_list uri_params_list[] = { + { + "vendor", + "10ec", + }, + { + "device", + "8139", + }, + { + "uuid", + "f59fac00-758f-498f-9fe5-87d790045d94", + }, + { + NULL, + NULL, + } +}; + +/** Form parameter URI test */ +static struct uri_params_test uri_params = { + "http://boot.ipxe.org/demo/boot.php##params", + { + .scheme = "http", + .host = "boot.ipxe.org", + .path = "/demo/boot.php", + }, + NULL, + uri_params_list, +}; + +/** Named form parameter URI test list */ +static struct uri_params_test_list uri_named_params_list[] = { + { + "mac", + "00:1e:65:80:d3:b6", + }, + { + "serial", + "LXTQ20Z1139322762F2000", + }, + { + NULL, + NULL, + } +}; + +/** Named form parameter URI test */ +static struct uri_params_test uri_named_params = { + "http://192.168.100.4:3001/register##params=foo", + { + .scheme = "http", + .host = "192.168.100.4", + .port = "3001", + .path = "/register", + }, + "foo", + uri_named_params_list, +}; + +/** + * Perform URI self-test + * + */ +static void uri_test_exec ( void ) { + + /* URI parsing, formatting, and duplication tests */ + uri_parse_format_dup_ok ( &uri_empty ); + uri_parse_format_dup_ok ( &uri_boot_ipxe_org ); + uri_parse_format_dup_ok ( &uri_mailto ); + uri_parse_format_dup_ok ( &uri_http_all ); + uri_parse_format_dup_ok ( &uri_http_escaped ); + uri_parse_ok ( &uri_http_escaped_improper ); /* Parse only */ + uri_parse_format_dup_ok ( &uri_ipv6 ); + uri_parse_format_dup_ok ( &uri_ipv6_port ); + uri_parse_format_dup_ok ( &uri_ipv6_local ); + uri_parse_ok ( &uri_ipv6_local_non_conforming ); /* Parse only */ + uri_parse_format_dup_ok ( &uri_iscsi ); + + /** URI port number tests */ + uri_port_ok ( &uri_explicit_port ); + uri_port_ok ( &uri_default_port ); + + /** Path resolution tests */ + uri_resolve_path_ok ( &uri_simple_path ); + uri_resolve_path_ok ( &uri_relative_path ); + uri_resolve_path_ok ( &uri_directory_path ); + uri_resolve_path_ok ( &uri_excessive_path ); + uri_resolve_path_ok ( &uri_absolute_path ); + + /** URI resolution tests */ + uri_resolve_ok ( &uri_relative ); + uri_resolve_ok ( &uri_absolute ); + uri_resolve_ok ( &uri_absolute_uri_path ); + uri_resolve_ok ( &uri_query ); + uri_resolve_ok ( &uri_fragment ); + + /* TFTP URI construction tests */ + uri_tftp_ok ( &uri_tftp_absolute ); + uri_tftp_ok ( &uri_tftp_relative ); + uri_tftp_ok ( &uri_tftp_icky ); + + /* Current working URI tests */ + uri_churi_ok ( uri_churi ); + + /* Form parameter URI tests */ + uri_params_ok ( &uri_params ); + uri_params_ok ( &uri_named_params ); } + +/** URI self-test */ +struct self_test uri_test __self_test = { + .name = "uri", + .exec = uri_test_exec, +}; diff --git a/roms/ipxe/src/tests/vsprintf_test.c b/roms/ipxe/src/tests/vsprintf_test.c new file mode 100644 index 000000000..11512ec8e --- /dev/null +++ b/roms/ipxe/src/tests/vsprintf_test.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * vsprintf() self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <stdio.h> +#include <ipxe/test.h> + +/** + * Report an snprintf() test result + * + */ +#define snprintf_ok( len, result, format, ... ) do { \ + char actual[ (len) ]; \ + const char expected[] = result; \ + size_t actual_len; \ + \ + actual_len = snprintf ( actual, sizeof ( actual ), \ + format, ##__VA_ARGS__ ); \ + ok ( actual_len >= strlen ( result ) ); \ + ok ( strcmp ( actual, expected ) == 0 ); \ + if ( strcmp ( actual, expected ) != 0 ) { \ + DBG ( "SNPRINTF expected \"%s\", got \"%s\"\n", \ + expected, actual ); \ + } \ + } while ( 0 ) + +/** + * Perform vsprintf() self-tests + * + */ +static void vsprintf_test_exec ( void ) { + + /* Constant string */ + snprintf_ok ( 16, "Testing", "Testing" ); + + /* Constant string, truncated to fit */ + snprintf_ok ( 5, "Test", "Testing" ); + + /* Basic format specifiers */ + snprintf_ok ( 16, "%", "%%" ); + snprintf_ok ( 16, "ABC", "%c%c%c", 'A', 'B', 'C' ); + snprintf_ok ( 16, "abc", "%lc%lc%lc", L'a', L'b', L'c' ); + snprintf_ok ( 16, "Hello world", "%s %s", "Hello", "world" ); + snprintf_ok ( 16, "Goodbye world", "%ls %s", L"Goodbye", "world" ); + snprintf_ok ( 16, "0x1234abcd", "%p", ( ( void * ) 0x1234abcd ) ); + snprintf_ok ( 16, "0xa723", "%#x", 0xa723 ); + snprintf_ok ( 16, "a723", "%x", 0xa723 ); + snprintf_ok ( 16, "0x0000a723", "%#08x", 0xa723 ); + snprintf_ok ( 16, "00A723", "%06X", 0xa723 ); + snprintf_ok ( 16, "9876abcd", "%lx", 0x9876abcdUL ); + snprintf_ok ( 16, "1234 5678", "%04llx %04llx", 0x1234ULL, 0x5678ULL ); + snprintf_ok ( 16, "123", "%d", 123 ); + snprintf_ok ( 16, "456", "%i", 456 ); + snprintf_ok ( 16, " 99", "%3d", 99 ); + snprintf_ok ( 16, "099", "%03d", 99 ); + snprintf_ok ( 16, "-72", "%d", -72 ); + snprintf_ok ( 16, " -72", "%4d", -72 ); + snprintf_ok ( 16, "-072", "%04d", -72 ); + snprintf_ok ( 16, "4", "%zd", sizeof ( uint32_t ) ); + snprintf_ok ( 16, "123456789", "%d", 123456789 ); + + /* Realistic combinations */ + snprintf_ok ( 64, "DBG 0x1234 thingy at 0x0003f0c0+0x5c\n", + "DBG %p %s at %#08lx+%#zx\n", ( ( void * ) 0x1234 ), + "thingy", 0x3f0c0UL, ( ( size_t ) 0x5c ) ); + snprintf_ok ( 64, "PCI 00:1f.3", "PCI %02x:%02x.%x", 0x00, 0x1f, 0x03 ); + snprintf_ok ( 64, "Region [1000000,3f000000)", "Region [%llx,%llx)", + 0x1000000ULL, 0x3f000000ULL ); +} + +/** vsprintf() self-test */ +struct self_test vsprintf_test __self_test = { + .name = "vsprintf", + .exec = vsprintf_test_exec, +}; diff --git a/roms/ipxe/src/tests/x509_test.c b/roms/ipxe/src/tests/x509_test.c index c014bd2e0..d3e01faf1 100644 --- a/roms/ipxe/src/tests/x509_test.c +++ b/roms/ipxe/src/tests/x509_test.c @@ -413,75 +413,81 @@ CERTIFICATE ( useless_crt, * issuer iPXE self-test leaf CA */ CERTIFICATE ( server_crt, - DATA ( 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, 0x01, 0xe6, 0x02, 0x01, - 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, - 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, - 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, - 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, - 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, - 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, - 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, - 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, - 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, - 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, - 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, - 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, - 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, - 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, - 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, - 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, - 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, - 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x84, - 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, - 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, - 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, - 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, - 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, - 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, - 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, - 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, - 0x6f, 0x72, 0x67, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, - 0x04, 0x03, 0x0c, 0x12, 0x62, 0x6f, 0x6f, 0x74, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, - 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, - 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, - 0x00, 0xbd, 0x43, 0x97, 0x45, 0xa2, 0xe0, 0x1d, 0x38, 0x41, - 0xb0, 0xd9, 0x91, 0xf9, 0x77, 0xa9, 0xcb, 0x9c, 0x9c, 0x93, - 0xfe, 0x5a, 0xee, 0xbc, 0xd9, 0x0f, 0x39, 0xf6, 0x42, 0xe4, - 0x55, 0x21, 0xbb, 0x11, 0xfd, 0xfd, 0xba, 0x25, 0x58, 0xc8, - 0xc6, 0xa5, 0x3b, 0x6f, 0x80, 0xba, 0x5b, 0xbc, 0x89, 0xca, - 0x7a, 0xdf, 0x6e, 0xb9, 0x81, 0xb6, 0x25, 0x67, 0x0a, 0x38, - 0x10, 0xf8, 0x26, 0x43, 0x0c, 0x51, 0x02, 0x14, 0xd6, 0xf2, - 0x9d, 0x7c, 0xf5, 0x25, 0x1c, 0x78, 0x4d, 0x47, 0xaf, 0x87, - 0x2e, 0x38, 0x49, 0x87, 0xb5, 0x8a, 0xf3, 0xb5, 0xd4, 0x15, - 0x69, 0x2a, 0x52, 0xc9, 0x46, 0x97, 0x34, 0x8e, 0x50, 0x4b, - 0xc4, 0xf2, 0xfb, 0x39, 0xfd, 0x16, 0x68, 0xdb, 0xa8, 0x17, - 0xe2, 0x71, 0x4b, 0xe0, 0xdf, 0x3d, 0xfc, 0xc3, 0x9b, 0x9d, - 0x22, 0xc9, 0xd3, 0xf6, 0x02, 0xa6, 0x60, 0xef, 0xf7, 0x02, - 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, - 0x81, 0x81, 0x00, 0x7d, 0xff, 0x73, 0xf3, 0x68, 0xe3, 0x75, - 0xf1, 0xcf, 0xac, 0x2e, 0x23, 0x73, 0xea, 0xd1, 0x26, 0x33, - 0xbf, 0xf9, 0x56, 0xdf, 0xbf, 0x98, 0x20, 0x84, 0x08, 0x78, - 0x6b, 0xe6, 0x71, 0x7e, 0x22, 0x68, 0x4d, 0x6c, 0xbb, 0xd5, - 0xcc, 0xb4, 0x28, 0x33, 0x5e, 0xbe, 0x4d, 0x10, 0x16, 0x9f, - 0x65, 0x3b, 0x68, 0x90, 0xa7, 0xf7, 0x9d, 0x57, 0x71, 0x45, - 0x39, 0x86, 0x4c, 0xc0, 0x97, 0x34, 0x03, 0x9c, 0x2b, 0x25, - 0x05, 0xb1, 0x5c, 0x0c, 0x4e, 0xf2, 0x14, 0xbf, 0xcf, 0xf0, - 0x9a, 0x2d, 0xcf, 0x02, 0x47, 0x60, 0xd2, 0xe9, 0xed, 0xbf, - 0x71, 0x5d, 0x07, 0x09, 0x01, 0x87, 0xeb, 0xf7, 0xa8, 0x26, - 0x86, 0x24, 0x59, 0xf0, 0x31, 0x3b, 0x42, 0xd1, 0xf1, 0xfd, - 0x7c, 0x49, 0x5f, 0x1a, 0xf0, 0x41, 0x67, 0xf0, 0x16, 0x3a, - 0xfd, 0xb6, 0xb5, 0xf6, 0x2e, 0x0c, 0x18, 0x1f, 0x09, 0x8e, - 0x4d ), - FINGERPRINT ( 0xe0, 0xdb, 0x60, 0x53, 0x7c, 0xf6, 0x25, 0x8f, - 0xa7, 0xba, 0xdf, 0xe2, 0x1a, 0xfc, 0x27, 0x49, - 0xf6, 0x83, 0x15, 0xbd, 0x1b, 0x4c, 0x3f, 0x36, - 0x6f, 0x33, 0xf2, 0x47, 0x8e, 0x8b, 0x38, 0xa8 ) ); + DATA ( 0x30, 0x82, 0x02, 0xba, 0x30, 0x82, 0x02, 0x23, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x18, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, + 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x30, 0x35, + 0x31, 0x33, 0x34, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, + 0x33, 0x30, 0x33, 0x30, 0x35, 0x31, 0x33, 0x34, 0x35, 0x30, + 0x30, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1b, + 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x62, + 0x6f, 0x6f, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, + 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0x9d, 0x87, 0xe4, 0xa7, + 0xcf, 0x12, 0x08, 0x43, 0x4c, 0x90, 0x8b, 0x10, 0x7d, 0xcc, + 0x94, 0x1e, 0x5e, 0xef, 0xa7, 0x90, 0xbc, 0xe8, 0xe4, 0xee, + 0xd9, 0xb4, 0xd9, 0x63, 0x55, 0xc7, 0x03, 0x98, 0x42, 0xd7, + 0x4e, 0xaf, 0xd7, 0xdc, 0x40, 0x83, 0x61, 0x1b, 0xcc, 0x7b, + 0xf5, 0x1d, 0xba, 0x9f, 0x66, 0xfb, 0xe7, 0x42, 0xbd, 0xd7, + 0xac, 0xeb, 0x3c, 0xa2, 0x99, 0x6a, 0xe4, 0x8f, 0xb4, 0x06, + 0x4e, 0xc3, 0x3b, 0x62, 0xcd, 0x6a, 0x30, 0x0a, 0xe0, 0xb1, + 0x50, 0x83, 0x77, 0xc4, 0x97, 0x15, 0xc4, 0x7c, 0x40, 0xb8, + 0x60, 0x39, 0x07, 0x72, 0x4b, 0xd2, 0x61, 0x5c, 0xd0, 0xac, + 0x21, 0x9b, 0x85, 0xba, 0x53, 0x39, 0x1d, 0xef, 0xe9, 0xb7, + 0x69, 0xed, 0x7f, 0x1c, 0x38, 0x56, 0x0a, 0xe5, 0x24, 0xd0, + 0x1a, 0xa5, 0x9a, 0xd2, 0x5e, 0x1b, 0x47, 0x42, 0x49, 0x08, + 0x0d, 0x68, 0x2d, 0xc9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x03, 0x55, 0x1d, 0x11, + 0x04, 0x2b, 0x30, 0x29, 0x82, 0x12, 0x64, 0x65, 0x6d, 0x6f, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x13, 0x2a, 0x2e, 0x61, 0x6c, + 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x23, 0x16, 0x6a, 0x10, 0x55, 0x44, + 0xb9, 0x9d, 0x9f, 0x9f, 0x53, 0x51, 0x3d, 0x7d, 0x33, 0xa1, + 0x84, 0xb2, 0x5a, 0xfb, 0x1d, 0x76, 0xd5, 0xb1, 0x79, 0x66, + 0xf5, 0xe3, 0xa6, 0x58, 0x2e, 0x3d, 0xec, 0x9f, 0xcf, 0x7d, + 0x75, 0x3b, 0xd7, 0xe8, 0xf6, 0x96, 0xd7, 0xdd, 0x89, 0x1e, + 0x30, 0x25, 0xd9, 0xbb, 0xc0, 0x99, 0xc0, 0x1f, 0x1b, 0x4f, + 0xa6, 0x8e, 0xd5, 0x76, 0x50, 0x18, 0xa1, 0x7a, 0x48, 0x08, + 0xd5, 0x75, 0xee, 0x20, 0x82, 0x12, 0xc0, 0xe8, 0xeb, 0xf1, + 0x50, 0xee, 0x9d, 0xbd, 0x73, 0x7c, 0xb5, 0x13, 0x05, 0x91, + 0x1f, 0xc6, 0x50, 0x08, 0xbc, 0x98, 0xde, 0x43, 0x9a, 0xa4, + 0x9f, 0x69, 0xf7, 0x6e, 0x36, 0x20, 0x42, 0x80, 0x72, 0xba, + 0x0d, 0x63, 0x4c, 0xc5, 0x00, 0x0d, 0x85, 0xaa, 0x14, 0x38, + 0x28, 0x11, 0x3e, 0xa2, 0xcc, 0xc2, 0xac, 0xe8, 0xa7, 0xbe, + 0x0a, 0xa0 ), + FINGERPRINT ( 0x2f, 0xd3, 0xe0, 0x69, 0xde, 0xbc, 0x7c, 0x39, + 0xa7, 0xee, 0x23, 0x3b, 0xf5, 0x92, 0xf5, 0xbe, + 0x05, 0xab, 0xb5, 0xf8, 0x42, 0x9e, 0xf5, 0x9c, + 0x24, 0xde, 0x9e, 0x1f, 0xeb, 0xed, 0xd1, 0x20 ) ); /* * subject not.a.ca.test.ipxe.org @@ -654,14 +660,20 @@ CHAIN ( useless_chain, &useless_crt, &leaf_crt, &intermediate_crt, &root_crt ); CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt, &intermediate_crt, &root_crt ); -/** Certificate store containing the iPXE self-test root CA */ +/** Empty certificate store */ +static struct x509_chain empty_store = { + .refcnt = REF_INIT ( ref_no_free ), + .links = LIST_HEAD_INIT ( empty_store.links ), +}; + +/** Root certificate list containing the iPXE self-test root CA */ static struct x509_root test_root = { .digest = &x509_test_algorithm, .count = 1, .fingerprints = root_crt_fingerprint, }; -/** Certificate store containing the iPXE self-test intermediate CA */ +/** Root certificate list containing the iPXE self-test intermediate CA */ static struct x509_root intermediate_root = { .digest = &x509_test_algorithm, .count = 1, @@ -695,144 +707,264 @@ static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */ * Report certificate parsing test result * * @v crt Test certificate + * @v file Test code file + * @v line Test code line */ -#define x509_certificate_ok( crt ) do { \ - ok ( x509_certificate ( (crt)->data, (crt)->len, \ - &(crt)->cert ) == 0 ); \ - } while ( 0 ) +static void x509_certificate_okx ( struct x509_test_certificate *crt, + const char *file, unsigned int line ) { + + okx ( x509_certificate ( crt->data, crt->len, &crt->cert ) == 0, + file, line ); +} +#define x509_certificate_ok( crt ) \ + x509_certificate_okx ( crt, __FILE__, __LINE__ ) /** * Report cached certificate parsing test result * * @v crt Test certificate + * @v file Test code file + * @v line Test code line */ -#define x509_cached_ok( crt ) do { \ - struct x509_certificate *temp; \ - ok ( x509_certificate ( (crt)->data, (crt)->len, \ - &temp ) == 0 ); \ - ok ( temp == (crt)->cert ); \ - x509_put ( temp ); \ - } while ( 0 ) +static void x509_cached_okx ( struct x509_test_certificate *crt, + const char *file, unsigned int line ) { + struct x509_certificate *temp; + + okx ( x509_certificate ( crt->data, crt->len, &temp ) == 0, + file, line ); + okx ( temp == crt->cert, file, line ); + x509_put ( temp ); +} +#define x509_cached_ok( crt ) x509_cached_okx ( crt, __FILE__, __LINE__ ) /** * Report certificate fingerprint test result * * @v crt Test certificate + * @v file Test code file + * @v line Test code line */ -#define x509_fingerprint_ok( crt ) do { \ - uint8_t fingerprint[ x509_test_algorithm.digestsize ]; \ - x509_fingerprint ( (crt)->cert, &x509_test_algorithm, \ - fingerprint ); \ - ok ( memcmp ( fingerprint, (crt)->fingerprint, \ - sizeof ( fingerprint ) ) == 0 ); \ - } while ( 0 ) +static void x509_fingerprint_okx ( struct x509_test_certificate *crt, + const char *file, unsigned int line ) { + uint8_t fingerprint[ x509_test_algorithm.digestsize ]; + + x509_fingerprint ( crt->cert, &x509_test_algorithm, fingerprint ); + okx ( memcmp ( fingerprint, crt->fingerprint, + sizeof ( fingerprint ) ) == 0, file, line ); +} +#define x509_fingerprint_ok( crt ) \ + x509_fingerprint_okx ( crt, __FILE__, __LINE__ ) /** * Report certificate issuer validation test result * * @v crt Test certificate * @v issuer Test issuer + * @v file Test code file + * @v line Test code line */ -#define x509_check_issuer_ok( crt, issuer ) do { \ - ok ( x509_check_issuer ( (crt)->cert, (issuer)->cert ) == 0 ); \ - } while ( 0 ) +static void x509_check_issuer_okx ( struct x509_test_certificate *crt, + struct x509_test_certificate *issuer, + const char *file, unsigned int line ) { + + okx ( x509_check_issuer ( crt->cert, issuer->cert ) == 0, file, line ); +} +#define x509_check_issuer_ok( crt, issuer ) \ + x509_check_issuer_okx ( crt, issuer, __FILE__, __LINE__ ) /** * Report certificate issuer validation failure test result * * @v crt Test certificate * @v issuer Test issuer + * @v file Test code file + * @v line Test code line */ -#define x509_check_issuer_fail_ok( crt, issuer ) do { \ - ok ( x509_check_issuer ( (crt)->cert, (issuer)->cert ) != 0 ); \ - } while ( 0 ) +static void x509_check_issuer_fail_okx ( struct x509_test_certificate *crt, + struct x509_test_certificate *issuer, + const char *file, unsigned int line ) { + + okx ( x509_check_issuer ( crt->cert, issuer->cert ) != 0, + file, line ); +} +#define x509_check_issuer_fail_ok( crt, issuer ) \ + x509_check_issuer_fail_okx ( crt, issuer, __FILE__, __LINE__ ) /** * Report certificate root validation test result * * @v crt Test certificate * @v root Test root certificate store + * @v file Test code file + * @v line Test code line */ -#define x509_check_root_ok( crt, root ) do { \ - ok ( x509_check_root ( (crt)->cert, root ) == 0 ); \ - } while ( 0 ) +static void x509_check_root_okx ( struct x509_test_certificate *crt, + struct x509_root *root, const char *file, + unsigned int line ) { + + okx ( x509_check_root ( crt->cert, root ) == 0, file, line ); +} +#define x509_check_root_ok( crt, root ) \ + x509_check_root_okx ( crt, root, __FILE__, __LINE__ ) /** * Report certificate root validation failure test result * * @v crt Test certificate * @v root Test root certificate store + * @v file Test code file + * @v line Test code line */ -#define x509_check_root_fail_ok( crt, root ) do { \ - ok ( x509_check_root ( (crt)->cert, root ) != 0 ); \ - } while ( 0 ) +static void x509_check_root_fail_okx ( struct x509_test_certificate *crt, + struct x509_root *root, + const char *file, unsigned int line ) { + + okx ( x509_check_root ( crt->cert, root ) != 0, file, line ); +} +#define x509_check_root_fail_ok( crt, root ) \ + x509_check_root_fail_okx ( crt, root, __FILE__, __LINE__ ) /** * Report certificate time validation test result * * @v crt Test certificate * @v time Test time + * @v file Test code file + * @v line Test code line */ -#define x509_check_time_ok( crt, time ) do { \ - ok ( x509_check_time ( (crt)->cert, time ) == 0 ); \ - } while ( 0 ) +static void x509_check_time_okx ( struct x509_test_certificate *crt, + time_t time, const char *file, + unsigned int line ) { + + okx ( x509_check_time ( crt->cert, time ) == 0, file, line ); +} +#define x509_check_time_ok( crt, time ) \ + x509_check_time_okx ( crt, time, __FILE__, __LINE__ ) /** * Report certificate time validation failure test result * * @v crt Test certificate * @v time Test time + * @v file Test code file + * @v line Test code line */ -#define x509_check_time_fail_ok( crt, time ) do { \ - ok ( x509_check_time ( (crt)->cert, time ) != 0 ); \ - } while ( 0 ) +static void x509_check_time_fail_okx ( struct x509_test_certificate *crt, + time_t time, const char *file, + unsigned int line ) { + + okx ( x509_check_time ( crt->cert, time ) != 0, file, line ); +} +#define x509_check_time_fail_ok( crt, time ) \ + x509_check_time_fail_okx ( crt, time, __FILE__, __LINE__ ) + +/** + * Report certificate name validation test result + * + * @v crt Test certificate + * @v name Test name + * @v file Test code file + * @v line Test code line + */ +static void x509_check_name_okx ( struct x509_test_certificate *crt, + const char *name, const char *file, + unsigned int line ) { + + okx ( x509_check_name ( crt->cert, name ) == 0, file, line ); +} +#define x509_check_name_ok( crt, name ) \ + x509_check_name_okx ( crt, name, __FILE__, __LINE__ ) + +/** + * Report certificate name validation failure test result + * + * @v crt Test certificate + * @v name Test name + * @v file Test code file + * @v line Test code line + */ +static void x509_check_name_fail_okx ( struct x509_test_certificate *crt, + const char *name, const char *file, + unsigned int line ) { + + okx ( x509_check_name ( crt->cert, name ) != 0, file, line ); +} +#define x509_check_name_fail_ok( crt, name ) \ + x509_check_name_fail_okx ( crt, name, __FILE__, __LINE__ ) /** * Report certificate chain parsing test result * * @v chn Test certificate chain + * @v file Test code file + * @v line Test code line */ -#define x509_chain_ok( chn ) do { \ - unsigned int i; \ - struct x509_certificate *first; \ - (chn)->chain = x509_alloc_chain(); \ - ok ( (chn)->chain != NULL ); \ - for ( i = 0 ; i < (chn)->count ; i++ ) { \ - ok ( x509_append ( (chn)->chain, \ - (chn)->certs[i]->cert ) == 0 ); \ - } \ - first = x509_first ( (chn)->chain ); \ - ok ( first != NULL ); \ - ok ( first->raw.len == (chn)->certs[0]->len ); \ - ok ( memcmp ( first->raw.data, (chn)->certs[0]->data, \ - first->raw.len ) == 0 ); \ - } while ( 0 ) +static void x509_chain_okx ( struct x509_test_chain *chn, const char *file, + unsigned int line ) { + unsigned int i; + struct x509_certificate *first; + + chn->chain = x509_alloc_chain(); + okx ( chn->chain != NULL, file, line ); + for ( i = 0 ; i < chn->count ; i++ ) { + okx ( x509_append ( chn->chain, chn->certs[i]->cert ) == 0, + file, line ); + } + first = x509_first ( chn->chain ); + okx ( first != NULL, file, line ); + okx ( first->raw.len == chn->certs[0]->len, file, line ); + okx ( memcmp ( first->raw.data, chn->certs[0]->data, + first->raw.len ) == 0, file, line ); +} +#define x509_chain_ok( chn ) \ + x509_chain_okx ( chn, __FILE__, __LINE__ ) /** * Report certificate chain validation test result * * @v chn Test certificate chain * @v time Test certificate validation time - * @v root Test root certificate store + * @v store Test certificate store + * @v root Test root certificate list + * @v file Test code file + * @v line Test code line */ -#define x509_validate_chain_ok( chn, time, root ) do { \ - x509_invalidate_chain ( (chn)->chain ); \ - ok ( x509_validate_chain ( (chn)->chain, (time), \ - (root) ) == 0 ); \ - } while ( 0 ) +static void x509_validate_chain_okx ( struct x509_test_chain *chn, time_t time, + struct x509_chain *store, + struct x509_root *root, const char *file, + unsigned int line ) { + + x509_invalidate_chain ( chn->chain ); + okx ( x509_validate_chain ( chn->chain, time, store, root ) == 0, + file, line ); +} +#define x509_validate_chain_ok( chn, time, store, root ) \ + x509_validate_chain_okx ( chn, time, store, root, __FILE__, __LINE__ ) /** * Report certificate chain validation failure test result * * @v chn Test certificate chain * @v time Test certificate validation time - * @v root Test root certificate store + * @v store Test certificate store + * @v root Test root certificate list + * @v file Test code file + * @v line Test code line */ -#define x509_validate_chain_fail_ok( chn, time, root ) do { \ - x509_invalidate_chain ( (chn)->chain ); \ - ok ( x509_validate_chain ( (chn)->chain, (time), \ - (root) ) != 0 ); \ - } while ( 0 ) +static void x509_validate_chain_fail_okx ( struct x509_test_chain *chn, + time_t time, + struct x509_chain *store, + struct x509_root *root, + const char *file, + unsigned int line ) { + + x509_invalidate_chain ( chn->chain ); + okx ( x509_validate_chain ( chn->chain, time, store, root ) != 0, + file, line ); +} +#define x509_validate_chain_fail_ok( chn, time, store, root ) \ + x509_validate_chain_fail_okx ( chn, time, store, root, \ + __FILE__, __LINE__ ) /** * Perform X.509 self-tests @@ -889,6 +1021,19 @@ static void x509_test_exec ( void ) { x509_check_time_ok ( &root_crt, test_expired ); x509_check_time_fail_ok ( &root_crt, test_ca_expired ); + /* Check certificate names */ + x509_check_name_ok ( &server_crt, "boot.test.ipxe.org" ); + x509_check_name_ok ( &server_crt, "demo.test.ipxe.org" ); + x509_check_name_fail_ok ( &server_crt, "incorrect.test.ipxe.org" ); + x509_check_name_ok ( &server_crt, "anything.alt.test.ipxe.org" ); + x509_check_name_ok ( &server_crt, "wildcard.alt.test.ipxe.org" ); + x509_check_name_fail_ok ( &server_crt, "sub.domain.alt.test.ipxe.org" ); + x509_check_name_fail_ok ( &server_crt, "alt.test.ipxe.org" ); + x509_check_name_fail_ok ( &server_crt, "test.ipxe.org" ); + x509_check_name_fail_ok ( &server_crt, "ipxe.org" ); + x509_check_name_fail_ok ( &server_crt, "org" ); + x509_check_name_fail_ok ( &server_crt, "" ); + /* Parse all certificate chains */ x509_chain_ok ( &server_chain ); x509_chain_ok ( &broken_server_chain ); @@ -898,25 +1043,35 @@ static void x509_test_exec ( void ) { x509_chain_ok ( &bad_path_len_chain ); /* Check certificate chains */ - x509_validate_chain_ok ( &server_chain, test_time, &test_root ); - x509_validate_chain_ok ( &server_chain, test_time, &intermediate_root ); - x509_validate_chain_fail_ok ( &server_chain, test_time, &dummy_root ); + x509_validate_chain_ok ( &server_chain, test_time, + &empty_store, &test_root ); + x509_validate_chain_ok ( &server_chain, test_time, + &empty_store, &intermediate_root ); + x509_validate_chain_fail_ok ( &server_chain, test_time, + &empty_store, &dummy_root ); x509_validate_chain_fail_ok ( &broken_server_chain, test_time, - &test_root ); + &empty_store, &test_root ); x509_validate_chain_fail_ok ( &incomplete_server_chain, test_time, - &test_root ); + &empty_store, &test_root ); x509_validate_chain_ok ( &incomplete_server_chain, test_time, - &intermediate_root ); - x509_validate_chain_fail_ok ( ¬_ca_chain, test_time, &test_root ); - x509_validate_chain_ok ( &useless_chain, test_time, &test_root ); + &empty_store, &intermediate_root ); + x509_validate_chain_fail_ok ( ¬_ca_chain, test_time, + &empty_store, &test_root ); + x509_validate_chain_ok ( &useless_chain, test_time, + &empty_store, &test_root ); x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time, - &test_root ); + &empty_store, &test_root ); /* Check certificate chain expiry times */ - x509_validate_chain_fail_ok ( &server_chain, test_expired, &test_root ); - x509_validate_chain_ok ( &useless_chain, test_expired, &test_root ); + x509_validate_chain_fail_ok ( &server_chain, test_expired, + &empty_store, &test_root ); + x509_validate_chain_ok ( &useless_chain, test_expired, + &empty_store, &test_root ); x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired, - &test_root ); + &empty_store, &test_root ); + + /* Sanity check */ + assert ( list_empty ( &empty_store.links ) ); /* Drop chain references */ x509_chain_put ( bad_path_len_chain.chain ); diff --git a/roms/ipxe/src/usr/autoboot.c b/roms/ipxe/src/usr/autoboot.c index 0587f2044..af3d1f7bb 100644 --- a/roms/ipxe/src/usr/autoboot.c +++ b/roms/ipxe/src/usr/autoboot.c @@ -30,11 +30,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/uri.h> #include <ipxe/open.h> #include <ipxe/init.h> +#include <ipxe/keys.h> +#include <ipxe/version.h> +#include <ipxe/shell.h> +#include <ipxe/features.h> +#include <ipxe/image.h> +#include <ipxe/timer.h> #include <usr/ifmgmt.h> #include <usr/route.h> -#include <usr/dhcpmgmt.h> #include <usr/imgmgmt.h> +#include <usr/prompt.h> #include <usr/autoboot.h> +#include <config/general.h> /** @file * @@ -42,11 +49,26 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Device location of preferred autoboot device */ +struct device_description autoboot_device; + /* Disambiguate the various error causes */ #define ENOENT_BOOT __einfo_error ( EINFO_ENOENT_BOOT ) #define EINFO_ENOENT_BOOT \ __einfo_uniqify ( EINFO_ENOENT, 0x01, "Nothing to boot" ) +#define NORMAL "\033[0m" +#define BOLD "\033[1m" +#define CYAN "\033[36m" + +/** The "scriptlet" setting */ +const struct setting scriptlet_setting __setting ( SETTING_MISC, scriptlet ) = { + .name = "scriptlet", + .description = "Boot scriptlet", + .tag = DHCP_EB_SCRIPTLET, + .type = &setting_type_string, +}; + /** * Perform PXE menu boot when PXE stack is not available */ @@ -55,15 +77,6 @@ __weak int pxe_menu_boot ( struct net_device *netdev __unused ) { } /** - * Identify the boot network device - * - * @ret netdev Boot network device - */ -static struct net_device * find_boot_netdev ( void ) { - return NULL; -} - -/** * Parse next-server and filename into a URI * * @v next_server Next-server address @@ -72,8 +85,6 @@ static struct net_device * find_boot_netdev ( void ) { */ static struct uri * parse_next_server_and_filename ( struct in_addr next_server, const char *filename ) { - char buf[ 23 /* "tftp://xxx.xxx.xxx.xxx/" */ + strlen ( filename ) - + 1 /* NUL */ ]; struct uri *uri; /* Parse filename */ @@ -81,17 +92,10 @@ static struct uri * parse_next_server_and_filename ( struct in_addr next_server, if ( ! uri ) return NULL; - /* Construct a tftp:// URI for the filename, if applicable. - * We can't just rely on the current working URI, because the - * relative URI resolution will remove the distinction between - * filenames with and without initial slashes, which is - * significant for TFTP. - */ + /* Construct a TFTP URI for the filename, if applicable */ if ( next_server.s_addr && filename[0] && ! uri_is_absolute ( uri ) ) { uri_put ( uri ); - snprintf ( buf, sizeof ( buf ), "tftp://%s/%s", - inet_ntoa ( next_server ), filename ); - uri = parse_uri ( buf ); + uri = tftp_uri ( next_server, filename ); if ( ! uri ) return NULL; } @@ -100,7 +104,8 @@ static struct uri * parse_next_server_and_filename ( struct in_addr next_server, } /** The "keep-san" setting */ -struct setting keep_san_setting __setting ( SETTING_SANBOOT_EXTRA ) = { +const struct setting keep_san_setting __setting ( SETTING_SANBOOT_EXTRA, + keep-san ) = { .name = "keep-san", .description = "Preserve SAN connection", .tag = DHCP_EB_KEEP_SAN, @@ -108,7 +113,8 @@ struct setting keep_san_setting __setting ( SETTING_SANBOOT_EXTRA ) = { }; /** The "skip-san-boot" setting */ -struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA ) = { +const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA, + skip-san-boot ) = { .name = "skip-san-boot", .description = "Do not boot from SAN device", .tag = DHCP_EB_SKIP_SAN_BOOT, @@ -159,7 +165,7 @@ int uriboot ( struct uri *filename, struct uri *root_path, int drive, /* Attempt filename boot if applicable */ if ( filename ) { - if ( ( rc = imgdownload ( filename, &image ) ) != 0 ) + if ( ( rc = imgdownload ( filename, 0, &image ) ) != 0 ) goto err_download; image->flags |= IMAGE_AUTO_UNREGISTER; if ( ( rc = image_exec ( image ) ) != 0 ) { @@ -232,31 +238,40 @@ static void close_all_netdevs ( void ) { * @ret uri URI, or NULL on failure */ struct uri * fetch_next_server_and_filename ( struct settings *settings ) { - struct in_addr next_server; - char buf[256]; + struct in_addr next_server = { 0 }; + char *raw_filename = NULL; + struct uri *uri = NULL; char *filename; - struct uri *uri; - - /* Fetch next-server setting */ - fetch_ipv4_setting ( settings, &next_server_setting, &next_server ); - if ( next_server.s_addr ) - printf ( "Next server: %s\n", inet_ntoa ( next_server ) ); - /* Fetch filename setting */ - fetch_string_setting ( settings, &filename_setting, - buf, sizeof ( buf ) ); - if ( buf[0] ) - printf ( "Filename: %s\n", buf ); + /* If we have a filename, fetch it along with the next-server + * setting from the same settings block. + */ + if ( fetch_setting ( settings, &filename_setting, &settings, + NULL, NULL, 0 ) >= 0 ) { + fetch_string_setting_copy ( settings, &filename_setting, + &raw_filename ); + fetch_ipv4_setting ( settings, &next_server_setting, + &next_server ); + } /* Expand filename setting */ - filename = expand_settings ( buf ); + filename = expand_settings ( raw_filename ? raw_filename : "" ); if ( ! filename ) - return NULL; + goto err_expand; /* Parse next server and filename */ + if ( next_server.s_addr ) + printf ( "Next server: %s\n", inet_ntoa ( next_server ) ); + if ( filename[0] ) + printf ( "Filename: %s\n", filename ); uri = parse_next_server_and_filename ( next_server, filename ); + if ( ! uri ) + goto err_parse; + err_parse: free ( filename ); + err_expand: + free ( raw_filename ); return uri; } @@ -267,25 +282,30 @@ struct uri * fetch_next_server_and_filename ( struct settings *settings ) { * @ret uri URI, or NULL on failure */ static struct uri * fetch_root_path ( struct settings *settings ) { - char buf[256]; + struct uri *uri = NULL; + char *raw_root_path; char *root_path; - struct uri *uri; /* Fetch root-path setting */ - fetch_string_setting ( settings, &root_path_setting, - buf, sizeof ( buf ) ); - if ( buf[0] ) - printf ( "Root path: %s\n", buf ); + fetch_string_setting_copy ( settings, &root_path_setting, + &raw_root_path ); /* Expand filename setting */ - root_path = expand_settings ( buf ); + root_path = expand_settings ( raw_root_path ? raw_root_path : "" ); if ( ! root_path ) - return NULL; + goto err_expand; /* Parse root path */ + if ( root_path[0] ) + printf ( "Root path: %s\n", root_path ); uri = parse_uri ( root_path ); + if ( ! uri ) + goto err_parse; + err_parse: free ( root_path ); + err_expand: + free ( raw_root_path ); return uri; } @@ -301,7 +321,7 @@ static int have_pxe_menu ( void ) { = { .tag = DHCP_PXE_DISCOVERY_CONTROL }; struct setting pxe_boot_menu_setting = { .tag = DHCP_PXE_BOOT_MENU }; - char buf[256]; + char buf[ 10 /* "PXEClient" + NUL */ ]; unsigned int pxe_discovery_control; fetch_string_setting ( NULL, &vendor_class_id_setting, @@ -334,8 +354,8 @@ int netboot ( struct net_device *netdev ) { goto err_ifopen; ifstat ( netdev ); - /* Configure device via DHCP */ - if ( ( rc = dhcp ( netdev ) ) != 0 ) + /* Configure device */ + if ( ( rc = ifconf ( netdev, NULL ) ) != 0 ) goto err_dhcp; route(); @@ -402,24 +422,116 @@ int netboot ( struct net_device *netdev ) { } /** + * Test if network device matches the autoboot device location + * + * @v netdev Network device + * @ret is_autoboot Network device matches the autoboot device location + */ +static int is_autoboot_device ( struct net_device *netdev ) { + + return ( ( netdev->dev->desc.bus_type == autoboot_device.bus_type ) && + ( netdev->dev->desc.location == autoboot_device.location ) ); +} + +/** * Boot the system */ -int autoboot ( void ) { - struct net_device *boot_netdev; +static int autoboot ( void ) { struct net_device *netdev; int rc = -ENODEV; - /* If we have an identifable boot device, try that first */ - if ( ( boot_netdev = find_boot_netdev() ) ) - rc = netboot ( boot_netdev ); - - /* If that fails, try booting from any of the other devices */ + /* Try booting from each network device. If we have a + * specified autoboot device location, then use only devices + * matching that location. + */ for_each_netdev ( netdev ) { - if ( netdev == boot_netdev ) + + /* Skip any non-matching devices, if applicable */ + if ( autoboot_device.bus_type && + ( ! is_autoboot_device ( netdev ) ) ) continue; + + /* Attempt booting from this device */ rc = netboot ( netdev ); } printf ( "No more network devices\n" ); return rc; } + +/** + * Prompt for shell entry + * + * @ret enter_shell User wants to enter shell + */ +static int shell_banner ( void ) { + + /* Skip prompt if timeout is zero */ + if ( BANNER_TIMEOUT <= 0 ) + return 0; + + /* Prompt user */ + printf ( "\n" ); + return ( prompt ( "Press Ctrl-B for the iPXE command line...", + ( ( BANNER_TIMEOUT * TICKS_PER_SEC ) / 10 ), + CTRL_B ) == 0 ); +} + +/** + * Main iPXE flow of execution + * + * @v netdev Network device, or NULL + */ +void ipxe ( struct net_device *netdev ) { + struct feature *feature; + struct image *image; + char *scriptlet; + + /* + * Print welcome banner + * + * + * If you wish to brand this build of iPXE, please do so by + * defining the string PRODUCT_NAME in config/general.h. + * + * While nothing in the GPL prevents you from removing all + * references to iPXE or http://ipxe.org, we prefer you not to + * do so. + * + */ + printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "iPXE %s" + NORMAL " -- Open Source Network Boot Firmware -- " + CYAN "http://ipxe.org" NORMAL "\n" + "Features:", product_version ); + for_each_table_entry ( feature, FEATURES ) + printf ( " %s", feature->name ); + printf ( "\n" ); + + /* Boot system */ + if ( ( image = first_image() ) != NULL ) { + /* We have an embedded image; execute it */ + image_exec ( image ); + } else if ( shell_banner() ) { + /* User wants shell; just give them a shell */ + shell(); + } else { + fetch_string_setting_copy ( NULL, &scriptlet_setting, + &scriptlet ); + if ( scriptlet ) { + /* User has defined a scriptlet; execute it */ + system ( scriptlet ); + free ( scriptlet ); + } else { + /* Try booting. If booting fails, offer the + * user another chance to enter the shell. + */ + if ( netdev ) { + netboot ( netdev ); + } else { + autoboot(); + } + if ( shell_banner() ) + shell(); + } + } +} diff --git a/roms/ipxe/src/usr/dhcpmgmt.c b/roms/ipxe/src/usr/dhcpmgmt.c index b61c01aa3..23982b19c 100644 --- a/roms/ipxe/src/usr/dhcpmgmt.c +++ b/roms/ipxe/src/usr/dhcpmgmt.c @@ -25,49 +25,22 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/netdevice.h> #include <ipxe/dhcp.h> #include <ipxe/monojob.h> -#include <ipxe/process.h> #include <usr/ifmgmt.h> #include <usr/dhcpmgmt.h> -#define LINK_WAIT_MS 15000 - /** @file * * DHCP management * */ -int dhcp ( struct net_device *netdev ) { - int rc; - - /* Check we can open the interface first */ - if ( ( rc = ifopen ( netdev ) ) != 0 ) - return rc; - - /* Wait for link-up */ - if ( ( rc = iflinkwait ( netdev, LINK_WAIT_MS ) ) != 0 ) - return rc; - - /* Perform DHCP */ - printf ( "DHCP (%s %s)", netdev->name, - netdev->ll_protocol->ntoa ( netdev->ll_addr ) ); - if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) { - rc = monojob_wait ( "" ); - } else if ( rc > 0 ) { - printf ( " using cached\n" ); - rc = 0; - } - - return rc; -} - int pxebs ( struct net_device *netdev, unsigned int pxe_type ) { int rc; /* Perform PXE Boot Server Discovery */ printf ( "PXEBS (%s type %d)", netdev->name, pxe_type ); if ( ( rc = start_pxebs ( &monojob, netdev, pxe_type ) ) == 0 ) - rc = monojob_wait ( "" ); + rc = monojob_wait ( "", 0 ); return rc; } diff --git a/roms/ipxe/src/usr/fcmgmt.c b/roms/ipxe/src/usr/fcmgmt.c index 2657ba0cf..a30f37a71 100644 --- a/roms/ipxe/src/usr/fcmgmt.c +++ b/roms/ipxe/src/usr/fcmgmt.c @@ -112,5 +112,5 @@ int fcels ( struct fc_port *port, struct fc_port_id *peer_port_id, } /* Wait for ELS to complete */ - return monojob_wait ( "" ); + return monojob_wait ( "", 0 ); } diff --git a/roms/ipxe/src/usr/ifmgmt.c b/roms/ipxe/src/usr/ifmgmt.c index 94e6e8754..cab1cd917 100644 --- a/roms/ipxe/src/usr/ifmgmt.c +++ b/roms/ipxe/src/usr/ifmgmt.c @@ -26,8 +26,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/console.h> #include <ipxe/netdevice.h> #include <ipxe/device.h> -#include <ipxe/process.h> -#include <ipxe/keys.h> +#include <ipxe/job.h> +#include <ipxe/monojob.h> +#include <ipxe/nap.h> +#include <ipxe/timer.h> #include <usr/ifmgmt.h> /** @file @@ -36,6 +38,15 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Default time to wait for link-up */ +#define LINK_WAIT_TIMEOUT ( 15 * TICKS_PER_SEC ) + +/** Default unsuccessful configuration status code */ +#define EADDRNOTAVAIL_CONFIG __einfo_error ( EINFO_EADDRNOTAVAIL_CONFIG ) +#define EINFO_EADDRNOTAVAIL_CONFIG \ + __einfo_uniqify ( EINFO_EADDRNOTAVAIL, 0x01, \ + "No configuration methods succeeded" ) + /** * Open network device * @@ -104,49 +115,179 @@ void ifstat ( struct net_device *netdev ) { ifstat_errors ( &netdev->rx_stats, "RXE" ); } +/** Network device poller */ +struct ifpoller { + /** Job control interface */ + struct interface job; + /** Network device */ + struct net_device *netdev; + /** Network device configurator (if applicable) */ + struct net_device_configurator *configurator; + /** + * Check progress + * + * @v ifpoller Network device poller + * @ret ongoing_rc Ongoing job status code (if known) + */ + int ( * progress ) ( struct ifpoller *ifpoller ); +}; + +/** + * Report network device poller progress + * + * @v ifpoller Network device poller + * @v progress Progress report to fill in + * @ret ongoing_rc Ongoing job status code (if known) + */ +static int ifpoller_progress ( struct ifpoller *ifpoller, + struct job_progress *progress __unused ) { + + /* Reduce CPU utilisation */ + cpu_nap(); + + /* Hand off to current progress checker */ + return ifpoller->progress ( ifpoller ); +} + +/** Network device poller operations */ +static struct interface_operation ifpoller_job_op[] = { + INTF_OP ( job_progress, struct ifpoller *, ifpoller_progress ), +}; + +/** Network device poller descriptor */ +static struct interface_descriptor ifpoller_job_desc = + INTF_DESC ( struct ifpoller, job, ifpoller_job_op ); + +/** + * Poll network device until completion + * + * @v netdev Network device + * @v configurator Network device configurator (if applicable) + * @v timeout Timeout period, in ticks + * @v progress Method to check progress + * @ret rc Return status code + */ +static int ifpoller_wait ( struct net_device *netdev, + struct net_device_configurator *configurator, + unsigned long timeout, + int ( * progress ) ( struct ifpoller *ifpoller ) ) { + static struct ifpoller ifpoller = { + .job = INTF_INIT ( ifpoller_job_desc ), + }; + + ifpoller.netdev = netdev; + ifpoller.configurator = configurator; + ifpoller.progress = progress; + intf_plug_plug ( &monojob, &ifpoller.job ); + return monojob_wait ( "", timeout ); +} + +/** + * Check link-up progress + * + * @v ifpoller Network device poller + * @ret ongoing_rc Ongoing job status code (if known) + */ +static int iflinkwait_progress ( struct ifpoller *ifpoller ) { + struct net_device *netdev = ifpoller->netdev; + int ongoing_rc = netdev->link_rc; + + /* Terminate successfully if link is up */ + if ( ongoing_rc == 0 ) + intf_close ( &ifpoller->job, 0 ); + + /* Otherwise, report link status as ongoing job status */ + return ongoing_rc; +} + /** * Wait for link-up, with status indication * * @v netdev Network device - * @v max_wait_ms Maximum time to wait, in ms + * @v timeout Timeout period, in ticks */ -int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) { - int key; +int iflinkwait ( struct net_device *netdev, unsigned long timeout ) { int rc; - /* Allow link state to be updated */ - netdev_poll ( netdev ); + /* Ensure device is open */ + if ( ( rc = ifopen ( netdev ) ) != 0 ) + return rc; + /* Return immediately if link is already up */ + netdev_poll ( netdev ); if ( netdev_link_ok ( netdev ) ) return 0; - printf ( "Waiting for link-up on %s...", netdev->name ); + /* Wait for link-up */ + printf ( "Waiting for link-up on %s", netdev->name ); + return ifpoller_wait ( netdev, NULL, timeout, iflinkwait_progress ); +} - while ( 1 ) { - if ( netdev_link_ok ( netdev ) ) { - rc = 0; - break; - } - if ( max_wait_ms-- == 0 ) { - rc = netdev->link_rc; - break; - } - step(); - if ( iskey() ) { - key = getchar(); - if ( key == CTRL_C ) { - rc = -ECANCELED; - break; - } - } - mdelay ( 1 ); - } +/** + * Check configuration progress + * + * @v ifpoller Network device poller + * @ret ongoing_rc Ongoing job status code (if known) + */ +static int ifconf_progress ( struct ifpoller *ifpoller ) { + struct net_device *netdev = ifpoller->netdev; + struct net_device_configurator *configurator = ifpoller->configurator; + struct net_device_configuration *config; + int rc; - if ( rc == 0 ) { - printf ( " ok\n" ); + /* Do nothing unless configuration has completed */ + if ( netdev_configuration_in_progress ( netdev ) ) + return 0; + + /* Terminate with appropriate overall return status code */ + if ( configurator ) { + config = netdev_configuration ( netdev, configurator ); + rc = config->rc; } else { - printf ( " failed: %s\n", strerror ( rc ) ); + rc = ( netdev_configuration_ok ( netdev ) ? + 0 : -EADDRNOTAVAIL_CONFIG ); } + intf_close ( &ifpoller->job, rc ); return rc; } + +/** + * Perform network device configuration + * + * @v netdev Network device + * @v configurator Network device configurator, or NULL to use all + * @ret rc Return status code + */ +int ifconf ( struct net_device *netdev, + struct net_device_configurator *configurator ) { + int rc; + + /* Ensure device is open and link is up */ + if ( ( rc = iflinkwait ( netdev, LINK_WAIT_TIMEOUT ) ) != 0 ) + return rc; + + /* Start configuration */ + if ( configurator ) { + if ( ( rc = netdev_configure ( netdev, configurator ) ) != 0 ) { + printf ( "Could not configure %s via %s: %s\n", + netdev->name, configurator->name, + strerror ( rc ) ); + return rc; + } + } else { + if ( ( rc = netdev_configure_all ( netdev ) ) != 0 ) { + printf ( "Could not configure %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } + } + + /* Wait for configuration to complete */ + printf ( "Configuring %s%s%s(%s %s)", + ( configurator ? "[" : "" ), + ( configurator ? configurator->name : "" ), + ( configurator ? "] " : "" ), + netdev->name, netdev->ll_protocol->ntoa ( netdev->ll_addr ) ); + return ifpoller_wait ( netdev, configurator, 0, ifconf_progress ); +} diff --git a/roms/ipxe/src/usr/imgmgmt.c b/roms/ipxe/src/usr/imgmgmt.c index ef4e2c366..c9c571640 100644 --- a/roms/ipxe/src/usr/imgmgmt.c +++ b/roms/ipxe/src/usr/imgmgmt.c @@ -40,15 +40,34 @@ FILE_LICENCE ( GPL2_OR_LATER ); * Download a new image * * @v uri URI + * @v timeout Download timeout * @v image Image to fill in * @ret rc Return status code */ -int imgdownload ( struct uri *uri, struct image **image ) { - size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 ); - char uri_string_redacted[len]; +int imgdownload ( struct uri *uri, unsigned long timeout, + struct image **image ) { const char *password; + char *uri_string_redacted; int rc; + /* Construct redacted URI */ + password = uri->password; + if ( password ) + uri->password = "***"; + uri_string_redacted = format_uri_alloc ( uri ); + uri->password = password; + if ( ! uri_string_redacted ) { + rc = -ENOMEM; + goto err_uri_string; + } + + /* Resolve URI */ + uri = resolve_uri ( cwuri, uri ); + if ( ! uri ) { + rc = -ENOMEM; + goto err_resolve_uri; + } + /* Allocate image */ *image = alloc_image ( uri ); if ( ! *image ) { @@ -56,23 +75,14 @@ int imgdownload ( struct uri *uri, struct image **image ) { goto err_alloc_image; } - /* Redact password portion of URI, if necessary */ - password = uri->password; - if ( password ) - uri->password = "***"; - unparse_uri ( uri_string_redacted, sizeof ( uri_string_redacted ), - uri, URI_ALL ); - uri->password = password; - /* Create downloader */ - if ( ( rc = create_downloader ( &monojob, *image, LOCATION_URI, - uri ) ) != 0 ) { + if ( ( rc = create_downloader ( &monojob, *image ) ) != 0 ) { printf ( "Could not start download: %s\n", strerror ( rc ) ); goto err_create_downloader; } /* Wait for download to complete */ - if ( ( rc = monojob_wait ( uri_string_redacted ) ) != 0 ) + if ( ( rc = monojob_wait ( uri_string_redacted, timeout ) ) != 0 ) goto err_monojob_wait; /* Register image */ @@ -81,18 +91,15 @@ int imgdownload ( struct uri *uri, struct image **image ) { goto err_register_image; } - /* Drop local reference to image. Image is guaranteed to - * remain in scope since it is registered. - */ - image_put ( *image ); - - return 0; - err_register_image: err_monojob_wait: err_create_downloader: image_put ( *image ); err_alloc_image: + uri_put ( uri ); + err_resolve_uri: + free ( uri_string_redacted ); + err_uri_string: return rc; } @@ -100,17 +107,19 @@ int imgdownload ( struct uri *uri, struct image **image ) { * Download a new image * * @v uri_string URI string + * @v timeout Download timeout * @v image Image to fill in * @ret rc Return status code */ -int imgdownload_string ( const char *uri_string, struct image **image ) { +int imgdownload_string ( const char *uri_string, unsigned long timeout, + struct image **image ) { struct uri *uri; int rc; if ( ! ( uri = parse_uri ( uri_string ) ) ) return -ENOMEM; - rc = imgdownload ( uri, image ); + rc = imgdownload ( uri, timeout, image ); uri_put ( uri ); return rc; @@ -120,10 +129,12 @@ int imgdownload_string ( const char *uri_string, struct image **image ) { * Acquire an image * * @v name_uri Name or URI string + * @v timeout Download timeout * @v image Image to fill in * @ret rc Return status code */ -int imgacquire ( const char *name_uri, struct image **image ) { +int imgacquire ( const char *name_uri, unsigned long timeout, + struct image **image ) { /* If we already have an image with the specified name, use it */ *image = find_image ( name_uri ); @@ -131,7 +142,7 @@ int imgacquire ( const char *name_uri, struct image **image ) { return 0; /* Otherwise, download a new image */ - return imgdownload_string ( name_uri, image ); + return imgdownload_string ( name_uri, timeout, image ); } /** diff --git a/roms/ipxe/src/usr/imgtrust.c b/roms/ipxe/src/usr/imgtrust.c index afb41529f..da7ff2ef0 100644 --- a/roms/ipxe/src/usr/imgtrust.c +++ b/roms/ipxe/src/usr/imgtrust.c @@ -77,14 +77,14 @@ int imgverify ( struct image *image, struct image *signature, list_for_each_entry ( info, &sig->info, list ) { if ( ( rc = create_validator ( &monojob, info->chain ) ) != 0 ) goto err_create_validator; - if ( ( rc = monojob_wait ( NULL ) ) != 0 ) + if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) goto err_validator_wait; } /* Use signature to verify image */ now = time ( NULL ); if ( ( rc = cms_verify ( sig, image->data, image->len, - name, now, NULL ) ) != 0 ) + name, now, NULL, NULL ) ) != 0 ) goto err_verify; /* Drop reference to signature */ diff --git a/roms/ipxe/src/usr/ipstat.c b/roms/ipxe/src/usr/ipstat.c new file mode 100644 index 000000000..95ad799dc --- /dev/null +++ b/roms/ipxe/src/usr/ipstat.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <ipxe/ipstat.h> +#include <usr/ipstat.h> + +/** @file + * + * IP statistics + * + */ + +/** + * Print IP statistics + * + */ +void ipstat ( void ) { + struct ip_statistics_family *family; + struct ip_statistics *stats; + + for_each_table_entry ( family, IP_STATISTICS_FAMILIES ) { + stats = family->stats; + printf ( "IP version %d:\n", family->version ); + printf ( " InReceives:%ld InMcastPkts:%ld InBcastPkts:%ld " + "InOctets:%ld\n", stats->in_receives, + stats->in_mcast_pkts, stats->in_bcast_pkts, + stats->in_octets ); + printf ( " InHdrErrors:%ld InAddrErrors:%ld " + "InUnknownProtos:%ld InTruncatedPkts:%ld\n", + stats->in_hdr_errors, stats->in_addr_errors, + stats->in_unknown_protos, stats->in_truncated_pkts ); + printf ( " ReasmReqds:%ld ReasmOKs:%ld ReasmFails:%ld\n", + stats->reasm_reqds, stats->reasm_oks, + stats->reasm_fails ); + printf ( " InDelivers:%ld OutRequests:%ld OutNoRoutes:%ld\n", + stats->in_delivers, stats->out_requests, + stats->out_no_routes ); + printf ( " OutTransmits:%ld OutMcastPkts:%ld OutBcastPkts:%ld " + "OutOctets:%ld\n", stats->out_transmits, + stats->out_mcast_pkts, stats->out_bcast_pkts, + stats->out_octets ); + } +} diff --git a/roms/ipxe/src/usr/lotest.c b/roms/ipxe/src/usr/lotest.c index c4b0b4413..9e2ac331c 100644 --- a/roms/ipxe/src/usr/lotest.c +++ b/roms/ipxe/src/usr/lotest.c @@ -39,7 +39,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -#define LINK_WAIT_MS 15000 +/** Loopback testing in progress flag */ +static int lotest_active; + +/** Loopback testing received packets */ +static LIST_HEAD ( lotest_queue ); /** * Process received packet @@ -56,8 +60,32 @@ static int lotest_rx ( struct io_buffer *iobuf, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused ) { - free_iob ( iobuf ); - return -ENOTSUP; + + /* Add to received packet queue if currently performing a test */ + if ( lotest_active ) { + list_add_tail ( &iobuf->list, &lotest_queue ); + } else { + free_iob ( iobuf ); + } + + return 0; +} + +/** + * Dequeue received packet + * + * @ret iobuf I/O buffer, or NULL + */ +static struct io_buffer * lotest_dequeue ( void ) { + struct io_buffer *iobuf; + + /* Remove first packet (if any) from received packet queue */ + iobuf = list_first_entry ( &lotest_queue, struct io_buffer, list ); + if ( ! iobuf ) + return NULL; + list_del ( &iobuf->list ); + + return iobuf; } /** @@ -86,22 +114,25 @@ static struct net_protocol lotest_protocol __net_protocol = { }; /** + * Discard all received loopback test packets + * + */ +static void lotest_flush ( void ) { + struct io_buffer *iobuf; + + while ( ( iobuf = lotest_dequeue() ) != NULL ) + free_iob ( iobuf ); +} + +/** * Wait for packet to be received * - * @v receiver Receiving network device* * @v data Expected data * @v len Expected data length * @ret rc Return status code */ -static int loopback_wait ( struct net_device *receiver, void *data, - size_t len ) { - struct ll_protocol *ll_protocol = receiver->ll_protocol; +static int loopback_wait ( void *data, size_t len ) { struct io_buffer *iobuf; - const void *ll_dest; - const void *ll_source; - uint16_t net_proto; - unsigned int flags; - int rc; /* Poll until packet arrives */ while ( 1 ) { @@ -114,28 +145,10 @@ static int loopback_wait ( struct net_device *receiver, void *data, net_poll(); /* Dequeue packet, if available */ - iobuf = netdev_rx_dequeue ( receiver ); + iobuf = lotest_dequeue(); if ( ! iobuf ) continue; - /* Strip link-layer header */ - if ( ( rc = ll_protocol->pull ( receiver, iobuf, &ll_dest, - &ll_source, &net_proto, - &flags ) ) != 0 ) { - printf ( "\nFailed to strip link-layer header: %s", - strerror ( rc ) ); - free_iob ( iob_disown ( iobuf ) ); - return rc; - } - - /* Ignore non-loopback packets */ - if ( net_proto != lotest_protocol.net_proto ) { - printf ( "\nReceived spurious packet type %04x\n", - ntohs ( net_proto ) ); - free_iob ( iob_disown ( iobuf ) ); - continue; - } - /* Check packet length */ if ( iob_len ( iobuf ) != len ) { printf ( "\nLength mismatch: sent %zd, received %zd", @@ -175,7 +188,8 @@ static int loopback_wait ( struct net_device *receiver, void *data, */ int loopback_test ( struct net_device *sender, struct net_device *receiver, size_t mtu ) { - uint8_t buf[mtu]; + uint8_t *buf; + uint32_t *seq; struct io_buffer *iobuf; unsigned int i; unsigned int successes; @@ -188,21 +202,28 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, return rc; /* Wait for link-up */ - if ( ( rc = iflinkwait ( sender, LINK_WAIT_MS ) ) != 0 ) + if ( ( rc = iflinkwait ( sender, 0 ) ) != 0 ) return rc; - if ( ( rc = iflinkwait ( receiver, LINK_WAIT_MS ) ) != 0 ) + if ( ( rc = iflinkwait ( receiver, 0 ) ) != 0 ) return rc; + /* Allocate data buffer */ + if ( mtu < sizeof ( *seq ) ) + mtu = sizeof ( *seq ); + buf = malloc ( mtu ); + if ( ! buf ) + return -ENOMEM; + seq = ( ( void * ) buf ); + /* Print initial statistics */ printf ( "Performing loopback test from %s to %s with %zd byte MTU\n", sender->name, receiver->name, mtu ); ifstat ( sender ); ifstat ( receiver ); - /* Freeze receive queue processing on the receiver, so that we - * can extract all received packets. - */ - netdev_rx_freeze ( receiver ); + /* Start loopback test */ + lotest_flush(); + lotest_active = 1; /* Perform loopback test */ for ( successes = 0 ; ; successes++ ) { @@ -211,17 +232,17 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, printf ( "\r%d", successes ); /* Generate random packet */ - for ( i = 0 ; i < sizeof ( buf ) ; i++ ) + *seq = htonl ( successes ); + for ( i = sizeof ( *seq ) ; i < mtu ; i++ ) buf[i] = random(); - iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( buf ) ); + iobuf = alloc_iob ( MAX_LL_HEADER_LEN + mtu ); if ( ! iobuf ) { printf ( "\nFailed to allocate I/O buffer" ); rc = -ENOMEM; break; } iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); - memcpy ( iob_put ( iobuf, sizeof ( buf ) ), - buf, sizeof ( buf ) ); + memcpy ( iob_put ( iobuf, mtu ), buf, mtu ); /* Transmit packet */ if ( ( rc = net_tx ( iob_disown ( iobuf ), sender, @@ -233,18 +254,22 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, } /* Wait for received packet */ - if ( ( rc = loopback_wait ( receiver, buf, - sizeof ( buf ) ) ) != 0 ) { + if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 ) break; - } } printf ( "\n"); - netdev_rx_unfreeze ( receiver ); + + /* Stop loopback testing */ + lotest_active = 0; + lotest_flush(); /* Dump final statistics */ ifstat ( sender ); ifstat ( receiver ); + /* Free buffer */ + free ( buf ); + return 0; } diff --git a/roms/ipxe/src/usr/neighmgmt.c b/roms/ipxe/src/usr/neighmgmt.c new file mode 100644 index 000000000..e4d21a208 --- /dev/null +++ b/roms/ipxe/src/usr/neighmgmt.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <ipxe/neighbour.h> +#include <usr/neighmgmt.h> + +/** @file + * + * Neighbour management + * + */ + +/** + * Print neighbour table + * + */ +void nstat ( void ) { + struct neighbour *neighbour; + struct net_device *netdev; + struct ll_protocol *ll_protocol; + struct net_protocol *net_protocol; + + list_for_each_entry ( neighbour, &neighbours, list ) { + netdev = neighbour->netdev; + ll_protocol = netdev->ll_protocol; + net_protocol = neighbour->net_protocol; + printf ( "%s %s %s is %s %s", netdev->name, net_protocol->name, + net_protocol->ntoa ( neighbour->net_dest ), + ll_protocol->name, + ( neighbour_has_ll_dest ( neighbour ) ? + ll_protocol->ntoa ( neighbour->ll_dest ) : + "(incomplete)" ) ); + if ( neighbour->discovery ) + printf ( " (%s)", neighbour->discovery->name ); + printf ( "\n" ); + } +} diff --git a/roms/ipxe/src/usr/nslookup.c b/roms/ipxe/src/usr/nslookup.c index c931ec5a1..eb2b08b42 100644 --- a/roms/ipxe/src/usr/nslookup.c +++ b/roms/ipxe/src/usr/nslookup.c @@ -46,7 +46,7 @@ struct nslookup { struct interface resolver; /** Setting name */ - const char *setting_name; + char *setting_name; }; /** @@ -71,7 +71,10 @@ static void nslookup_close ( struct nslookup *nslookup, int rc ) { static void nslookup_resolv_done ( struct nslookup *nslookup, struct sockaddr *sa ) { struct sockaddr_in *sin; - struct setting_type *type; + struct sockaddr_in6 *sin6; + const struct setting_type *default_type; + struct settings *settings; + struct setting setting; void *data; size_t len; int rc; @@ -82,16 +85,31 @@ static void nslookup_resolv_done ( struct nslookup *nslookup, sin = ( ( struct sockaddr_in * ) sa ); data = &sin->sin_addr; len = sizeof ( sin->sin_addr ); - type = &setting_type_ipv4; + default_type = &setting_type_ipv4; + break; + case AF_INET6: + sin6 = ( ( struct sockaddr_in6 * ) sa ); + data = &sin6->sin6_addr; + len = sizeof ( sin6->sin6_addr ); + default_type = &setting_type_ipv6; break; default: rc = -ENOTSUP; goto err; } - /* Save in specified setting */ - if ( ( rc = store_named_setting ( nslookup->setting_name, type, - data, len ) ) != 0 ) + /* Parse specified setting name */ + if ( ( rc = parse_setting_name ( nslookup->setting_name, + autovivify_child_settings, &settings, + &setting ) ) != 0 ) + goto err; + + /* Apply default type if necessary */ + if ( ! setting.type ) + setting.type = default_type; + + /* Store in specified setting */ + if ( ( rc = store_setting ( settings, &setting, data, len ) ) != 0 ) goto err; err: @@ -175,7 +193,7 @@ int nslookup ( const char *name, const char *setting_name ) { /* Perform name resolution */ if ( ( rc = resolv_setting ( &monojob, name, setting_name ) ) == 0 ) - rc = monojob_wait ( NULL ); + rc = monojob_wait ( NULL, 0 ); if ( rc != 0 ) { printf ( "Could not resolve %s: %s\n", name, strerror ( rc ) ); return rc; diff --git a/roms/ipxe/src/usr/pingmgmt.c b/roms/ipxe/src/usr/pingmgmt.c new file mode 100644 index 000000000..2d4db491f --- /dev/null +++ b/roms/ipxe/src/usr/pingmgmt.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <ipxe/pinger.h> +#include <ipxe/monojob.h> +#include <ipxe/timer.h> +#include <usr/pingmgmt.h> + +/** @file + * + * ICMP ping management + * + */ + +/** + * Display ping result + * + * @v src Source socket address + * @v sequence Sequence number + * @v len Payload length + * @v rc Status code + */ +static void ping_callback ( struct sockaddr *peer, unsigned int sequence, + size_t len, int rc ) { + + /* Display ping response */ + printf ( "%zd bytes from %s: seq=%d", + len, sock_ntoa ( peer ), sequence ); + if ( rc != 0 ) + printf ( ": %s", strerror ( rc ) ); + printf ( "\n" ); +} + +/** + * Ping a host + * + * @v hostname Hostname + * @v timeout Timeout between pings, in ticks + * @v len Payload length + * @ret rc Return status code + */ +int ping ( const char *hostname, unsigned long timeout, size_t len ) { + int rc; + + /* Create pinger */ + if ( ( rc = create_pinger ( &monojob, hostname, timeout, + len, ping_callback ) ) != 0 ) { + printf ( "Could not start ping: %s\n", strerror ( rc ) ); + return rc; + } + + /* Wait for ping to complete */ + if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) { + printf ( "Finished: %s\n", strerror ( rc ) ); + return rc; + } + + return 0; +} diff --git a/roms/ipxe/src/interface/efi/efi_strerror.c b/roms/ipxe/src/usr/profstat.c index 46bfbbb5b..991427473 100644 --- a/roms/ipxe/src/interface/efi/efi_strerror.c +++ b/roms/ipxe/src/usr/profstat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>. + * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,27 +20,25 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdio.h> -#include <ipxe/efi/efi.h> +#include <ipxe/profile.h> +#include <usr/profstat.h> /** @file * - * iPXE error message formatting for EFI + * Profiling * */ /** - * Format EFI status code + * Print profiling statistics * - * @v efirc EFI status code - * @v efi_strerror EFI status code string */ -const char * efi_strerror ( EFI_STATUS efirc ) { - static char errbuf[32]; +void profstat ( void ) { + struct profiler *profiler; - if ( ! efirc ) - return "No error"; - - snprintf ( errbuf, sizeof ( errbuf ), "Error %lld", - ( unsigned long long ) ( efirc ^ MAX_BIT ) ); - return errbuf; + for_each_table_entry ( profiler, PROFILERS ) { + printf ( "%s: %ld +/- %ld ticks (%d samples)\n", + profiler->name, profile_mean ( profiler ), + profile_stddev ( profiler ), profiler->count ); + } } diff --git a/roms/ipxe/src/usr/prompt.c b/roms/ipxe/src/usr/prompt.c index ede037457..957b4ab3d 100644 --- a/roms/ipxe/src/usr/prompt.c +++ b/roms/ipxe/src/usr/prompt.c @@ -28,28 +28,27 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <errno.h> #include <stdio.h> #include <ipxe/console.h> -#include <ipxe/timer.h> #include <usr/prompt.h> /** * Prompt for keypress * * @v text Prompt string - * @v wait_ms Time to wait, in milliseconds (0=indefinite) + * @v timeout Timeout period, in ticks (0=indefinite) * @v key Key to wait for (0=any key) * @ret rc Return status code * * Returns success if the specified key was pressed within the * specified timeout period. */ -int prompt ( const char *text, unsigned int wait_ms, int key ) { +int prompt ( const char *text, unsigned long timeout, int key ) { int key_pressed; /* Display prompt */ printf ( "%s", text ); /* Wait for key */ - key_pressed = getkey ( ( wait_ms * TICKS_PER_SEC ) / 1000 ); + key_pressed = getkey ( timeout ); /* Clear the prompt line */ while ( *(text++) ) diff --git a/roms/ipxe/src/usr/pxemenu.c b/roms/ipxe/src/usr/pxemenu.c index d50ee6ba9..b69905df1 100644 --- a/roms/ipxe/src/usr/pxemenu.c +++ b/roms/ipxe/src/usr/pxemenu.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/keys.h> #include <ipxe/timer.h> #include <ipxe/uri.h> +#include <ipxe/ansicol.h> #include <usr/dhcpmgmt.h> #include <usr/autoboot.h> @@ -41,10 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/* Colour pairs */ -#define CPAIR_NORMAL 1 -#define CPAIR_SELECT 2 - /** A PXE boot menu item */ struct pxe_menu_item { /** Boot Server type */ @@ -101,9 +98,9 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) { /* Fetch raw menu */ memset ( raw_menu, 0, sizeof ( raw_menu ) ); - if ( ( raw_menu_len = fetch_setting ( NULL, &pxe_boot_menu_setting, - raw_menu, - sizeof ( raw_menu ) ) ) < 0 ) { + if ( ( raw_menu_len = fetch_raw_setting ( NULL, &pxe_boot_menu_setting, + raw_menu, + sizeof ( raw_menu ) ) ) < 0 ){ rc = raw_menu_len; DBG ( "Could not retrieve raw PXE boot menu: %s\n", strerror ( rc ) ); @@ -116,8 +113,9 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) { raw_menu_end = ( raw_menu + raw_menu_len ); /* Fetch raw prompt length */ - raw_prompt_len = fetch_setting_len ( NULL, - &pxe_boot_menu_prompt_setting ); + raw_prompt_len = + fetch_raw_setting ( NULL, &pxe_boot_menu_prompt_setting, + NULL, 0 ); if ( raw_prompt_len < 0 ) raw_prompt_len = 0; @@ -168,8 +166,8 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) { if ( raw_prompt_len ) { raw_menu_prompt = ( ( ( void * ) raw_menu_item ) + 1 /* NUL */ ); - fetch_setting ( NULL, &pxe_boot_menu_prompt_setting, - raw_menu_prompt, raw_prompt_len ); + fetch_raw_setting ( NULL, &pxe_boot_menu_prompt_setting, + raw_menu_prompt, raw_prompt_len ); (*menu)->timeout = ( ( raw_menu_prompt->timeout == 0xff ) ? -1 : raw_menu_prompt->timeout ); @@ -203,7 +201,7 @@ static void pxe_menu_draw_item ( struct pxe_menu *menu, /* Draw row */ row = ( LINES - menu->num_items + index ); - color_set ( ( selected ? CPAIR_SELECT : CPAIR_NORMAL ), NULL ); + color_set ( ( selected ? CPAIR_PXE : CPAIR_DEFAULT ), NULL ); mvprintw ( row, 0, "%s", buf ); move ( row, 1 ); } @@ -223,9 +221,7 @@ static int pxe_menu_select ( struct pxe_menu *menu ) { /* Initialise UI */ initscr(); start_color(); - init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK ); - init_pair ( CPAIR_SELECT, COLOR_BLACK, COLOR_WHITE ); - color_set ( CPAIR_NORMAL, NULL ); + color_set ( CPAIR_DEFAULT, NULL ); /* Draw initial menu */ for ( i = 0 ; i < menu->num_items ; i++ ) diff --git a/roms/ipxe/src/usr/route.c b/roms/ipxe/src/usr/route.c index e393e38d4..ba4cc3221 100644 --- a/roms/ipxe/src/usr/route.c +++ b/roms/ipxe/src/usr/route.c @@ -19,28 +19,26 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#include <stdio.h> #include <ipxe/netdevice.h> -#include <ipxe/ip.h> #include <usr/route.h> /** @file * - * Routing table management + * Routing management * */ +/** + * Print routing table + * + */ void route ( void ) { - struct ipv4_miniroute *miniroute; + struct net_device *netdev; + struct routing_family *family; - list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) { - printf ( "%s: %s/", miniroute->netdev->name, - inet_ntoa ( miniroute->address ) ); - printf ( "%s", inet_ntoa ( miniroute->netmask ) ); - if ( miniroute->gateway.s_addr ) - printf ( " gw %s", inet_ntoa ( miniroute->gateway ) ); - if ( ! netdev_is_open ( miniroute->netdev ) ) - printf ( " (inaccessible)" ); - printf ( "\n" ); + for_each_netdev ( netdev ) { + for_each_table_entry ( family, ROUTING_FAMILIES ) { + family->print ( netdev ); + } } } diff --git a/roms/ipxe/src/usr/route_ipv4.c b/roms/ipxe/src/usr/route_ipv4.c new file mode 100644 index 000000000..b4d1b7bf3 --- /dev/null +++ b/roms/ipxe/src/usr/route_ipv4.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <ipxe/netdevice.h> +#include <ipxe/ip.h> +#include <usr/route.h> + +/** @file + * + * IPv4 routing management + * + */ + +/** + * Print IPv4 routing table + * + * @v netdev Network device + */ +static void route_ipv4_print ( struct net_device *netdev ) { + struct ipv4_miniroute *miniroute; + + list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) { + if ( miniroute->netdev != netdev ) + continue; + printf ( "%s: %s/", netdev->name, + inet_ntoa ( miniroute->address ) ); + printf ( "%s", inet_ntoa ( miniroute->netmask ) ); + if ( miniroute->gateway.s_addr ) + printf ( " gw %s", inet_ntoa ( miniroute->gateway ) ); + if ( ! netdev_is_open ( miniroute->netdev ) ) + printf ( " (inaccessible)" ); + printf ( "\n" ); + } +} + +/** IPv4 routing family */ +struct routing_family ipv4_routing_family __routing_family ( ROUTING_IPV4 ) = { + .print = route_ipv4_print, +}; diff --git a/roms/ipxe/src/usr/route_ipv6.c b/roms/ipxe/src/usr/route_ipv6.c new file mode 100644 index 000000000..6045f85bb --- /dev/null +++ b/roms/ipxe/src/usr/route_ipv6.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stdio.h> +#include <ipxe/netdevice.h> +#include <ipxe/ipv6.h> +#include <usr/route.h> + +/** @file + * + * IPv6 routing management + * + */ + +/** + * Print IPv6 routing table + * + * @v netdev Network device + */ +static void route_ipv6_print ( struct net_device *netdev ) { + struct ipv6_miniroute *miniroute; + + list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) { + if ( miniroute->netdev != netdev ) + continue; + printf ( "%s: %s/%d", netdev->name, + inet6_ntoa ( &miniroute->address ), + miniroute->prefix_len ); + if ( miniroute->flags & IPV6_HAS_ROUTER ) + printf ( " gw %s", inet6_ntoa ( &miniroute->router ) ); + if ( ! ( miniroute->flags & IPV6_HAS_ADDRESS ) ) + printf ( " (no address)" ); + if ( ! netdev_is_open ( miniroute->netdev ) ) + printf ( " (inaccessible)" ); + printf ( "\n" ); + } +} + +/** IPv6 routing family */ +struct routing_family ipv6_routing_family __routing_family ( ROUTING_IPV6 ) = { + .print = route_ipv6_print, +}; diff --git a/roms/ipxe/src/usr/sync.c b/roms/ipxe/src/usr/sync.c new file mode 100644 index 000000000..f7a04c44c --- /dev/null +++ b/roms/ipxe/src/usr/sync.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stddef.h> +#include <ipxe/job.h> +#include <ipxe/monojob.h> +#include <ipxe/pending.h> +#include <usr/sync.h> + +/** @file + * + * Wait for pending operations to complete + * + */ + +/** + * Report progress + * + * @v intf Interface + * @v progress Progress report to fill in + * @ret ongoing_rc Ongoing job status code (if known) + */ +static int sync_progress ( struct interface *intf, + struct job_progress *progress __unused ) { + + /* Terminate successfully if no pending operations remain */ + if ( ! have_pending() ) + intf_close ( intf, 0 ); + + return 0; +} + +/** Synchroniser interface operations */ +static struct interface_operation sync_intf_op[] = { + INTF_OP ( job_progress, struct interface *, sync_progress ), +}; + +/** Synchroniser interface descriptor */ +static struct interface_descriptor sync_intf_desc = + INTF_DESC_PURE ( sync_intf_op ); + +/** Synchroniser */ +static struct interface sync_intf = INTF_INIT ( sync_intf_desc ); + +/** + * Wait for pending operations to complete + * + * @v timeout Timeout period, in ticks (0=indefinite) + * @ret rc Return status code + */ +int sync ( unsigned long timeout ) { + + /* Attach synchroniser and wait for completion */ + intf_plug_plug ( &monojob, &sync_intf ); + return monojob_wait ( NULL, timeout ); +} diff --git a/roms/ipxe/src/util/einfo.c b/roms/ipxe/src/util/einfo.c index 354d475fa..d21558980 100644 --- a/roms/ipxe/src/util/einfo.c +++ b/roms/ipxe/src/util/einfo.c @@ -38,10 +38,15 @@ struct options { /** Error usage information */ struct einfo { + /** Size of error information record */ uint32_t size; + /** Error number */ uint32_t error; + /** Offset to error description (NUL-terminated) */ uint32_t desc; + /** Offset to file name (NUL-terminated) */ uint32_t file; + /** Line number */ uint32_t line; } __attribute__ (( packed )); diff --git a/roms/ipxe/src/util/elf2efi.c b/roms/ipxe/src/util/elf2efi.c index b28c7ef33..45d539574 100644 --- a/roms/ipxe/src/util/elf2efi.c +++ b/roms/ipxe/src/util/elf2efi.c @@ -18,6 +18,8 @@ */ #define _GNU_SOURCE +#define PACKAGE "elf2efi" +#define PACKAGE_VERSION "1" #include <stdint.h> #include <stddef.h> #include <stdlib.h> diff --git a/roms/ipxe/src/util/geniso b/roms/ipxe/src/util/geniso index 48ea2f2aa..4dc721927 100755 --- a/roms/ipxe/src/util/geniso +++ b/roms/ipxe/src/util/geniso @@ -38,6 +38,14 @@ shift dir=`mktemp -d bin/iso.dir.XXXXXX` cfg=$dir/isolinux.cfg cp -p $isolinux_bin $dir + +# syslinux 6.x needs a file called ldlinux.c32 +ldlinux_c32=$(dirname ${isolinux_bin})/ldlinux.c32 +if [ -s ${ldlinux_c32} ] +then + cp -p ${ldlinux_c32} ${dir} +fi + cat > $cfg <<EOF # These default options can be changed in the geniso script SAY iPXE ISO boot image diff --git a/roms/ipxe/src/util/genliso b/roms/ipxe/src/util/genliso index 184408ade..7a112a145 100755 --- a/roms/ipxe/src/util/genliso +++ b/roms/ipxe/src/util/genliso @@ -57,7 +57,7 @@ do ;; esac first=$g - echo LABEL $b + echo LABEL $g echo "" KERNEL $g mcopy -m -i $img $f ::$g done >> $cfg diff --git a/roms/ipxe/src/util/zbin.c b/roms/ipxe/src/util/zbin.c index 0dabaf1e3..3b7cf95b3 100644 --- a/roms/ipxe/src/util/zbin.c +++ b/roms/ipxe/src/util/zbin.c @@ -143,7 +143,7 @@ static int alloc_output_file ( size_t max_len, struct output_file *output ) { max_len ); return -1; } - memset ( output->buf, 0xff, sizeof ( output->buf ) ); + memset ( output->buf, 0xff, max_len ); return 0; } |